Date: Tue, 19 Sep 2006 15:33:04 -0500 From: Eric Sandeen Subject: [RHEL5 Patch 3/3] (resend) Fix ext3 32-bit inodes This one is in the -mm tree as ext3-inode-numbers-are-unsigned-long.patch, resent to accomodate sct's request for uints instead; just pinged akpm to pick up the ulonglong->uint change. This is primarily format string fixes, with changes to ialloc.c where large inode counts could overflow, and also pass around journal_inum as an unsigned long, just to be pedantic about it.... Signed-off-by: Eric Sandeen Cc: Mingming Cao Signed-off-by: Andrew Morton Index: linux-2.6.17-1.2654.el5/fs/ext3/ialloc.c =================================================================== --- linux-2.6.17-1.2654.el5.orig/fs/ext3/ialloc.c +++ linux-2.6.17-1.2654.el5/fs/ext3/ialloc.c @@ -202,7 +202,7 @@ error_return: static int find_group_dir(struct super_block *sb, struct inode *parent) { int ngroups = EXT3_SB(sb)->s_groups_count; - int freei, avefreei; + unsigned int freei, avefreei; struct ext3_group_desc *desc, *best_desc = NULL; struct buffer_head *bh; int group, best_group = -1; @@ -261,10 +261,10 @@ static int find_group_orlov(struct super struct ext3_super_block *es = sbi->s_es; int ngroups = sbi->s_groups_count; int inodes_per_group = EXT3_INODES_PER_GROUP(sb); - int freei, avefreei; + unsigned int freei, avefreei; ext3_fsblk_t freeb, avefreeb; ext3_fsblk_t blocks_per_dir; - int ndirs; + unsigned int ndirs; int max_debt, max_dirs, min_inodes; ext3_grpblk_t min_blocks; int group = -1, i; Index: linux-2.6.17-1.2654.el5/fs/ext3/inode.c =================================================================== --- linux-2.6.17-1.2654.el5.orig/fs/ext3/inode.c +++ linux-2.6.17-1.2654.el5/fs/ext3/inode.c @@ -2115,7 +2115,7 @@ static void ext3_free_branches(handle_t */ if (!bh) { ext3_error(inode->i_sb, "ext3_free_branches", - "Read failure, inode=%ld, block="E3FSBLK, + "Read failure, inode=%lu, block="E3FSBLK, inode->i_ino, nr); continue; } Index: linux-2.6.17-1.2654.el5/fs/ext3/namei.c =================================================================== --- linux-2.6.17-1.2654.el5.orig/fs/ext3/namei.c +++ linux-2.6.17-1.2654.el5/fs/ext3/namei.c @@ -1919,8 +1919,8 @@ int ext3_orphan_add(handle_t *handle, st if (!err) list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); - jbd_debug(4, "superblock will point to %ld\n", inode->i_ino); - jbd_debug(4, "orphan inode %ld will point to %d\n", + jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); + jbd_debug(4, "orphan inode %lu will point to %d\n", inode->i_ino, NEXT_ORPHAN(inode)); out_unlock: unlock_super(sb); Index: linux-2.6.17-1.2654.el5/fs/ext3/super.c =================================================================== --- linux-2.6.17-1.2654.el5.orig/fs/ext3/super.c +++ linux-2.6.17-1.2654.el5/fs/ext3/super.c @@ -45,7 +45,7 @@ static int ext3_load_journal(struct super_block *, struct ext3_super_block *, unsigned long journal_devnum); static int ext3_create_journal(struct super_block *, struct ext3_super_block *, - int); + unsigned int); static void ext3_commit_super (struct super_block * sb, struct ext3_super_block * es, int sync); @@ -376,7 +376,7 @@ static void dump_orphan_list(struct supe list_for_each(l, &sbi->s_orphan) { struct inode *inode = orphan_list_entry(l); printk(KERN_ERR " " - "inode %s:%ld at %p: mode %o, nlink %d, next %d\n", + "inode %s:%lu at %p: mode %o, nlink %d, next %d\n", inode->i_sb->s_id, inode->i_ino, inode, inode->i_mode, inode->i_nlink, NEXT_ORPHAN(inode)); @@ -711,7 +711,7 @@ static ext3_fsblk_t get_sb_block(void ** } static int parse_options (char *options, struct super_block *sb, - unsigned long *inum, unsigned long *journal_devnum, + unsigned int *inum, unsigned long *journal_devnum, ext3_fsblk_t *n_blocks_count, int is_remount) { struct ext3_sb_info *sbi = EXT3_SB(sb); @@ -1264,17 +1264,17 @@ static void ext3_orphan_cleanup (struct DQUOT_INIT(inode); if (inode->i_nlink) { printk(KERN_DEBUG - "%s: truncating inode %ld to %Ld bytes\n", + "%s: truncating inode %lu to %Ld bytes\n", __FUNCTION__, inode->i_ino, inode->i_size); - jbd_debug(2, "truncating inode %ld to %Ld bytes\n", + jbd_debug(2, "truncating inode %lu to %Ld bytes\n", inode->i_ino, inode->i_size); ext3_truncate(inode); nr_truncates++; } else { printk(KERN_DEBUG - "%s: deleting unreferenced inode %ld\n", + "%s: deleting unreferenced inode %lu\n", __FUNCTION__, inode->i_ino); - jbd_debug(2, "deleting unreferenced inode %ld\n", + jbd_debug(2, "deleting unreferenced inode %lu\n", inode->i_ino); nr_orphans++; } @@ -1353,7 +1353,7 @@ static int ext3_fill_super (struct super ext3_fsblk_t sb_block = get_sb_block(&data); ext3_fsblk_t logic_sb_block; unsigned long offset = 0; - unsigned long journal_inum = 0; + unsigned int journal_inum = 0; unsigned long journal_devnum = 0; unsigned long def_mount_opts; struct inode *root; @@ -1802,7 +1802,8 @@ static void ext3_init_journal_params(str spin_unlock(&journal->j_state_lock); } -static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum) +static journal_t *ext3_get_journal(struct super_block *sb, + unsigned int journal_inum) { struct inode *journal_inode; journal_t *journal; @@ -1937,7 +1938,7 @@ static int ext3_load_journal(struct supe unsigned long journal_devnum) { journal_t *journal; - int journal_inum = le32_to_cpu(es->s_journal_inum); + unsigned int journal_inum = le32_to_cpu(es->s_journal_inum); dev_t journal_dev; int err = 0; int really_read_only; @@ -2023,7 +2024,7 @@ static int ext3_load_journal(struct supe static int ext3_create_journal(struct super_block * sb, struct ext3_super_block * es, - int journal_inum) + unsigned int journal_inum) { journal_t *journal; @@ -2036,7 +2037,7 @@ static int ext3_create_journal(struct su if (!(journal = ext3_get_journal(sb, journal_inum))) return -EINVAL; - printk(KERN_INFO "EXT3-fs: creating new journal on inode %d\n", + printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n", journal_inum); if (journal_create(journal)) { Index: linux-2.6.17-1.2654.el5/fs/ext3/xattr.c =================================================================== --- linux-2.6.17-1.2654.el5.orig/fs/ext3/xattr.c +++ linux-2.6.17-1.2654.el5/fs/ext3/xattr.c @@ -75,7 +75,7 @@ #ifdef EXT3_XATTR_DEBUG # define ea_idebug(inode, f...) do { \ - printk(KERN_DEBUG "inode %s:%ld: ", \ + printk(KERN_DEBUG "inode %s:%lu: ", \ inode->i_sb->s_id, inode->i_ino); \ printk(f); \ printk("\n"); \ @@ -233,7 +233,7 @@ ext3_xattr_block_get(struct inode *inode atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); if (ext3_xattr_check_block(bh)) { bad_block: ext3_error(inode->i_sb, __FUNCTION__, - "inode %ld: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block "E3FSBLK, inode->i_ino, EXT3_I(inode)->i_file_acl); error = -EIO; goto cleanup; @@ -375,7 +375,7 @@ ext3_xattr_block_list(struct inode *inod atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); if (ext3_xattr_check_block(bh)) { ext3_error(inode->i_sb, __FUNCTION__, - "inode %ld: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block "E3FSBLK, inode->i_ino, EXT3_I(inode)->i_file_acl); error = -EIO; goto cleanup; @@ -647,7 +647,7 @@ ext3_xattr_block_find(struct inode *inod le32_to_cpu(BHDR(bs->bh)->h_refcount)); if (ext3_xattr_check_block(bs->bh)) { ext3_error(sb, __FUNCTION__, - "inode %ld: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block "E3FSBLK, inode->i_ino, EXT3_I(inode)->i_file_acl); error = -EIO; goto cleanup; @@ -848,7 +848,7 @@ cleanup_dquot: bad_block: ext3_error(inode->i_sb, __FUNCTION__, - "inode %ld: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block "E3FSBLK, inode->i_ino, EXT3_I(inode)->i_file_acl); goto cleanup; @@ -1077,14 +1077,14 @@ ext3_xattr_delete_inode(handle_t *handle bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); if (!bh) { ext3_error(inode->i_sb, __FUNCTION__, - "inode %ld: block "E3FSBLK" read error", inode->i_ino, + "inode %lu: block "E3FSBLK" read error", inode->i_ino, EXT3_I(inode)->i_file_acl); goto cleanup; } if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || BHDR(bh)->h_blocks != cpu_to_le32(1)) { ext3_error(inode->i_sb, __FUNCTION__, - "inode %ld: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block "E3FSBLK, inode->i_ino, EXT3_I(inode)->i_file_acl); goto cleanup; } @@ -1211,7 +1211,7 @@ again: bh = sb_bread(inode->i_sb, ce->e_block); if (!bh) { ext3_error(inode->i_sb, __FUNCTION__, - "inode %ld: block %lu read error", + "inode %lu: block %lu read error", inode->i_ino, (unsigned long) ce->e_block); } else if (le32_to_cpu(BHDR(bh)->h_refcount) >= EXT3_XATTR_REFCOUNT_MAX) { Date: Tue, 19 Sep 2006 15:32:02 -0500 From: Eric Sandeen Subject: [RHEL5 Patch 1/3] (resend) Fix ext3 overflows at 16T This one is in -mm as fix-ext3-mounts-at-16t.patch and fix-ext3-mounts-at-16t-fix.patch this gets things mounting for a 16T ext3 filesystem. (patched up e2fsprogs will be needed too, working on that) jarod wilson has been helping with testing. This patch fixes these issues in the kernel: o sbi->s_groups_count overflows in ext3_fill_super() sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) - le32_to_cpu(es->s_first_data_block) + EXT3_BLOCKS_PER_GROUP(sb) - 1) / EXT3_BLOCKS_PER_GROUP(sb); at 16T, s_blocks_count is already maxed out; adding EXT3_BLOCKS_PER_GROUP(sb) overflows it and groups_count comes out to 0. Not really what we want, and causes a failed mount. Changing it this way works & avoids the overflow: (A + B - 1)/B changed to: ((A - 1)/B) + 1 o ext3_check_descriptors() overflows range checks ext3_check_descriptors() iterates over all block groups making sure that various bits are within the right block ranges... on the last pass through, it is checking the error case [item] >= block + EXT3_BLOCKS_PER_GROUP(sb) where "block" is the first block in the last block group. The last block in this group (and the last one that will fit in 32 bits) is block + EXT3_BLOCKS_PER_GROUP(sb)- 1. block + EXT3_BLOCKS_PER_GROUP(sb) wraps back around to 0. so, make things clearer with "first_block" and "last_block" where those are first and last, inclusive, and use <, > rather than <, >=. Finally, the last block group may be smaller than the rest, so account for this on the last pass through: last_block = sb->s_blocks_count - 1; Signed-off-by: Eric Sandeen Cc: Mingming Cao Signed-off-by: Andrew Morton Index: linux-2.6.17-1.2654.el5/fs/ext3/super.c =================================================================== --- linux-2.6.17-1.2654.el5.orig/fs/ext3/super.c +++ linux-2.6.17-1.2654.el5/fs/ext3/super.c @@ -1132,7 +1132,8 @@ static int ext3_setup_super(struct super static int ext3_check_descriptors (struct super_block * sb) { struct ext3_sb_info *sbi = EXT3_SB(sb); - ext3_fsblk_t block = le32_to_cpu(sbi->s_es->s_first_data_block); + ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); + ext3_fsblk_t last_block; struct ext3_group_desc * gdp = NULL; int desc_block = 0; int i; @@ -1141,12 +1142,17 @@ static int ext3_check_descriptors (struc for (i = 0; i < sbi->s_groups_count; i++) { + if (i == sbi->s_groups_count - 1) + last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; + else + last_block = first_block + + (EXT3_BLOCKS_PER_GROUP(sb) - 1); + if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) gdp = (struct ext3_group_desc *) sbi->s_group_desc[desc_block++]->b_data; - if (le32_to_cpu(gdp->bg_block_bitmap) < block || - le32_to_cpu(gdp->bg_block_bitmap) >= - block + EXT3_BLOCKS_PER_GROUP(sb)) + if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || + le32_to_cpu(gdp->bg_block_bitmap) > last_block) { ext3_error (sb, "ext3_check_descriptors", "Block bitmap for group %d" @@ -1155,9 +1161,8 @@ static int ext3_check_descriptors (struc le32_to_cpu(gdp->bg_block_bitmap)); return 0; } - if (le32_to_cpu(gdp->bg_inode_bitmap) < block || - le32_to_cpu(gdp->bg_inode_bitmap) >= - block + EXT3_BLOCKS_PER_GROUP(sb)) + if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || + le32_to_cpu(gdp->bg_inode_bitmap) > last_block) { ext3_error (sb, "ext3_check_descriptors", "Inode bitmap for group %d" @@ -1166,9 +1171,9 @@ static int ext3_check_descriptors (struc le32_to_cpu(gdp->bg_inode_bitmap)); return 0; } - if (le32_to_cpu(gdp->bg_inode_table) < block || - le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >= - block + EXT3_BLOCKS_PER_GROUP(sb)) + if (le32_to_cpu(gdp->bg_inode_table) < first_block || + le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > + last_block) { ext3_error (sb, "ext3_check_descriptors", "Inode table for group %d" @@ -1177,7 +1182,7 @@ static int ext3_check_descriptors (struc le32_to_cpu(gdp->bg_inode_table)); return 0; } - block += EXT3_BLOCKS_PER_GROUP(sb); + first_block += EXT3_BLOCKS_PER_GROUP(sb); gdp++; } @@ -1580,10 +1585,9 @@ static int ext3_fill_super (struct super if (EXT3_BLOCKS_PER_GROUP(sb) == 0) goto cantfind_ext3; - sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_first_data_block) + - EXT3_BLOCKS_PER_GROUP(sb) - 1) / - EXT3_BLOCKS_PER_GROUP(sb); + sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - + le32_to_cpu(es->s_first_data_block) - 1) + / EXT3_BLOCKS_PER_GROUP(sb)) + 1; db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) / EXT3_DESC_PER_BLOCK(sb); sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), Date: Tue, 19 Sep 2006 15:32:42 -0500 From: Eric Sandeen Subject: [RHEL5 Patch 2/3] (resend) Fix more ext3 overflows at 16T This is in akpm's tree as more-ext3-16t-overflow-fixes.patch and more-ext3-16t-overflow-fixes-fix.patch Some of the changes in balloc.c are just cosmetic - if they overflow they'll then underflow and things are fine. 5th hunk actually fixes an overflow problem. Also check for potential overflows in inode & block counts when resizing. Signed-off-by: Eric Sandeen Cc: Mingming Cao Signed-off-by: Andrew Morton Index: linux-2.6.17-1.2654.el5/fs/ext3/balloc.c =================================================================== --- linux-2.6.17-1.2654.el5.orig/fs/ext3/balloc.c +++ linux-2.6.17-1.2654.el5/fs/ext3/balloc.c @@ -168,7 +168,7 @@ goal_in_my_reservation(struct ext3_reser ext3_fsblk_t group_first_block, group_last_block; group_first_block = ext3_group_first_block_no(sb, group); - group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1; + group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); if ((rsv->_rsv_start > group_last_block) || (rsv->_rsv_end < group_first_block)) @@ -897,7 +897,7 @@ static int alloc_new_reservation(struct spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; group_first_block = ext3_group_first_block_no(sb, group); - group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1; + group_end_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); if (grp_goal < 0) start_block = group_first_block; @@ -1063,7 +1063,7 @@ ext3_try_to_allocate_with_rsv(struct sup struct ext3_reserve_window_node * my_rsv, unsigned long *count, int *errp) { - ext3_fsblk_t group_first_block; + ext3_fsblk_t group_first_block, group_last_block; ext3_grpblk_t ret = 0; int fatal; unsigned long num = *count; @@ -1100,6 +1100,7 @@ ext3_try_to_allocate_with_rsv(struct sup * first block is the block number of the first block in this group */ group_first_block = ext3_group_first_block_no(sb, group); + group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); /* * Basically we will allocate a new block from inode's reservation @@ -1132,8 +1133,8 @@ ext3_try_to_allocate_with_rsv(struct sup try_to_extend_reservation(my_rsv, sb, *count-my_rsv->rsv_end + grp_goal - 1); - if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) - || (my_rsv->rsv_end < group_first_block)) + if ((my_rsv->rsv_start > group_last_block) || + (my_rsv->rsv_end < group_first_block)) BUG(); ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, grp_goal, &num, &my_rsv->rsv_window); Index: linux-2.6.17-1.2654.el5/fs/ext3/resize.c =================================================================== --- linux-2.6.17-1.2654.el5.orig/fs/ext3/resize.c +++ linux-2.6.17-1.2654.el5/fs/ext3/resize.c @@ -730,6 +730,18 @@ int ext3_group_add(struct super_block *s return -EPERM; } + if (le32_to_cpu(es->s_blocks_count) + input->blocks_count < + le32_to_cpu(es->s_blocks_count)) { + ext3_warning(sb, __FUNCTION__, "blocks_count overflow\n"); + return -EINVAL; + } + + if (le32_to_cpu(es->s_inodes_count) + EXT3_INODES_PER_GROUP(sb) < + le32_to_cpu(es->s_inodes_count)) { + ext3_warning(sb, __FUNCTION__, "inodes_count overflow\n"); + return -EINVAL; + } + if (reserved_gdb || gdb_off == 0) { if (!EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_RESIZE_INODE)){ @@ -958,6 +970,11 @@ int ext3_group_extend(struct super_block add = EXT3_BLOCKS_PER_GROUP(sb) - last; + if (o_blocks_count + add < o_blocks_count) { + ext3_warning(sb, __FUNCTION__, "blocks_count overflow"); + return -EINVAL; + } + if (o_blocks_count + add > n_blocks_count) add = n_blocks_count - o_blocks_count;