mirror of
https://github.com/torvalds/linux.git
synced 2026-10-22 23:01:49 +02:00
\n
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAmrWCkcACgkQnJ2qBz9k QNmHVAgApIXB6tQv9reUKKQ72A90JMdNEUwTM5OYdUptIK09tk7nDPsQ/DOQu5Lf VWnFFxD3lZyHQ5grxm/2YRC89O/v5ovqm7Yo6MX6s5m5brMtlolGsY0tkLqchMC7 7wKMA54oWj5BzbzouyRhCUoWRAhrVlGlY4DnXxzbFpWXwj9hgtJvz+sNL7OouMk2 NKfExFcDtqdi7WDgX//It65HYN3yHtCg7J08dLIaWCny8OZjUOPKjPEGSeqS6vXt mLb9W7Ayhkj2ySDfnaz9kMAp5zbcRCymiYm1WG+QmXszV71R3GAPpZSCSqD5SzaT Ud1YAaeNjtTL3D2hfxpsNs/nmuCjkA== =XcXn -----END PGP SIGNATURE----- Merge tag 'fs_for_v7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs Pull ext2, isofs, udf and quota updates from Jan Kara: - ext2 changes to support clang context tracking - multiple isofs hardenings and cleanups - several udf hardening fixes - block use of fs-specific quota formats with incorrect filesystem * tag 'fs_for_v7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: (26 commits) udf: fix return value for non-recorded-allocated extents in udf_map_block() isofs: shrink the name conversion buffer isofs: pass the name buffer size to get_rock_ridge_filename() isofs: report the Joliet name length in statfs isofs: return long Joliet names whole isofs: Simplify isofs_read_level3_size() isofs: bound empty directory blocks in isofs_read_level3_size() quota: fix shrinker scan budget accounting in dqcache_shrink_scan() ext2: drain in-flight DIO before buffered write fallback isofs: validate directory records in isofs_read_level3_size() once_lite: Simplify condition handling and fix context analysis isofs: convert the zisofs read path to use folios isofs: fix Rock Ridge CE extent validation on multisession media shmem: Refuse to enable tmpfs format for another filesystem ocfs2: Refuse to enable ocfs2 format for another filesystem ext2: enable context analysis support for ext2 filesystem ext2: annotate s_rsv_window_root as requiring s_rsv_window_lock ext2: annotate block-mapping helpers as requiring truncate_mutex ext2: annotate ext2_init_block_alloc_info() as requiring truncate_mutex ext2: mark s_mount_state as guarded by s_lock ...
This commit is contained in:
commit
744e5400b3
|
|
@ -3,6 +3,8 @@
|
|||
# Makefile for the linux ext2-filesystem routines.
|
||||
#
|
||||
|
||||
CONTEXT_ANALYSIS := y
|
||||
|
||||
obj-$(CONFIG_EXT2_FS) += ext2.o
|
||||
|
||||
ext2-y := balloc.o dir.o file.o ialloc.o inode.o \
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ search_reserve_window(struct rb_root *root, ext2_fsblk_t goal)
|
|||
*/
|
||||
void ext2_rsv_window_add(struct super_block *sb,
|
||||
struct ext2_reserve_window_node *rsv)
|
||||
__must_hold(&EXT2_SB(sb)->s_rsv_window_lock)
|
||||
{
|
||||
struct rb_root *root = &EXT2_SB(sb)->s_rsv_window_root;
|
||||
struct rb_node *node = &rsv->rsv_node;
|
||||
|
|
@ -373,6 +374,7 @@ void ext2_rsv_window_add(struct super_block *sb,
|
|||
*/
|
||||
static void rsv_window_remove(struct super_block *sb,
|
||||
struct ext2_reserve_window_node *rsv)
|
||||
__must_hold(&EXT2_SB(sb)->s_rsv_window_lock)
|
||||
{
|
||||
rsv->rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
|
||||
rsv->rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
|
||||
|
|
@ -414,6 +416,7 @@ static inline int rsv_is_empty(struct ext2_reserve_window *rsv)
|
|||
* Needs truncate_mutex protection prior to calling this function.
|
||||
*/
|
||||
void ext2_init_block_alloc_info(struct inode *inode)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex)
|
||||
{
|
||||
struct ext2_inode_info *ei = EXT2_I(inode);
|
||||
struct ext2_block_alloc_info *block_i;
|
||||
|
|
@ -758,6 +761,7 @@ static int find_next_reservable_window(
|
|||
struct super_block * sb,
|
||||
ext2_fsblk_t start_block,
|
||||
ext2_fsblk_t last_block)
|
||||
__must_hold(&EXT2_SB(sb)->s_rsv_window_lock)
|
||||
{
|
||||
struct rb_node *next;
|
||||
struct ext2_reserve_window_node *rsv, *prev;
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ struct ext2_sb_info {
|
|||
unsigned long s_gdb_count; /* Number of group descriptor blocks */
|
||||
unsigned long s_desc_per_block; /* Number of group descriptors per block */
|
||||
unsigned long s_groups_count; /* Number of groups in the fs */
|
||||
unsigned long s_overhead_last; /* Last calculated overhead */
|
||||
unsigned long s_blocks_last; /* Last seen block count */
|
||||
unsigned long s_overhead_last __guarded_by(&s_lock); /* Last calculated overhead */
|
||||
unsigned long s_blocks_last __guarded_by(&s_lock); /* Last seen block count */
|
||||
struct buffer_head * s_sbh; /* Buffer containing the super block */
|
||||
struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */
|
||||
struct buffer_head ** s_group_desc;
|
||||
|
|
@ -86,14 +86,14 @@ struct ext2_sb_info {
|
|||
unsigned long s_sb_block;
|
||||
kuid_t s_resuid;
|
||||
kgid_t s_resgid;
|
||||
unsigned short s_mount_state;
|
||||
unsigned short s_mount_state __guarded_by(&s_lock);
|
||||
unsigned short s_pad;
|
||||
int s_addr_per_block_bits;
|
||||
int s_desc_per_block_bits;
|
||||
int s_inode_size;
|
||||
int s_first_ino;
|
||||
spinlock_t s_next_gen_lock;
|
||||
u32 s_next_generation;
|
||||
u32 s_next_generation __guarded_by(&s_next_gen_lock);
|
||||
unsigned long s_dir_count;
|
||||
u8 *s_debts;
|
||||
struct percpu_counter s_freeblocks_counter;
|
||||
|
|
@ -102,7 +102,7 @@ struct ext2_sb_info {
|
|||
struct blockgroup_lock *s_blockgroup_lock;
|
||||
/* root of the per fs reservation window tree */
|
||||
spinlock_t s_rsv_window_lock;
|
||||
struct rb_root s_rsv_window_root;
|
||||
struct rb_root s_rsv_window_root __guarded_by(&s_rsv_window_lock);
|
||||
struct ext2_reserve_window_node s_rsv_window_head;
|
||||
/*
|
||||
* s_lock protects against concurrent modifications of s_mount_state,
|
||||
|
|
@ -710,8 +710,10 @@ extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
|
|||
struct buffer_head ** bh);
|
||||
extern void ext2_discard_reservation (struct inode *);
|
||||
extern int ext2_should_retry_alloc(struct super_block *sb, int *retries);
|
||||
extern void ext2_init_block_alloc_info(struct inode *);
|
||||
extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_window_node *rsv);
|
||||
extern void ext2_init_block_alloc_info(struct inode *inode)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex);
|
||||
extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_window_node *rsv)
|
||||
__must_hold(&EXT2_SB(sb)->s_rsv_window_lock);
|
||||
|
||||
/* dir.c */
|
||||
int ext2_add_link(struct dentry *, struct inode *);
|
||||
|
|
@ -761,7 +763,8 @@ extern __printf(3, 4)
|
|||
void ext2_error(struct super_block *, const char *, const char *, ...);
|
||||
extern __printf(3, 4)
|
||||
void ext2_msg(struct super_block *, const char *, const char *, ...);
|
||||
extern void ext2_update_dynamic_rev (struct super_block *sb);
|
||||
extern void ext2_update_dynamic_rev(struct super_block *sb)
|
||||
__must_hold(&EXT2_SB(sb)->s_lock);
|
||||
extern void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es,
|
||||
int wait);
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,13 @@ static ssize_t ext2_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
int ret2;
|
||||
|
||||
iocb->ki_flags &= ~IOCB_DIRECT;
|
||||
|
||||
/*
|
||||
* Prevent concurrent direct I/O and buffered I/O to the same file
|
||||
* range. Wait for in-flight DIO to finish before dirtying pages.
|
||||
*/
|
||||
inode_dio_wait(inode);
|
||||
|
||||
pos = iocb->ki_pos;
|
||||
status = generic_perform_write(iocb, from);
|
||||
if (unlikely(status < 0)) {
|
||||
|
|
|
|||
|
|
@ -327,6 +327,7 @@ static ext2_fsblk_t ext2_find_near(struct inode *inode, Indirect *ind)
|
|||
|
||||
static inline ext2_fsblk_t ext2_find_goal(struct inode *inode, long block,
|
||||
Indirect *partial)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex)
|
||||
{
|
||||
struct ext2_block_alloc_info *block_i;
|
||||
|
||||
|
|
@ -397,6 +398,7 @@ ext2_blks_to_allocate(Indirect * branch, int k, unsigned long blks,
|
|||
static int ext2_alloc_blocks(struct inode *inode,
|
||||
ext2_fsblk_t goal, int indirect_blks, int blks,
|
||||
ext2_fsblk_t new_blocks[4], int *err)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex)
|
||||
{
|
||||
int target, i;
|
||||
unsigned long count = 0;
|
||||
|
|
@ -477,6 +479,7 @@ static int ext2_alloc_blocks(struct inode *inode,
|
|||
static int ext2_alloc_branch(struct inode *inode,
|
||||
int indirect_blks, int *blks, ext2_fsblk_t goal,
|
||||
int *offsets, Indirect *branch)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex)
|
||||
{
|
||||
int blocksize = inode->i_sb->s_blocksize;
|
||||
int i, n = 0;
|
||||
|
|
@ -558,6 +561,7 @@ static int ext2_alloc_branch(struct inode *inode,
|
|||
*/
|
||||
static void ext2_splice_branch(struct inode *inode,
|
||||
long block, Indirect *where, int num, int blks)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex)
|
||||
{
|
||||
int i;
|
||||
struct ext2_block_alloc_info *block_i;
|
||||
|
|
@ -1002,6 +1006,7 @@ static Indirect *ext2_find_shared(struct inode *inode,
|
|||
int offsets[4],
|
||||
Indirect chain[4],
|
||||
__le32 *top)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex)
|
||||
{
|
||||
Indirect *partial, *p;
|
||||
int k, err;
|
||||
|
|
@ -1057,6 +1062,7 @@ static Indirect *ext2_find_shared(struct inode *inode,
|
|||
* appropriately.
|
||||
*/
|
||||
static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex)
|
||||
{
|
||||
ext2_fsblk_t block_to_free = 0, count = 0;
|
||||
ext2_fsblk_t nr;
|
||||
|
|
@ -1097,6 +1103,7 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
|
|||
* appropriately.
|
||||
*/
|
||||
static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int depth)
|
||||
__must_hold(&EXT2_I(inode)->truncate_mutex)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
ext2_fsblk_t nr;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ void ext2_msg(struct super_block *sb, const char *prefix,
|
|||
* This must be called with sbi->s_lock held.
|
||||
*/
|
||||
void ext2_update_dynamic_rev(struct super_block *sb)
|
||||
__must_hold(&EXT2_SB(sb)->s_lock)
|
||||
{
|
||||
struct ext2_super_block *es = EXT2_SB(sb)->s_es;
|
||||
|
||||
|
|
@ -633,6 +634,7 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
|||
static int ext2_setup_super (struct super_block * sb,
|
||||
struct ext2_super_block * es,
|
||||
int read_only)
|
||||
__must_hold(&EXT2_SB(sb)->s_lock)
|
||||
{
|
||||
int res = 0;
|
||||
struct ext2_sb_info *sbi = EXT2_SB(sb);
|
||||
|
|
@ -894,7 +896,7 @@ static int ext2_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||
sb->s_fs_info = sbi;
|
||||
sbi->s_sb_block = sb_block;
|
||||
|
||||
spin_lock_init(&sbi->s_lock);
|
||||
guard(spinlock_init)(&EXT2_SB(sb)->s_lock);
|
||||
ret = -EINVAL;
|
||||
|
||||
/*
|
||||
|
|
@ -1126,23 +1128,26 @@ static int ext2_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||
goto failed_mount2;
|
||||
}
|
||||
sbi->s_gdb_count = db_count;
|
||||
sbi->s_next_generation = get_random_u32();
|
||||
spin_lock_init(&sbi->s_next_gen_lock);
|
||||
scoped_guard(spinlock, &sbi->s_next_gen_lock)
|
||||
sbi->s_next_generation = get_random_u32();
|
||||
|
||||
/* per filesystem reservation list head & lock */
|
||||
spin_lock_init(&sbi->s_rsv_window_lock);
|
||||
sbi->s_rsv_window_root = RB_ROOT;
|
||||
/*
|
||||
* Add a single, static dummy reservation to the start of the
|
||||
* reservation window list --- it gives us a placeholder for
|
||||
* append-at-start-of-list which makes the allocation logic
|
||||
* _much_ simpler.
|
||||
*/
|
||||
sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
|
||||
sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
|
||||
sbi->s_rsv_window_head.rsv_alloc_hit = 0;
|
||||
sbi->s_rsv_window_head.rsv_goal_size = 0;
|
||||
ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);
|
||||
scoped_guard(spinlock, &EXT2_SB(sb)->s_rsv_window_lock) {
|
||||
sbi->s_rsv_window_root = RB_ROOT;
|
||||
/*
|
||||
* Add a single, static dummy reservation to the start of the
|
||||
* reservation window list --- it gives us a placeholder for
|
||||
* append-at-start-of-list which makes the allocation logic
|
||||
* _much_ simpler.
|
||||
*/
|
||||
sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
|
||||
sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
|
||||
sbi->s_rsv_window_head.rsv_alloc_hit = 0;
|
||||
sbi->s_rsv_window_head.rsv_goal_size = 0;
|
||||
ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);
|
||||
}
|
||||
|
||||
err = percpu_counter_init(&sbi->s_freeblocks_counter,
|
||||
ext2_count_free_blocks(sb), GFP_KERNEL);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ static DEFINE_MUTEX(zisofs_zlib_lock);
|
|||
*/
|
||||
static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
|
||||
loff_t block_end, int pcount,
|
||||
struct page **pages, unsigned poffset,
|
||||
struct folio **folios, unsigned int poffset,
|
||||
int *errp)
|
||||
{
|
||||
unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
|
||||
|
|
@ -66,11 +66,12 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
|
|||
if (block_size == 0) {
|
||||
for ( i = 0 ; i < pcount ; i++ ) {
|
||||
unsigned int off = i ? 0 : poffset;
|
||||
struct folio *folio = folios[i];
|
||||
|
||||
if (!pages[i])
|
||||
if (!folio)
|
||||
continue;
|
||||
memzero_page(pages[i], off, PAGE_SIZE - off);
|
||||
SetPageUptodate(pages[i]);
|
||||
folio_zero_range(folio, off, folio_size(folio) - off);
|
||||
folio_mark_uptodate(folio);
|
||||
}
|
||||
return (((loff_t)pcount) << PAGE_SHIFT) - poffset;
|
||||
}
|
||||
|
|
@ -119,11 +120,12 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
|
|||
|
||||
while (curpage < pcount && curbh < haveblocks &&
|
||||
zerr != Z_STREAM_END) {
|
||||
struct folio *folio = folios[curpage];
|
||||
|
||||
if (!stream.avail_out) {
|
||||
if (pages[curpage]) {
|
||||
stream.next_out = kmap_local_page(pages[curpage])
|
||||
+ poffset;
|
||||
stream.avail_out = PAGE_SIZE - poffset;
|
||||
if (folio) {
|
||||
stream.next_out = kmap_local_folio(folio, poffset);
|
||||
stream.avail_out = folio_size(folio) - poffset;
|
||||
poffset = 0;
|
||||
} else {
|
||||
stream.next_out = (void *)&zisofs_sink_page;
|
||||
|
|
@ -173,9 +175,9 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
|
|||
|
||||
if (!stream.avail_out) {
|
||||
/* This page completed */
|
||||
if (pages[curpage]) {
|
||||
flush_dcache_page(pages[curpage]);
|
||||
SetPageUptodate(pages[curpage]);
|
||||
if (folio) {
|
||||
flush_dcache_folio(folio);
|
||||
folio_mark_uptodate(folio);
|
||||
}
|
||||
if (stream.next_out != (unsigned char *)zisofs_sink_page) {
|
||||
kunmap_local(stream.next_out);
|
||||
|
|
@ -206,7 +208,7 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
|
|||
* fills in other pages if we have data for them.
|
||||
*/
|
||||
static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
|
||||
struct page **pages)
|
||||
struct folio **folios)
|
||||
{
|
||||
loff_t start_off, end_off;
|
||||
loff_t block_start, block_end;
|
||||
|
|
@ -221,14 +223,14 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
|
|||
int err;
|
||||
loff_t ret;
|
||||
|
||||
BUG_ON(!pages[full_page]);
|
||||
BUG_ON(!folios[full_page]);
|
||||
|
||||
/*
|
||||
* We want to read at least 'full_page' page. Because we have to
|
||||
* uncompress the whole compression block anyway, fill the surrounding
|
||||
* pages with the data we have anyway...
|
||||
*/
|
||||
start_off = page_offset(pages[full_page]);
|
||||
start_off = folio_pos(folios[full_page]);
|
||||
end_off = min_t(loff_t, start_off + PAGE_SIZE, inode->i_size);
|
||||
|
||||
cstart_block = start_off >> zisofs_block_shift;
|
||||
|
|
@ -267,9 +269,9 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
|
|||
}
|
||||
err = 0;
|
||||
ret = zisofs_uncompress_block(inode, block_start, block_end,
|
||||
pcount, pages, poffset, &err);
|
||||
pcount, folios, poffset, &err);
|
||||
poffset += ret;
|
||||
pages += poffset >> PAGE_SHIFT;
|
||||
folios += poffset >> PAGE_SHIFT;
|
||||
pcount -= poffset >> PAGE_SHIFT;
|
||||
full_page -= poffset >> PAGE_SHIFT;
|
||||
poffset &= ~PAGE_MASK;
|
||||
|
|
@ -289,9 +291,11 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
|
|||
cstart_block++;
|
||||
}
|
||||
|
||||
if (poffset && *pages) {
|
||||
memzero_page(*pages, poffset, PAGE_SIZE - poffset);
|
||||
SetPageUptodate(*pages);
|
||||
if (poffset && *folios) {
|
||||
struct folio *folio = *folios;
|
||||
|
||||
folio_zero_range(folio, poffset, folio_size(folio) - poffset);
|
||||
folio_mark_uptodate(folio);
|
||||
}
|
||||
brelse(bh);
|
||||
return 0;
|
||||
|
|
@ -312,7 +316,7 @@ static int zisofs_read_folio(struct file *file, struct folio *folio)
|
|||
unsigned int zisofs_pages_per_cblock =
|
||||
PAGE_SHIFT <= zisofs_block_shift ?
|
||||
(1 << (zisofs_block_shift - PAGE_SHIFT)) : 0;
|
||||
struct page **pages;
|
||||
struct folio **folios;
|
||||
pgoff_t index = folio->index, end_index;
|
||||
|
||||
end_index = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
|
|
@ -336,33 +340,38 @@ static int zisofs_read_folio(struct file *file, struct folio *folio)
|
|||
full_page = 0;
|
||||
pcount = 1;
|
||||
}
|
||||
pages = kzalloc_objs(*pages,
|
||||
max_t(unsigned int, zisofs_pages_per_cblock, 1));
|
||||
if (!pages) {
|
||||
folios = kzalloc_objs(*folios,
|
||||
max_t(unsigned int, zisofs_pages_per_cblock, 1));
|
||||
if (!folios) {
|
||||
folio_unlock(folio);
|
||||
return -ENOMEM;
|
||||
}
|
||||
pages[full_page] = &folio->page;
|
||||
folios[full_page] = folio;
|
||||
|
||||
for (i = 0; i < pcount; i++, index++) {
|
||||
if (i != full_page)
|
||||
pages[i] = grab_cache_page_nowait(mapping, index);
|
||||
if (i == full_page)
|
||||
continue;
|
||||
folios[i] = __filemap_get_folio(mapping, index,
|
||||
FGP_LOCK | FGP_CREAT | FGP_NOWAIT,
|
||||
mapping_gfp_mask(mapping));
|
||||
if (IS_ERR(folios[i]))
|
||||
folios[i] = NULL;
|
||||
}
|
||||
|
||||
err = zisofs_fill_pages(inode, full_page, pcount, pages);
|
||||
err = zisofs_fill_pages(inode, full_page, pcount, folios);
|
||||
|
||||
/* Release any residual pages, do not SetPageUptodate */
|
||||
/* Release any residual folios, do not mark them uptodate */
|
||||
for (i = 0; i < pcount; i++) {
|
||||
if (pages[i]) {
|
||||
flush_dcache_page(pages[i]);
|
||||
unlock_page(pages[i]);
|
||||
if (folios[i]) {
|
||||
flush_dcache_folio(folios[i]);
|
||||
folio_unlock(folios[i]);
|
||||
if (i != full_page)
|
||||
put_page(pages[i]);
|
||||
folio_put(folios[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point, err contains 0 or -EIO depending on the "critical" page */
|
||||
kfree(pages);
|
||||
kfree(folios);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -186,7 +186,8 @@ static int do_isofs_readdir(struct inode *inode, struct file *file,
|
|||
|
||||
map = 1;
|
||||
if (sbi->s_rock) {
|
||||
len = get_rock_ridge_filename(de, tmpname, inode);
|
||||
len = get_rock_ridge_filename(de, tmpname, NAME_MAX + 1,
|
||||
inode);
|
||||
if (len != 0) { /* may be -1 */
|
||||
p = tmpname;
|
||||
map = 0;
|
||||
|
|
@ -195,7 +196,9 @@ static int do_isofs_readdir(struct inode *inode, struct file *file,
|
|||
if (map) {
|
||||
#ifdef CONFIG_JOLIET
|
||||
if (sbi->s_joliet_level) {
|
||||
len = get_joliet_filename(de, tmpname, inode);
|
||||
len = get_joliet_filename(de, tmpname,
|
||||
JOLIET_NAME_MAX + 1,
|
||||
inode);
|
||||
p = tmpname;
|
||||
} else
|
||||
#endif
|
||||
|
|
@ -233,7 +236,12 @@ static int isofs_readdir(struct file *file, struct dir_context *ctx)
|
|||
char *tmpname;
|
||||
struct inode *inode = file_inode(file);
|
||||
|
||||
tmpname = kmalloc(1024, GFP_KERNEL);
|
||||
/*
|
||||
* Rockridge can produce names of NAME_MAX size, Acorn extensions at
|
||||
* most 227 chars.
|
||||
*/
|
||||
BUILD_BUG_ON(JOLIET_NAME_MAX < NAME_MAX || JOLIET_NAME_MAX < 227);
|
||||
tmpname = kmalloc(JOLIET_NAME_MAX + 1, GFP_KERNEL);
|
||||
if (tmpname == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -821,6 +821,8 @@ static int isofs_fill_super(struct super_block *s, struct fs_context *fc)
|
|||
if (!sb_set_blocksize(s, orig_zonesize))
|
||||
goto out_freesbi;
|
||||
|
||||
sbi->s_session_start = (sector_t)vol_desc_start <<
|
||||
(ISOFS_BLOCK_BITS - s->s_blocksize_bits);
|
||||
sbi->s_nls_iocharset = NULL;
|
||||
|
||||
#ifdef CONFIG_JOLIET
|
||||
|
|
@ -1010,7 +1012,8 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_files = ISOFS_SB(sb)->s_ninodes;
|
||||
buf->f_ffree = 0;
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = NAME_MAX;
|
||||
buf->f_namelen = ISOFS_SB(sb)->s_joliet_level ?
|
||||
JOLIET_NAME_MAX : NAME_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1171,10 +1174,9 @@ static int isofs_read_level3_size(struct inode *inode)
|
|||
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
|
||||
int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra;
|
||||
struct buffer_head *bh = NULL;
|
||||
unsigned long block, offset, block_saved, offset_saved;
|
||||
unsigned long block, offset;
|
||||
int i = 0;
|
||||
int more_entries = 0;
|
||||
struct iso_directory_record *tmpde = NULL;
|
||||
struct iso_inode_info *ei = ISOFS_I(inode);
|
||||
|
||||
inode->i_size = 0;
|
||||
|
|
@ -1198,9 +1200,17 @@ static int isofs_read_level3_size(struct inode *inode)
|
|||
goto out_noread;
|
||||
}
|
||||
de = (struct iso_directory_record *) (bh->b_data + offset);
|
||||
de_len = *(unsigned char *) de;
|
||||
|
||||
if (de_len == 0) {
|
||||
/*
|
||||
* If we are at the end of a block (or at its zero-padded
|
||||
* tail), move on to the next block. A zero length byte at
|
||||
* the start of a block means the whole block is empty;
|
||||
* count that towards the same limit as sections below, or a
|
||||
* chain of empty blocks could be walked without bound.
|
||||
*/
|
||||
if (offset >= bufsize || de->length[0] == 0) {
|
||||
if (offset == 0 && ++i > 100)
|
||||
goto out_toomany;
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
++block;
|
||||
|
|
@ -1208,60 +1218,36 @@ static int isofs_read_level3_size(struct inode *inode)
|
|||
continue;
|
||||
}
|
||||
|
||||
block_saved = block;
|
||||
offset_saved = offset;
|
||||
offset += de_len;
|
||||
|
||||
/* Make sure we have a full directory entry */
|
||||
if (offset >= bufsize) {
|
||||
int slop = bufsize - offset + de_len;
|
||||
if (!tmpde) {
|
||||
tmpde = kmalloc(256, GFP_KERNEL);
|
||||
if (!tmpde)
|
||||
goto out_nomem;
|
||||
}
|
||||
memcpy(tmpde, de, slop);
|
||||
offset &= bufsize - 1;
|
||||
block++;
|
||||
if (!isofs_dir_record_valid(de, offset, bufsize)) {
|
||||
printk(KERN_NOTICE "iso9660: Corrupted directory entry in block %lu of inode %llu\n",
|
||||
block, inode->i_ino);
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
if (offset) {
|
||||
bh = sb_bread(inode->i_sb, block);
|
||||
if (!bh)
|
||||
goto out_noread;
|
||||
memcpy((void *)tmpde+slop, bh->b_data, offset);
|
||||
}
|
||||
de = tmpde;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Save the first continuation directory entry in the inode */
|
||||
if (more_entries && !ei->i_next_section_block) {
|
||||
ei->i_next_section_block = block;
|
||||
ei->i_next_section_offset = offset;
|
||||
}
|
||||
de_len = de->length[0];
|
||||
offset += de_len;
|
||||
inode->i_size += isonum_733(de->size);
|
||||
if (i == 1) {
|
||||
ei->i_next_section_block = block_saved;
|
||||
ei->i_next_section_offset = offset_saved;
|
||||
}
|
||||
|
||||
more_entries = de->flags[-high_sierra] & 0x80;
|
||||
|
||||
i++;
|
||||
if (i > 100)
|
||||
if (++i > 100)
|
||||
goto out_toomany;
|
||||
} while (more_entries);
|
||||
out:
|
||||
kfree(tmpde);
|
||||
brelse(bh);
|
||||
return 0;
|
||||
|
||||
out_nomem:
|
||||
brelse(bh);
|
||||
return -ENOMEM;
|
||||
|
||||
out_noread:
|
||||
printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block);
|
||||
kfree(tmpde);
|
||||
return -EIO;
|
||||
|
||||
out_toomany:
|
||||
printk(KERN_INFO "%s: More than 100 file sections ?!?, aborting...\n"
|
||||
printk(KERN_INFO "%s: More than 100 file sections/empty blocks ?!?, aborting...\n"
|
||||
"isofs_read_level3_size: inode=%llu\n",
|
||||
__func__, inode->i_ino);
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ struct isofs_sb_info {
|
|||
unsigned long s_firstdatazone;
|
||||
unsigned long s_log_zone_size;
|
||||
unsigned long s_max_size;
|
||||
/* Session start in filesystem block units. */
|
||||
sector_t s_session_start;
|
||||
|
||||
int s_rock_offset; /* offset of SUSP fields within SU area */
|
||||
s32 s_sbsector;
|
||||
|
|
@ -113,13 +115,23 @@ struct timespec64 iso_date(u8 *p, int flags);
|
|||
struct inode; /* To make gcc happy */
|
||||
|
||||
extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated);
|
||||
extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
|
||||
int get_rock_ridge_filename(struct iso_directory_record *de, char *retname,
|
||||
int retnamesize, struct inode *inode);
|
||||
extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
|
||||
bool isofs_dir_record_valid(struct iso_directory_record *de,
|
||||
unsigned long offset,
|
||||
unsigned long bufsize);
|
||||
|
||||
int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *);
|
||||
/*
|
||||
* The longest name the Joliet converter returns, in bytes. A directory
|
||||
* record is at most 255 bytes long, which leaves room for 111 UTF-16 units
|
||||
* of name, and no character set needs more than three bytes for one unit.
|
||||
*/
|
||||
#define JOLIET_NAME_MAX \
|
||||
((255 - sizeof(struct iso_directory_record)) / 2 * 3)
|
||||
|
||||
int get_joliet_filename(struct iso_directory_record *de, unsigned char *outname,
|
||||
int outsize, struct inode *inode);
|
||||
int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
|
||||
|
||||
extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int flags);
|
||||
|
|
|
|||
|
|
@ -15,19 +15,26 @@
|
|||
* Convert Unicode 16 to UTF-8 or ASCII.
|
||||
*/
|
||||
static int
|
||||
uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls)
|
||||
uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls,
|
||||
int outsize)
|
||||
{
|
||||
__be16 *ip, ch;
|
||||
unsigned char *op;
|
||||
unsigned char *op, *end;
|
||||
|
||||
ip = uni;
|
||||
op = ascii;
|
||||
end = ascii + outsize - 1; /* leave room for the terminator */
|
||||
|
||||
while ((ch = get_unaligned(ip)) && len) {
|
||||
int llen;
|
||||
llen = nls->uni2char(be16_to_cpu(ch), op, NLS_MAX_CHARSET_SIZE);
|
||||
|
||||
if (op >= end)
|
||||
break;
|
||||
llen = nls->uni2char(be16_to_cpu(ch), op, end - op);
|
||||
if (llen > 0)
|
||||
op += llen;
|
||||
else if (llen == -ENAMETOOLONG)
|
||||
break;
|
||||
else
|
||||
*op++ = '?';
|
||||
ip++;
|
||||
|
|
@ -38,21 +45,27 @@ uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls)
|
|||
return (op - ascii);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the Joliet name of @de into @outname, a buffer of @outsize bytes.
|
||||
* The result is at most @outsize - 1 bytes long; a longer name is cut at a
|
||||
* character boundary.
|
||||
*/
|
||||
int
|
||||
get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, struct inode * inode)
|
||||
get_joliet_filename(struct iso_directory_record *de, unsigned char *outname,
|
||||
int outsize, struct inode *inode)
|
||||
{
|
||||
struct nls_table *nls;
|
||||
unsigned char len = 0;
|
||||
int len = 0;
|
||||
|
||||
nls = ISOFS_SB(inode->i_sb)->s_nls_iocharset;
|
||||
|
||||
if (!nls) {
|
||||
len = utf16s_to_utf8s((const wchar_t *) de->name,
|
||||
de->name_len[0] >> 1, UTF16_BIG_ENDIAN,
|
||||
outname, PAGE_SIZE);
|
||||
outname, outsize - 1);
|
||||
} else {
|
||||
len = uni16_to_x8(outname, (__be16 *) de->name,
|
||||
de->name_len[0] >> 1, nls);
|
||||
de->name_len[0] >> 1, nls, outsize);
|
||||
}
|
||||
if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1'))
|
||||
len -= 2;
|
||||
|
|
|
|||
|
|
@ -104,12 +104,14 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
|
|||
dpnt = de->name;
|
||||
|
||||
if (sbi->s_rock &&
|
||||
((i = get_rock_ridge_filename(de, tmpname, dir)))) {
|
||||
((i = get_rock_ridge_filename(de, tmpname, NAME_MAX + 1,
|
||||
dir)))) {
|
||||
dlen = i; /* possibly -1 */
|
||||
dpnt = tmpname;
|
||||
#ifdef CONFIG_JOLIET
|
||||
} else if (sbi->s_joliet_level) {
|
||||
dlen = get_joliet_filename(de, tmpname, dir);
|
||||
dlen = get_joliet_filename(de, tmpname,
|
||||
JOLIET_NAME_MAX + 1, dir);
|
||||
dpnt = tmpname;
|
||||
#endif
|
||||
} else if (sbi->s_mapping == 'a') {
|
||||
|
|
@ -155,7 +157,7 @@ struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, unsigned i
|
|||
struct inode *inode;
|
||||
char *tmpname;
|
||||
|
||||
tmpname = kmalloc(1024, GFP_USER);
|
||||
tmpname = kmalloc(JOLIET_NAME_MAX + 1, GFP_USER);
|
||||
if (!tmpname)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
#include "isofs.h"
|
||||
#include "rock.h"
|
||||
|
|
@ -84,6 +85,10 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode)
|
|||
*/
|
||||
static int rock_continue(struct rock_state *rs)
|
||||
{
|
||||
struct super_block *sb = rs->inode->i_sb;
|
||||
struct isofs_sb_info *sbi = ISOFS_SB(sb);
|
||||
sector_t session_end = sbi->s_session_start +
|
||||
((sector_t)sbi->s_nzones << (ISOFS_BLOCK_BITS - sb->s_blocksize_bits));
|
||||
int ret = 1;
|
||||
int blocksize = 1 << rs->inode->i_blkbits;
|
||||
const int min_de_size = offsetof(struct rock_ridge, u);
|
||||
|
|
@ -101,11 +106,13 @@ static int rock_continue(struct rock_state *rs)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if ((unsigned)rs->cont_extent >= ISOFS_SB(rs->inode->i_sb)->s_nzones) {
|
||||
if (rs->cont_extent &&
|
||||
(rs->cont_extent < sbi->s_session_start ||
|
||||
rs->cont_extent >= session_end)) {
|
||||
printk(KERN_NOTICE "rock: corrupted directory entry. "
|
||||
"extent=%u out of volume (nzones=%lu)\n",
|
||||
(unsigned)rs->cont_extent,
|
||||
ISOFS_SB(rs->inode->i_sb)->s_nzones);
|
||||
sbi->s_nzones);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -202,10 +209,14 @@ static int rock_check_overflow(struct rock_state *rs, int sig)
|
|||
}
|
||||
|
||||
/*
|
||||
* Build the Rock Ridge name of @de in @retname, a buffer of @retnamesize
|
||||
* bytes. From the first NM entry that does not fit along with the
|
||||
* terminator, the rest of the name is dropped.
|
||||
*
|
||||
* return length of name field; 0: not found, -1: to be ignored
|
||||
*/
|
||||
int get_rock_ridge_filename(struct iso_directory_record *de,
|
||||
char *retname, struct inode *inode)
|
||||
char *retname, int retnamesize, struct inode *inode)
|
||||
{
|
||||
struct rock_state rs;
|
||||
struct rock_ridge *rr;
|
||||
|
|
@ -280,7 +291,7 @@ int get_rock_ridge_filename(struct iso_directory_record *de,
|
|||
break;
|
||||
}
|
||||
len = rr->len - 5;
|
||||
if (retnamlen + len > NAME_MAX) {
|
||||
if (retnamlen + len >= retnamesize) {
|
||||
truncate = 1;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,10 @@ static int ocfs2_local_check_quota_file(struct super_block *sb, int type)
|
|||
struct ocfs2_disk_dqheader *dqhead;
|
||||
int status, ret = 0;
|
||||
|
||||
/* OCFS2 quota format is supported only for OCFS2 filesystems */
|
||||
if (sb->s_magic != OCFS2_SUPER_MAGIC)
|
||||
goto out_err;
|
||||
|
||||
/* First check whether we understand local quota file */
|
||||
status = ocfs2_read_quota_block(linode, 0, &bh);
|
||||
if (status) {
|
||||
|
|
|
|||
|
|
@ -809,6 +809,7 @@ static unsigned long
|
|||
dqcache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||
{
|
||||
struct dquot *dquot;
|
||||
unsigned long orig_nr_to_scan = sc->nr_to_scan;
|
||||
unsigned long freed = 0;
|
||||
|
||||
spin_lock(&dq_list_lock);
|
||||
|
|
@ -822,6 +823,21 @@ dqcache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
|||
freed++;
|
||||
}
|
||||
spin_unlock(&dq_list_lock);
|
||||
|
||||
sc->nr_scanned = orig_nr_to_scan - sc->nr_to_scan;
|
||||
|
||||
/*
|
||||
* DQST_FREE_DQUOTS is a percpu counter, so count_objects() can
|
||||
* report a stale/approximate value that is still positive even
|
||||
* though free_dquots is actually empty by the time we get here.
|
||||
* When that happens sc->nr_scanned comes back 0 and we have
|
||||
* nothing further to offer this reclaim pass, so tell
|
||||
* do_shrink_slab() to stop calling us instead of letting it burn
|
||||
* through its one-shot scan budget against an empty list.
|
||||
*/
|
||||
if (sc->nr_scanned == 0)
|
||||
return SHRINK_STOP;
|
||||
|
||||
return freed;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -372,8 +372,8 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
|
|||
map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc,
|
||||
offset);
|
||||
map->oflags |= UDF_BLK_MAPPED;
|
||||
ret = 0;
|
||||
}
|
||||
ret = 0;
|
||||
out_read:
|
||||
up_read(&iinfo->i_data_sem);
|
||||
brelse(epos.bh);
|
||||
|
|
@ -1336,6 +1336,26 @@ int udf_setsize(struct inode *inode, loff_t newsize)
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify validity of struct deviceSpec on disk. udf_get_extendedattr() has
|
||||
* already verified the generic header and made sure attribute fits in the
|
||||
* inode so we just have to make sure attribute space is large enough for
|
||||
* deviceSpec struct and required impUse information.
|
||||
*/
|
||||
static bool udf_device_spec_valid(struct deviceSpec *dsea)
|
||||
{
|
||||
u32 attr_length, imp_use_length;
|
||||
|
||||
attr_length = le32_to_cpu(dsea->attrLength);
|
||||
imp_use_length = le32_to_cpu(dsea->impUseLength);
|
||||
if (attr_length < sizeof(struct deviceSpec) ||
|
||||
imp_use_length < sizeof(struct regid) ||
|
||||
imp_use_length > attr_length - sizeof(struct deviceSpec))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Maximum length of linked list formed by ICB hierarchy. The chosen number is
|
||||
* arbitrary - just that we hopefully don't limit any real use of rewritten
|
||||
|
|
@ -1654,13 +1674,19 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
|
|||
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
||||
struct deviceSpec *dsea =
|
||||
(struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
|
||||
if (dsea) {
|
||||
init_special_inode(inode, inode->i_mode,
|
||||
|
||||
if (IS_ERR(dsea)) {
|
||||
ret = PTR_ERR(dsea);
|
||||
goto out;
|
||||
}
|
||||
/* Device inodes must have a device spec attribute */
|
||||
if (!dsea || !udf_device_spec_valid(dsea)) {
|
||||
ret = -EFSCORRUPTED;
|
||||
goto out;
|
||||
}
|
||||
init_special_inode(inode, inode->i_mode,
|
||||
MKDEV(le32_to_cpu(dsea->majorDeviceIdent),
|
||||
le32_to_cpu(dsea->minorDeviceIdent)));
|
||||
/* Developer ID ??? */
|
||||
} else
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
|
|
@ -1757,6 +1783,7 @@ int udf_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
|
||||
unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
int err;
|
||||
|
||||
bh = sb_getblk(inode->i_sb,
|
||||
udf_get_lb_pblock(inode->i_sb, &iinfo->i_location, 0));
|
||||
|
|
@ -1816,11 +1843,21 @@ int udf_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
struct regid *eid;
|
||||
struct deviceSpec *dsea =
|
||||
(struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
|
||||
|
||||
/* Validity of extended attrs was checked on load */
|
||||
if (WARN_ON_ONCE(IS_ERR(dsea))) {
|
||||
err = PTR_ERR(dsea);
|
||||
goto out_unlock;
|
||||
}
|
||||
if (!dsea) {
|
||||
dsea = (struct deviceSpec *)
|
||||
udf_add_extendedattr(inode,
|
||||
sizeof(struct deviceSpec) +
|
||||
sizeof(struct regid), 12, 0x3);
|
||||
if (IS_ERR(dsea)) {
|
||||
err = PTR_ERR(dsea);
|
||||
goto out_unlock;
|
||||
}
|
||||
dsea->attrType = cpu_to_le32(12);
|
||||
dsea->attrSubtype = 1;
|
||||
dsea->attrLength = cpu_to_le32(
|
||||
|
|
@ -1962,6 +1999,11 @@ int udf_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
set_inode_metadata_writeback(inode);
|
||||
|
||||
return 0;
|
||||
|
||||
out_unlock:
|
||||
unlock_buffer(bh);
|
||||
brelse(bh);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
|
|||
cpu_to_le16(TAG_IDENT_EAHD) ||
|
||||
le32_to_cpu(eahd->descTag.tagLocation) !=
|
||||
iinfo->i_location.logicalBlockNum)
|
||||
return NULL;
|
||||
return ERR_PTR(-EFSCORRUPTED);
|
||||
} else {
|
||||
struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
|
|||
return (struct genericFormat *)&ea[offset];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOSPC);
|
||||
}
|
||||
|
||||
struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
|
||||
|
|
@ -144,7 +144,7 @@ struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
|
|||
cpu_to_le16(TAG_IDENT_EAHD) ||
|
||||
le32_to_cpu(eahd->descTag.tagLocation) !=
|
||||
iinfo->i_location.logicalBlockNum)
|
||||
return NULL;
|
||||
return ERR_PTR(-EFSCORRUPTED);
|
||||
|
||||
if (type < 2048)
|
||||
offset = sizeof(struct extendedAttrHeaderDesc);
|
||||
|
|
@ -153,16 +153,17 @@ struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
|
|||
else
|
||||
offset = le32_to_cpu(eahd->appAttrLocation);
|
||||
|
||||
while (offset + sizeof(*gaf) < iinfo->i_lenEAttr) {
|
||||
while (offset <
|
||||
iinfo->i_lenEAttr - sizeof(struct genericFormat)) {
|
||||
uint32_t attrLength;
|
||||
|
||||
gaf = (struct genericFormat *)&ea[offset];
|
||||
attrLength = le32_to_cpu(gaf->attrLength);
|
||||
|
||||
/* Detect undersized elements and buffer overflows */
|
||||
if ((attrLength < sizeof(*gaf)) ||
|
||||
(attrLength > (iinfo->i_lenEAttr - offset)))
|
||||
break;
|
||||
if (attrLength < sizeof(struct genericFormat) ||
|
||||
attrLength > iinfo->i_lenEAttr - offset)
|
||||
return ERR_PTR(-EFSCORRUPTED);
|
||||
|
||||
if (le32_to_cpu(gaf->attrType) == type &&
|
||||
gaf->attrSubtype == subtype)
|
||||
|
|
|
|||
|
|
@ -1617,7 +1617,10 @@ static bool udf_lvid_valid(struct super_block *sb,
|
|||
|
||||
parts = le32_to_cpu(lvid->numOfPartitions);
|
||||
impuselen = le32_to_cpu(lvid->lengthOfImpUse);
|
||||
if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize ||
|
||||
if (sizeof(struct logicalVolIntegrityDescImpUse) > impuselen ||
|
||||
impuselen >= sb->s_blocksize)
|
||||
return false;
|
||||
if (parts >= sb->s_blocksize ||
|
||||
sizeof(struct logicalVolIntegrityDesc) + impuselen +
|
||||
2 * parts * sizeof(u32) > sb->s_blocksize)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -10,19 +10,21 @@
|
|||
#define DO_ONCE_LITE(func, ...) \
|
||||
DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
|
||||
|
||||
#define __ONCE_LITE_IF(condition) \
|
||||
#define __ONCE_LITE() \
|
||||
({ \
|
||||
static bool __section(".data..once") __already_done; \
|
||||
bool __ret_cond = !!(condition); \
|
||||
bool __ret_once = false; \
|
||||
\
|
||||
if (unlikely(__ret_cond) && unlikely(!__already_done)) {\
|
||||
if (unlikely(!__already_done)) { \
|
||||
__already_done = true; \
|
||||
__ret_once = true; \
|
||||
} \
|
||||
unlikely(__ret_once); \
|
||||
})
|
||||
|
||||
#define __ONCE_LITE_IF(condition) \
|
||||
(unlikely(condition) && __ONCE_LITE())
|
||||
|
||||
#define DO_ONCE_LITE_IF(condition, func, ...) \
|
||||
({ \
|
||||
bool __ret_do_once = !!(condition); \
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/magic.h>
|
||||
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/quota.h>
|
||||
|
|
@ -54,6 +55,10 @@ struct quota_id {
|
|||
|
||||
static int shmem_check_quota_file(struct super_block *sb, int type)
|
||||
{
|
||||
/* Verify enabling happens on tmpfs superblock */
|
||||
if (sb->s_magic != TMPFS_MAGIC)
|
||||
return 0;
|
||||
|
||||
/* There is no real quota file, nothing to do */
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user