aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTahsin Erdogan <tahsin@google.com>2017-06-22 11:55:14 -0400
committerTheodore Ts'o <tytso@mit.edu>2017-06-22 11:55:14 -0400
commitcdb7ee4c632759075866bb8da5fb16b764e66ded (patch)
treed3c6d898e4f77c5dc8073d42b7262f4ee8663fac
parentb9fc761ea2d82e910e92f83d01bbbbe1f5e99bfc (diff)
ext4: add nombcache mount option
The main purpose of mb cache is to achieve deduplication in extended attributes. In use cases where opportunity for deduplication is unlikely, it only adds overhead. Add a mount option to explicitly turn off mb cache. Suggested-by: Andreas Dilger <adilger@dilger.ca> Signed-off-by: Tahsin Erdogan <tahsin@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/ext4/ext4.h1
-rw-r--r--fs/ext4/super.c34
-rw-r--r--fs/ext4/xattr.c52
3 files changed, 59 insertions, 28 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index fe92a63c86cb..68ddd24db9a2 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1114,6 +1114,7 @@ struct ext4_inode_info {
1114/* 1114/*
1115 * Mount flags set via mount options or defaults 1115 * Mount flags set via mount options or defaults
1116 */ 1116 */
1117#define EXT4_MOUNT_NO_MBCACHE 0x00001 /* Do not use mbcache */
1117#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */ 1118#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
1118#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ 1119#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
1119#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ 1120#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 5ac76e8d4013..1fec35bd4084 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1336,7 +1336,7 @@ enum {
1336 Opt_inode_readahead_blks, Opt_journal_ioprio, 1336 Opt_inode_readahead_blks, Opt_journal_ioprio,
1337 Opt_dioread_nolock, Opt_dioread_lock, 1337 Opt_dioread_nolock, Opt_dioread_lock,
1338 Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, 1338 Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
1339 Opt_max_dir_size_kb, Opt_nojournal_checksum, 1339 Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
1340}; 1340};
1341 1341
1342static const match_table_t tokens = { 1342static const match_table_t tokens = {
@@ -1419,6 +1419,8 @@ static const match_table_t tokens = {
1419 {Opt_noinit_itable, "noinit_itable"}, 1419 {Opt_noinit_itable, "noinit_itable"},
1420 {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, 1420 {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
1421 {Opt_test_dummy_encryption, "test_dummy_encryption"}, 1421 {Opt_test_dummy_encryption, "test_dummy_encryption"},
1422 {Opt_nombcache, "nombcache"},
1423 {Opt_nombcache, "no_mbcache"}, /* for backward compatibility */
1422 {Opt_removed, "check=none"}, /* mount option from ext2/3 */ 1424 {Opt_removed, "check=none"}, /* mount option from ext2/3 */
1423 {Opt_removed, "nocheck"}, /* mount option from ext2/3 */ 1425 {Opt_removed, "nocheck"}, /* mount option from ext2/3 */
1424 {Opt_removed, "reservation"}, /* mount option from ext2/3 */ 1426 {Opt_removed, "reservation"}, /* mount option from ext2/3 */
@@ -1626,6 +1628,7 @@ static const struct mount_opts {
1626 {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, 1628 {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
1627 {Opt_max_dir_size_kb, 0, MOPT_GTE0}, 1629 {Opt_max_dir_size_kb, 0, MOPT_GTE0},
1628 {Opt_test_dummy_encryption, 0, MOPT_GTE0}, 1630 {Opt_test_dummy_encryption, 0, MOPT_GTE0},
1631 {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
1629 {Opt_err, 0, 0} 1632 {Opt_err, 0, 0}
1630}; 1633};
1631 1634
@@ -4080,19 +4083,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
4080 sbi->s_journal->j_commit_callback = ext4_journal_commit_callback; 4083 sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
4081 4084
4082no_journal: 4085no_journal:
4083 sbi->s_ea_block_cache = ext4_xattr_create_cache(); 4086 if (!test_opt(sb, NO_MBCACHE)) {
4084 if (!sbi->s_ea_block_cache) { 4087 sbi->s_ea_block_cache = ext4_xattr_create_cache();
4085 ext4_msg(sb, KERN_ERR, "Failed to create ea_block_cache"); 4088 if (!sbi->s_ea_block_cache) {
4086 goto failed_mount_wq;
4087 }
4088
4089 if (ext4_has_feature_ea_inode(sb)) {
4090 sbi->s_ea_inode_cache = ext4_xattr_create_cache();
4091 if (!sbi->s_ea_inode_cache) {
4092 ext4_msg(sb, KERN_ERR, 4089 ext4_msg(sb, KERN_ERR,
4093 "Failed to create ea_inode_cache"); 4090 "Failed to create ea_block_cache");
4094 goto failed_mount_wq; 4091 goto failed_mount_wq;
4095 } 4092 }
4093
4094 if (ext4_has_feature_ea_inode(sb)) {
4095 sbi->s_ea_inode_cache = ext4_xattr_create_cache();
4096 if (!sbi->s_ea_inode_cache) {
4097 ext4_msg(sb, KERN_ERR,
4098 "Failed to create ea_inode_cache");
4099 goto failed_mount_wq;
4100 }
4101 }
4096 } 4102 }
4097 4103
4098 if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) && 4104 if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) &&
@@ -4989,6 +4995,12 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
4989 } 4995 }
4990 } 4996 }
4991 4997
4998 if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_NO_MBCACHE) {
4999 ext4_msg(sb, KERN_ERR, "can't enable nombcache during remount");
5000 err = -EINVAL;
5001 goto restore_opts;
5002 }
5003
4992 if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_DAX) { 5004 if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_DAX) {
4993 ext4_msg(sb, KERN_WARNING, "warning: refusing change of " 5005 ext4_msg(sb, KERN_WARNING, "warning: refusing change of "
4994 "dax flag with busy inodes while remounting"); 5006 "dax flag with busy inodes while remounting");
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index a5ad0ccdd1cb..34fa37e7744c 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -991,10 +991,13 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
991 set_nlink(ea_inode, 1); 991 set_nlink(ea_inode, 1);
992 ext4_orphan_del(handle, ea_inode); 992 ext4_orphan_del(handle, ea_inode);
993 993
994 hash = ext4_xattr_inode_get_hash(ea_inode); 994 if (ea_inode_cache) {
995 mb_cache_entry_create(ea_inode_cache, GFP_NOFS, hash, 995 hash = ext4_xattr_inode_get_hash(ea_inode);
996 ea_inode->i_ino, 996 mb_cache_entry_create(ea_inode_cache,
997 true /* reusable */); 997 GFP_NOFS, hash,
998 ea_inode->i_ino,
999 true /* reusable */);
1000 }
998 } 1001 }
999 } else { 1002 } else {
1000 WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld", 1003 WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld",
@@ -1008,9 +1011,11 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
1008 clear_nlink(ea_inode); 1011 clear_nlink(ea_inode);
1009 ext4_orphan_add(handle, ea_inode); 1012 ext4_orphan_add(handle, ea_inode);
1010 1013
1011 hash = ext4_xattr_inode_get_hash(ea_inode); 1014 if (ea_inode_cache) {
1012 mb_cache_entry_delete(ea_inode_cache, hash, 1015 hash = ext4_xattr_inode_get_hash(ea_inode);
1013 ea_inode->i_ino); 1016 mb_cache_entry_delete(ea_inode_cache, hash,
1017 ea_inode->i_ino);
1018 }
1014 } 1019 }
1015 } 1020 }
1016 1021
@@ -1194,7 +1199,9 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
1194 * This must happen under buffer lock for 1199 * This must happen under buffer lock for
1195 * ext4_xattr_block_set() to reliably detect freed block 1200 * ext4_xattr_block_set() to reliably detect freed block
1196 */ 1201 */
1197 mb_cache_entry_delete(ea_block_cache, hash, bh->b_blocknr); 1202 if (ea_block_cache)
1203 mb_cache_entry_delete(ea_block_cache, hash,
1204 bh->b_blocknr);
1198 get_bh(bh); 1205 get_bh(bh);
1199 unlock_buffer(bh); 1206 unlock_buffer(bh);
1200 1207
@@ -1214,11 +1221,13 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
1214 if (ref == EXT4_XATTR_REFCOUNT_MAX - 1) { 1221 if (ref == EXT4_XATTR_REFCOUNT_MAX - 1) {
1215 struct mb_cache_entry *ce; 1222 struct mb_cache_entry *ce;
1216 1223
1217 ce = mb_cache_entry_get(ea_block_cache, hash, 1224 if (ea_block_cache) {
1218 bh->b_blocknr); 1225 ce = mb_cache_entry_get(ea_block_cache, hash,
1219 if (ce) { 1226 bh->b_blocknr);
1220 ce->e_reusable = 1; 1227 if (ce) {
1221 mb_cache_entry_put(ea_block_cache, ce); 1228 ce->e_reusable = 1;
1229 mb_cache_entry_put(ea_block_cache, ce);
1230 }
1222 } 1231 }
1223 } 1232 }
1224 1233
@@ -1395,6 +1404,9 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value,
1395 struct mb_cache *ea_inode_cache = EA_INODE_CACHE(inode); 1404 struct mb_cache *ea_inode_cache = EA_INODE_CACHE(inode);
1396 void *ea_data; 1405 void *ea_data;
1397 1406
1407 if (!ea_inode_cache)
1408 return NULL;
1409
1398 ce = mb_cache_entry_find_first(ea_inode_cache, hash); 1410 ce = mb_cache_entry_find_first(ea_inode_cache, hash);
1399 if (!ce) 1411 if (!ce)
1400 return NULL; 1412 return NULL;
@@ -1465,8 +1477,9 @@ static int ext4_xattr_inode_lookup_create(handle_t *handle, struct inode *inode,
1465 return err; 1477 return err;
1466 } 1478 }
1467 1479
1468 mb_cache_entry_create(EA_INODE_CACHE(inode), GFP_NOFS, hash, 1480 if (EA_INODE_CACHE(inode))
1469 ea_inode->i_ino, true /* reusable */); 1481 mb_cache_entry_create(EA_INODE_CACHE(inode), GFP_NOFS, hash,
1482 ea_inode->i_ino, true /* reusable */);
1470 1483
1471 *ret_inode = ea_inode; 1484 *ret_inode = ea_inode;
1472 return 0; 1485 return 0;
@@ -1793,8 +1806,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
1793 * ext4_xattr_block_set() to reliably detect modified 1806 * ext4_xattr_block_set() to reliably detect modified
1794 * block 1807 * block
1795 */ 1808 */
1796 mb_cache_entry_delete(ea_block_cache, hash, 1809 if (ea_block_cache)
1797 bs->bh->b_blocknr); 1810 mb_cache_entry_delete(ea_block_cache, hash,
1811 bs->bh->b_blocknr);
1798 ea_bdebug(bs->bh, "modifying in-place"); 1812 ea_bdebug(bs->bh, "modifying in-place");
1799 error = ext4_xattr_set_entry(i, s, handle, inode, 1813 error = ext4_xattr_set_entry(i, s, handle, inode,
1800 true /* is_block */); 1814 true /* is_block */);
@@ -2883,6 +2897,8 @@ ext4_xattr_block_cache_insert(struct mb_cache *ea_block_cache,
2883 EXT4_XATTR_REFCOUNT_MAX; 2897 EXT4_XATTR_REFCOUNT_MAX;
2884 int error; 2898 int error;
2885 2899
2900 if (!ea_block_cache)
2901 return;
2886 error = mb_cache_entry_create(ea_block_cache, GFP_NOFS, hash, 2902 error = mb_cache_entry_create(ea_block_cache, GFP_NOFS, hash,
2887 bh->b_blocknr, reusable); 2903 bh->b_blocknr, reusable);
2888 if (error) { 2904 if (error) {
@@ -2949,6 +2965,8 @@ ext4_xattr_block_cache_find(struct inode *inode,
2949 struct mb_cache_entry *ce; 2965 struct mb_cache_entry *ce;
2950 struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 2966 struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode);
2951 2967
2968 if (!ea_block_cache)
2969 return NULL;
2952 if (!header->h_hash) 2970 if (!header->h_hash)
2953 return NULL; /* never share */ 2971 return NULL; /* never share */
2954 ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); 2972 ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);