projects/linux·commit 744e5400

Merge tag 'fs_for_v7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

744e5400 · Linus Torvalds <[email protected]> · 2026-10-20 16:30:13 -10:00

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
  ...
Commit
744e5400b36f84b4816e3ff8531ec2dff52b474c
Parents
fefd797c · 0f242ca0

Merge commit. Changes below are compared with the first parent: fefd797c.

Changes

20 files changed · +276 −134

FileStatusAddDelContent
fs/ext2/Makefilemodified+2−0View file
fs/ext2/balloc.cmodified+4−0View file
fs/ext2/ext2.hmodified+11−8View file
fs/ext2/file.cmodified+7−0View file
fs/ext2/inode.cmodified+7−0View file
fs/ext2/super.cmodified+19−14View file
fs/isofs/compress.cmodified+43−34View file
fs/isofs/dir.cmodified+11−3View file
fs/isofs/inode.cmodified+28−42View file
fs/isofs/isofs.hmodified+14−2View file
fs/isofs/joliet.cmodified+20−7View file
fs/isofs/namei.cmodified+5−3View file
fs/isofs/rock.cmodified+15−4View file
fs/ocfs2/quota_local.cmodified+4−0View file
fs/quota/dquot.cmodified+16−0View file
fs/udf/inode.cmodified+48−6View file
fs/udf/misc.cmodified+8−7View file
fs/udf/super.cmodified+4−1View file
include/linux/once_lite.hmodified+5−3View file
mm/shmem_quota.cmodified+5−0View file

Only the first 600 diff lines are shown. Download the complete patch.

fs/ext2/Makefile

View file
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile
index 8860948..33db2e9 100644
--- a/fs/ext2/Makefile
+++ b/fs/ext2/Makefile
@@ -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 \

fs/ext2/balloc.c

View file
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index adf0f31..80acc1e 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -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;

fs/ext2/ext2.h

View file
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index cf2796e..7bdada9 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -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);

fs/ext2/file.c

View file
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index b9020df..67fe423 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -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)) {

fs/ext2/inode.c

View file
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index b52ded3..12ac4cf 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -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 @@ failed_out:
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 @@ failed:
*/
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 @@ no_top:
* 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;

fs/ext2/super.c

View file
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index a40f530..fb217ef 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -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);

fs/isofs/compress.c

View file
diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c
index f9869d6..2d23aba 100644
--- a/fs/isofs/compress.c
+++ b/fs/isofs/compress.c
@@ -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 @@ b_eio:
* 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;
}

fs/isofs/dir.c

View file
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 2874125..a6cfb86 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -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;

fs/isofs/inode.c

View file
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 337836a..4824e42 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -821,6 +821,8 @@ root_found:
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;
}
- inode->i_size += isonum_733(de->size);
- if (i == 1) {
- ei->i_next_section_block = block_saved;
- ei->i_next_section_offset = offset_saved;
+ /* 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);
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",

This diff is incomplete. Download the complete patch.

fs/isofs/isofs.h

View file

This diff is incomplete. Download the complete patch.

fs/isofs/joliet.c

View file

This diff is incomplete. Download the complete patch.

fs/isofs/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/isofs/rock.c

View file

This diff is incomplete. Download the complete patch.

fs/ocfs2/quota_local.c

View file

This diff is incomplete. Download the complete patch.

fs/quota/dquot.c

View file

This diff is incomplete. Download the complete patch.

fs/udf/inode.c

View file

This diff is incomplete. Download the complete patch.

fs/udf/misc.c

View file

This diff is incomplete. Download the complete patch.

fs/udf/super.c

View file

This diff is incomplete. Download the complete patch.

include/linux/once_lite.h

View file

This diff is incomplete. Download the complete patch.

mm/shmem_quota.c

View file

This diff is incomplete. Download the complete patch.