From aed82035c0d194347f5cab17ebd48f355c379b1b Mon Sep 17 00:00:00 2001 From: James Simmons Date: Tue, 14 May 2013 10:39:12 -0400 Subject: [PATCH] LU-2479 ldiskfs: fix max_dir_size checking This patch fix max_dir_size checking and adds max_dir_size_kb mount options according to ext4 main line patch df981d03eeff7971ac7e6ff37000bfa702327ef1. Sanity test 129 changed to check directory size limits. 1) file creation without directory size increase 2) file creation after directory limit 3) file creation with disable limit Signed-off-by: Alexander Boyko Signed-off-by: James Simmons Xyratex-bug-id: MRP-697 Change-Id: I3b8502c0b1fa77622a4a0da6ef8d33d4f8194f69 Reviewed-on: http://review.whamcloud.com/5140 Tested-by: Hudson Tested-by: Maloo Reviewed-by: Keith Mannthey Reviewed-by: Andreas Dilger --- .../rhel6.3/ext4-max-dir-size-options.patch | 36 ++++++++++ .../patches/rhel6.3/ext4-max-dir-size.patch | 84 +++++++++++----------- .../rhel6.4/ext4-max-dir-size-options.patch | 36 ++++++++++ .../sles11sp1/ext4-max-dir-size-options.patch | 36 ++++++++++ .../sles11sp2/ext4-max-dir-size-options.patch | 33 +++++++++ .../series/ldiskfs-2.6-rhel6.4.series | 3 +- .../kernel_patches/series/ldiskfs-2.6-rhel6.series | 3 +- .../series/ldiskfs-2.6-sles11.series | 3 +- .../series/ldiskfs-3.0-sles11.series | 3 +- lustre/tests/sanity.sh | 27 +++++-- 10 files changed, 212 insertions(+), 52 deletions(-) create mode 100644 ldiskfs/kernel_patches/patches/rhel6.3/ext4-max-dir-size-options.patch create mode 100644 ldiskfs/kernel_patches/patches/rhel6.4/ext4-max-dir-size-options.patch create mode 100644 ldiskfs/kernel_patches/patches/sles11sp1/ext4-max-dir-size-options.patch create mode 100644 ldiskfs/kernel_patches/patches/sles11sp2/ext4-max-dir-size-options.patch diff --git a/ldiskfs/kernel_patches/patches/rhel6.3/ext4-max-dir-size-options.patch b/ldiskfs/kernel_patches/patches/rhel6.3/ext4-max-dir-size-options.patch new file mode 100644 index 0000000..edb5726 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/rhel6.3/ext4-max-dir-size-options.patch @@ -0,0 +1,36 @@ +diff -urpN linux-stage.orig/fs/ext4/super.c linux-stage/fs/ext4/super.c +--- linux-stage.orig/fs/ext4/super.c 2013-05-13 10:29:34.125478791 -0400 ++++ linux-stage/fs/ext4/super.c 2013-05-13 10:31:59.800359005 -0400 +@@ -1264,8 +1264,8 @@ enum { + Opt_mballoc, Opt_bigendian_extents, Opt_force_over_128tb, + Opt_extents, Opt_noextents, + Opt_no_mbcache, +- Opt_discard, Opt_nodiscard, +- Opt_init_inode_table, Opt_noinit_inode_table, ++ Opt_discard, Opt_nodiscard, Opt_init_inode_table, Opt_noinit_inode_table, ++ Opt_max_dir_size_kb, + }; + + static const match_table_t tokens = { +@@ -1346,6 +1346,7 @@ static const match_table_t tokens = { + {Opt_init_inode_table, "init_itable=%u"}, + {Opt_init_inode_table, "init_itable"}, + {Opt_noinit_inode_table, "noinit_itable"}, ++ {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, + {Opt_err, NULL}, + }; + +@@ -1732,6 +1733,13 @@ set_qf_format: + case Opt_nodelalloc: + clear_opt(sbi->s_mount_opt, DELALLOC); + break; ++ case Opt_max_dir_size_kb: ++ if (match_int(&args[0], &option)) ++ return 0; ++ if (option < 0) ++ return 0; ++ sbi->s_max_dir_size = option * 1024; ++ break; + case Opt_stripe: + if (match_int(&args[0], &option)) + return 0; diff --git a/ldiskfs/kernel_patches/patches/rhel6.3/ext4-max-dir-size.patch b/ldiskfs/kernel_patches/patches/rhel6.3/ext4-max-dir-size.patch index 5046b48..6741924 100644 --- a/ldiskfs/kernel_patches/patches/rhel6.3/ext4-max-dir-size.patch +++ b/ldiskfs/kernel_patches/patches/rhel6.3/ext4-max-dir-size.patch @@ -1,29 +1,37 @@ -Index: linux-2.6.32-el6-beta/fs/ext4/ialloc.c +Index: linux-2.6.32-el6-beta/fs/ext4/namei.c =================================================================== ---- linux-2.6.32-el6-beta.orig/fs/ext4/ialloc.c -+++ linux-2.6.32-el6-beta/fs/ext4/ialloc.c -@@ -825,11 +825,15 @@ struct inode *ext4_new_inode(handle_t *h - sb = dir->i_sb; - ngroups = ext4_get_groups_count(sb); - trace_ext4_request_inode(dir, mode); -+ -+ sbi = EXT4_SB(sb); -+ if (sbi->s_max_dir_size > 0 && i_size_read(dir) >= sbi->s_max_dir_size) -+ return ERR_PTR(-EFBIG); +--- linux-2.6.32-el6-beta/fs/ext4/namei.c ++++ linux-2.6.32-el6-beta/fs/ext4/namei.c +@@ -59,6 +59,14 @@ static struct buffer_head *ext4_append(h + * have to be serialized -bzzz */ + down(&ei->i_append_sem); + ++ if (unlikely(EXT4_SB(inode->i_sb)->s_max_dir_size && ++ (inode->i_size >= ++ EXT4_SB(inode->i_sb)->s_max_dir_size))) { ++ *err = -ENOSPC; ++ up(&ei->i_append_sem); ++ return NULL; ++ } + - inode = new_inode(sb); - if (!inode) - return ERR_PTR(-ENOMEM); - ei = EXT4_I(inode); -- sbi = EXT4_SB(sb); + *block = inode->i_size >> inode->i_sb->s_blocksize_bits; - if (!goal) - goal = sbi->s_inode_goal; + bh = ext4_bread(handle, inode, *block, 1, err); Index: linux-2.6.32-el6-beta/fs/ext4/super.c =================================================================== --- linux-2.6.32-el6-beta.orig/fs/ext4/super.c +++ linux-2.6.32-el6-beta/fs/ext4/super.c -@@ -2601,6 +2601,7 @@ EXT4_RO_ATTR(lifetime_write_kbytes); +@@ -999,6 +999,9 @@ static int ext4_show_options(struct seq_ + seq_printf(seq, ",init_itable=%u", + (unsigned) sbi->s_li_wait_mult); + ++ if (sbi->s_max_dir_size) ++ seq_printf(seq, "max_dir_size=%lu", sbi->s_max_dir_size); ++ + ext4_show_quota_options(seq, sb); + + return 0; +@@ -2373,6 +2384,7 @@ EXT4_RO_ATTR(lifetime_write_kbytes); EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, inode_readahead_blks_store, s_inode_readahead_blks); EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); @@ -31,7 +39,7 @@ Index: linux-2.6.32-el6-beta/fs/ext4/super.c EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); -@@ -2615,6 +2616,7 @@ static struct attribute *ext4_attrs[] = +@@ -2388,6 +2400,7 @@ static struct attribute *ext4_attrs[] = ATTR_LIST(lifetime_write_kbytes), ATTR_LIST(inode_readahead_blks), ATTR_LIST(inode_goal), @@ -39,29 +47,23 @@ Index: linux-2.6.32-el6-beta/fs/ext4/super.c ATTR_LIST(mb_stats), ATTR_LIST(mb_max_to_scan), ATTR_LIST(mb_min_to_scan), +@@ -2877,6 +2890,7 @@ static int ext4_fill_super(struct super_ + } + sb->s_fs_info = sbi; + sbi->s_mount_opt = 0; ++ sbi->s_max_dir_size = 0; + sbi->s_resuid = EXT4_DEF_RESUID; + sbi->s_resgid = EXT4_DEF_RESGID; + sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; Index: linux-2.6.32-el6-beta/fs/ext4/ext4.h =================================================================== --- linux-2.6.32-el6-beta.orig/fs/ext4/ext4.h +++ linux-2.6.32-el6-beta/fs/ext4/ext4.h -@@ -1029,6 +1029,8 @@ struct ext4_sb_info { - - unsigned int s_log_groups_per_flex; - struct flex_groups *s_flex_groups; -+ +@@ -1113,6 +1113,7 @@ struct ext4_sb_info { + unsigned long s_mb_prealloc_table_size; + unsigned int s_mb_group_prealloc; + unsigned int s_max_writeback_mb_bump; + unsigned long s_max_dir_size; - - /* workqueue for dio unwritten */ - struct workqueue_struct *dio_unwritten_wq; -@@ -1353,6 +1355,12 @@ struct mmp_struct { - #define EXT4_MMP_MIN_CHECK_INTERVAL 5 - - /* -+ * max directory size tunable -+ */ -+#define EXT4_DEFAULT_MAX_DIR_SIZE 0 -+#define EXT4_MAX_DIR_SIZE_NAME "max_dir_size" -+ -+/* - * Function prototypes - */ - + /* where last allocation was done - for stream allocation */ + unsigned long s_mb_last_group; + unsigned long s_mb_last_start; diff --git a/ldiskfs/kernel_patches/patches/rhel6.4/ext4-max-dir-size-options.patch b/ldiskfs/kernel_patches/patches/rhel6.4/ext4-max-dir-size-options.patch new file mode 100644 index 0000000..e056c7c --- /dev/null +++ b/ldiskfs/kernel_patches/patches/rhel6.4/ext4-max-dir-size-options.patch @@ -0,0 +1,36 @@ +diff -urpN linux-stage.orig/fs/ext4/super.c linux-stage/fs/ext4/super.c +--- linux-stage.orig/fs/ext4/super.c 2013-05-13 09:35:17.628478645 -0400 ++++ linux-stage/fs/ext4/super.c 2013-05-13 09:46:08.062358974 -0400 +@@ -1268,8 +1268,8 @@ enum { + Opt_mballoc, Opt_bigendian_extents, Opt_force_over_128tb, + Opt_extents, Opt_noextents, + Opt_no_mbcache, +- Opt_discard, Opt_nodiscard, +- Opt_init_itable, Opt_noinit_itable, ++ Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, ++ Opt_max_dir_size_kb, + }; + + static const match_table_t tokens = { +@@ -1350,6 +1350,7 @@ static const match_table_t tokens = { + {Opt_init_itable, "init_itable=%u"}, + {Opt_init_itable, "init_itable"}, + {Opt_noinit_itable, "noinit_itable"}, ++ {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, + {Opt_err, NULL}, + }; + +@@ -1736,6 +1737,13 @@ set_qf_format: + case Opt_nodelalloc: + clear_opt(sbi->s_mount_opt, DELALLOC); + break; ++ case Opt_max_dir_size_kb: ++ if (match_int(&args[0], &option)) ++ return 0; ++ if (option < 0) ++ return 0; ++ sbi->s_max_dir_size = option * 1024; ++ break; + case Opt_stripe: + if (match_int(&args[0], &option)) + return 0; diff --git a/ldiskfs/kernel_patches/patches/sles11sp1/ext4-max-dir-size-options.patch b/ldiskfs/kernel_patches/patches/sles11sp1/ext4-max-dir-size-options.patch new file mode 100644 index 0000000..050b928 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/sles11sp1/ext4-max-dir-size-options.patch @@ -0,0 +1,36 @@ +diff -urpN linux-stage.orig/fs/ext4/super.c linux-stage/fs/ext4/super.c +--- linux-stage.orig/fs/ext4/super.c 2013-05-13 11:44:45.000000000 -0400 ++++ linux-stage/fs/ext4/super.c 2013-05-13 11:50:19.000000000 -0400 +@@ -1248,8 +1248,8 @@ enum { + Opt_mballoc, Opt_bigendian_extents, Opt_force_over_128tb, + Opt_extents, Opt_noextents, + Opt_no_mbcache, +- Opt_discard, Opt_nodiscard, +- Opt_init_inode_table, Opt_noinit_inode_table, ++ Opt_discard, Opt_nodiscard, Opt_init_inode_table, Opt_noinit_inode_table, ++ Opt_max_dir_size_kb, + }; + + static const match_table_t tokens = { +@@ -1326,6 +1326,7 @@ static const match_table_t tokens = { + {Opt_noextents, "noextents"}, + {Opt_discard, "discard"}, + {Opt_nodiscard, "nodiscard"}, ++ {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, + {Opt_err, NULL}, + }; + +@@ -1708,6 +1709,13 @@ set_qf_format: + case Opt_nodelalloc: + clear_opt(sbi->s_mount_opt, DELALLOC); + break; ++ case Opt_max_dir_size_kb: ++ if (match_int(&args[0], &option)) ++ return 0; ++ if (option < 0) ++ return 0; ++ sbi->s_max_dir_size = option * 1024; ++ break; + case Opt_stripe: + if (match_int(&args[0], &option)) + return 0; diff --git a/ldiskfs/kernel_patches/patches/sles11sp2/ext4-max-dir-size-options.patch b/ldiskfs/kernel_patches/patches/sles11sp2/ext4-max-dir-size-options.patch new file mode 100644 index 0000000..f2c7e5a --- /dev/null +++ b/ldiskfs/kernel_patches/patches/sles11sp2/ext4-max-dir-size-options.patch @@ -0,0 +1,33 @@ +diff -urpN linux-stage.orig/fs/ext4/super.c linux-stage/fs/ext4/super.c +--- linux-stage.orig/fs/ext4/super.c 2013-05-13 11:04:01.000000000 -0400 ++++ linux-stage/fs/ext4/super.c 2013-05-13 11:05:23.000000000 -0400 +@@ -1369,6 +1369,7 @@ enum { + Opt_extents, Opt_noextents, + Opt_no_mbcache, + Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, ++ Opt_max_dir_size_kb, + }; + + static const match_table_t tokens = { +@@ -1453,6 +1454,7 @@ static const match_table_t tokens = { + {Opt_init_itable, "init_itable=%u"}, + {Opt_init_itable, "init_itable"}, + {Opt_noinit_itable, "noinit_itable"}, ++ {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, + {Opt_err, NULL}, + }; + +@@ -1871,6 +1873,13 @@ set_qf_format: + case Opt_nomblk_io_submit: + clear_opt(sb, MBLK_IO_SUBMIT); + break; ++ case Opt_max_dir_size_kb: ++ if (match_int(&args[0], &option)) ++ return 0; ++ if (option < 0) ++ return 0; ++ sbi->s_max_dir_size = option * 1024; ++ break; + case Opt_stripe: + if (match_int(&args[0], &option)) + return 0; diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.4.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.4.series index 409e8cd..6bdb397 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.4.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.4.series @@ -7,7 +7,6 @@ sles11sp1/ext4-ext_generation.patch rhel6.3/ext4-inode-version.patch rhel6.4/ext4-mmp.patch rhel6.3/ext4-lookup-dotdot.patch -rhel6.3/ext4-max-dir-size.patch rhel6.3/ext4-print-inum-in-htree-warning.patch rhel6.3/ext4-xattr-no-update-ctime.patch rhel6.4/ext4-prealloc.patch @@ -41,3 +40,5 @@ rhel6.3/ext4-quota-first-class.patch rhel6.3/ext4-inode_info_reorganize.patch rhel6.4/ext4-fix-mbgroups-access.patch rhel6.3/ext4-fix-ext4_mb_add_n_trim.patch +rhel6.3/ext4-max-dir-size.patch +rhel6.4/ext4-max-dir-size-options.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.series index e051972..75eb54c 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.series @@ -7,7 +7,6 @@ sles11sp1/ext4-ext_generation.patch rhel6.3/ext4-inode-version.patch rhel6.3/ext4-mmp.patch rhel6.3/ext4-lookup-dotdot.patch -rhel6.3/ext4-max-dir-size.patch rhel6.3/ext4-print-inum-in-htree-warning.patch rhel6.3/ext4-xattr-no-update-ctime.patch rhel6.3/ext4-prealloc.patch @@ -41,3 +40,5 @@ rhel6.3/ext4-quota-first-class.patch rhel6.3/ext4-inode_info_reorganize.patch rhel6.3/ext4-fix-mbgroups-access.patch rhel6.3/ext4-fix-ext4_mb_add_n_trim.patch +rhel6.3/ext4-max-dir-size.patch +rhel6.3/ext4-max-dir-size-options.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series index 2c35389..2e18297 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles11.series @@ -8,7 +8,6 @@ rhel6.3/ext4-inode-version.patch sles11sp1/ext4-update-sles11-rhel6.patch rhel6.3/ext4-mmp.patch rhel6.3/ext4-lookup-dotdot.patch -rhel6.3/ext4-max-dir-size.patch rhel6.3/ext4-print-inum-in-htree-warning.patch rhel6.3/ext4-xattr-no-update-ctime.patch rhel6.3/ext4-prealloc.patch @@ -41,3 +40,5 @@ rhel6.3/ext4-quota-force-block-alloc-quotaoff.patch rhel6.3/ext4-quota-dont-update-cmtime.patch rhel6.3/ext4-quota-first-class.patch rhel6.3/ext4-fix-ext4_mb_add_n_trim.patch +rhel6.3/ext4-max-dir-size.patch +sles11sp1/ext4-max-dir-size-options.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11.series b/ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11.series index 3f3f6dd..598524c 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11.series @@ -15,7 +15,6 @@ rhel6.3/ext4-nlink-2.6.patch sles11sp2/ext4-ext_generation.patch rhel6.3/ext4-inode-version.patch sles11sp2/ext4-lookup-dotdot.patch -rhel6.3/ext4-max-dir-size.patch rhel6.3/ext4-print-inum-in-htree-warning.patch rhel6.3/ext4-xattr-no-update-ctime.patch sles11sp2/ext4-prealloc.patch @@ -42,3 +41,5 @@ rhel6.3/ext4-nocmtime-2.6.patch rhel6.3/ext4-export-64bit-name-hash.patch sles11sp2/ext4-store-tree-generation-at-find.patch sles11sp2/ext4_pdirop.patch +rhel6.3/ext4-max-dir-size.patch +sles11sp2/ext4-max-dir-size-options.patch diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index d4aa2fc..3f8badb 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -7727,31 +7727,44 @@ test_129() { fi remote_mds_nodsh && skip "remote MDS with nodsh" && return + ENOSPC=28 EFBIG=27 - MAX=16384 - set_dir_limits $MAX test_mkdir -p $DIR/$tdir + MAX=$(stat -c%s "$DIR/$tdir") + set_dir_limits $MAX local I=0 local J=0 - while [ ! $I -gt $((MAX * MDSCOUNT)) ]; do + while [ ! $I -gt $MAX ]; do $MULTIOP $DIR/$tdir/$J Oc rc=$? - if [ $rc -eq $EFBIG ]; then + #check two errors ENOSPC for new version of ext4 max_dir_size patch + #mainline kernel commit df981d03eeff7971ac7e6ff37000bfa702327ef1 + #and EFBIG for previous versions + if [ $rc -eq $EFBIG -o $rc -eq $ENOSPC ] && [ $I -gt 0 ]; then set_dir_limits 0 echo "return code $rc received as expected" - return 0 + multiop $DIR/$tdir/$J Oc + rc=$? + I=$(stat -c%s "$DIR/$tdir") + if [ $I -gt $MAX ] && [ $rc -eq 0 ]; then + return 0 + else + error_exit "return code $rc current dir size $I " \ + "previous limit $MAX" + fi elif [ $rc -ne 0 ]; then set_dir_limits 0 - error_exit "return code $rc received instead of expected $EFBIG" + error_exit "return code $rc received instead of expected " \ + "$EFBIG or $ENOSPC, files in dir $I" fi J=$((J+1)) I=$(stat -c%s "$DIR/$tdir") done set_dir_limits 0 - error "exceeded dir size limit $MAX x $MDSCOUNT $((MAX * MDSCOUNT)) : $I bytes" + error "exceeded dir size limit $MAX x $MDSCOUNT $MAX : $I bytes" } run_test 129 "test directory size limit ========================" -- 1.8.3.1