aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/ext4.txt10
-rw-r--r--fs/ext4/ext4.h1
-rw-r--r--fs/ext4/namei.c7
-rw-r--r--fs/ext4/super.c7
4 files changed, 25 insertions, 0 deletions
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 1b7f9acbcbbe..104322bf378c 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -375,6 +375,16 @@ dioread_nolock locking. If the dioread_nolock option is specified
375 Because of the restrictions this options comprises 375 Because of the restrictions this options comprises
376 it is off by default (e.g. dioread_lock). 376 it is off by default (e.g. dioread_lock).
377 377
378max_dir_size_kb=n This limits the size of directories so that any
379 attempt to expand them beyond the specified
380 limit in kilobytes will cause an ENOSPC error.
381 This is useful in memory constrained
382 environments, where a very large directory can
383 cause severe performance problems or even
384 provoke the Out Of Memory killer. (For example,
385 if there is only 512mb memory available, a 176mb
386 directory may seriously cramp the system's style.)
387
378i_version Enable 64-bit inode version support. This option is 388i_version Enable 64-bit inode version support. This option is
379 off by default. 389 off by default.
380 390
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index c3411d4ce2da..7c0841ecde6c 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1243,6 +1243,7 @@ struct ext4_sb_info {
1243 unsigned int s_mb_order2_reqs; 1243 unsigned int s_mb_order2_reqs;
1244 unsigned int s_mb_group_prealloc; 1244 unsigned int s_mb_group_prealloc;
1245 unsigned int s_max_writeback_mb_bump; 1245 unsigned int s_max_writeback_mb_bump;
1246 unsigned int s_max_dir_size_kb;
1246 /* where last allocation was done - for stream allocation */ 1247 /* where last allocation was done - for stream allocation */
1247 unsigned long s_mb_last_group; 1248 unsigned long s_mb_last_group;
1248 unsigned long s_mb_last_start; 1249 unsigned long s_mb_last_start;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2a42cc04466f..7450ff01c3c4 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -55,6 +55,13 @@ static struct buffer_head *ext4_append(handle_t *handle,
55{ 55{
56 struct buffer_head *bh; 56 struct buffer_head *bh;
57 57
58 if (unlikely(EXT4_SB(inode->i_sb)->s_max_dir_size_kb &&
59 ((inode->i_size >> 10) >=
60 EXT4_SB(inode->i_sb)->s_max_dir_size_kb))) {
61 *err = -ENOSPC;
62 return NULL;
63 }
64
58 *block = inode->i_size >> inode->i_sb->s_blocksize_bits; 65 *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
59 66
60 bh = ext4_bread(handle, inode, *block, 1, err); 67 bh = ext4_bread(handle, inode, *block, 1, err);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 598498904035..5a97e590692d 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1230,6 +1230,7 @@ enum {
1230 Opt_inode_readahead_blks, Opt_journal_ioprio, 1230 Opt_inode_readahead_blks, Opt_journal_ioprio,
1231 Opt_dioread_nolock, Opt_dioread_lock, 1231 Opt_dioread_nolock, Opt_dioread_lock,
1232 Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, 1232 Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
1233 Opt_max_dir_size_kb,
1233}; 1234};
1234 1235
1235static const match_table_t tokens = { 1236static const match_table_t tokens = {
@@ -1303,6 +1304,7 @@ static const match_table_t tokens = {
1303 {Opt_init_itable, "init_itable=%u"}, 1304 {Opt_init_itable, "init_itable=%u"},
1304 {Opt_init_itable, "init_itable"}, 1305 {Opt_init_itable, "init_itable"},
1305 {Opt_noinit_itable, "noinit_itable"}, 1306 {Opt_noinit_itable, "noinit_itable"},
1307 {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
1306 {Opt_removed, "check=none"}, /* mount option from ext2/3 */ 1308 {Opt_removed, "check=none"}, /* mount option from ext2/3 */
1307 {Opt_removed, "nocheck"}, /* mount option from ext2/3 */ 1309 {Opt_removed, "nocheck"}, /* mount option from ext2/3 */
1308 {Opt_removed, "reservation"}, /* mount option from ext2/3 */ 1310 {Opt_removed, "reservation"}, /* mount option from ext2/3 */
@@ -1483,6 +1485,7 @@ static const struct mount_opts {
1483 {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT}, 1485 {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT},
1484 {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT}, 1486 {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
1485 {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, 1487 {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
1488 {Opt_max_dir_size_kb, 0, MOPT_GTE0},
1486 {Opt_err, 0, 0} 1489 {Opt_err, 0, 0}
1487}; 1490};
1488 1491
@@ -1598,6 +1601,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
1598 if (!args->from) 1601 if (!args->from)
1599 arg = EXT4_DEF_LI_WAIT_MULT; 1602 arg = EXT4_DEF_LI_WAIT_MULT;
1600 sbi->s_li_wait_mult = arg; 1603 sbi->s_li_wait_mult = arg;
1604 } else if (token == Opt_max_dir_size_kb) {
1605 sbi->s_max_dir_size_kb = arg;
1601 } else if (token == Opt_stripe) { 1606 } else if (token == Opt_stripe) {
1602 sbi->s_stripe = arg; 1607 sbi->s_stripe = arg;
1603 } else if (m->flags & MOPT_DATAJ) { 1608 } else if (m->flags & MOPT_DATAJ) {
@@ -1829,6 +1834,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
1829 if (nodefs || (test_opt(sb, INIT_INODE_TABLE) && 1834 if (nodefs || (test_opt(sb, INIT_INODE_TABLE) &&
1830 (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT))) 1835 (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)))
1831 SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult); 1836 SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult);
1837 if (nodefs || sbi->s_max_dir_size_kb)
1838 SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb);
1832 1839
1833 ext4_show_quota_options(seq, sb); 1840 ext4_show_quota_options(seq, sb);
1834 return 0; 1841 return 0;