]> git.hungrycats.org Git - linux/commitdiff
xattr: Option to disable meta-data block cache
authorAndreas Dilger <andreas.dilger@intel.com>
Wed, 14 Dec 2016 12:24:44 +0000 (13:24 +0100)
committerSasha Levin <alexander.levin@verizon.com>
Fri, 23 Dec 2016 13:56:34 +0000 (08:56 -0500)
mbcache provides absolutely no value for Lustre xattrs (because
they are unique and cannot be shared between files) and as we can
see it has a noticable overhead in some cases. In the past there
was a CONFIG_MBCACHE option that would allow it to be disabled,
but this was removed in newer kernels, so we will need to patch
ldiskfs to fix this.

References: <https://bugzilla.kernel.org/show_bug.cgi?id=107301>
References: <https://git.hpdd.intel.com/fs/lustre-release.git/blob_plain/HEAD:/ldiskfs/kernel_patches/patches/rhel7/ext4-disable-mb-cache.patch>
References: CVE-2015-8952

On 13.12.2016 at 15:58 Ben Hutchings wrote:
> I decided not to apply this as it's a userland ABI extension that we
> would then need to carry indefinitely.

Signed-off-by: Philipp Hahn <hahn@univention.de>
Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
fs/ext4/ext4.h
fs/ext4/super.c
fs/ext4/xattr.c

index 15213a567301d12f2dbb1a8641a20f417c52206d..145d6ba4117d299cb18df5ca6a7f4cf98076f10d 100644 (file)
@@ -1008,6 +1008,7 @@ struct ext4_inode_info {
 /*
  * Mount flags set via mount options or defaults
  */
+#define EXT4_MOUNT_NO_MBCACHE          0x00001 /* Disable mbcache */
 #define EXT4_MOUNT_GRPID               0x00004 /* Create files with directory's group */
 #define EXT4_MOUNT_DEBUG               0x00008 /* Some debugging messages */
 #define EXT4_MOUNT_ERRORS_CONT         0x00010 /* Continue on errors */
index afb3eb3e8b0f8b06237ca56a128d5c7aadf55463..4723d8b02747c77bbf08542500127e668bd8a647 100644 (file)
@@ -1144,6 +1144,7 @@ enum {
        Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
        Opt_inode_readahead_blks, Opt_journal_ioprio,
        Opt_dioread_nolock, Opt_dioread_lock,
+       Opt_no_mbcache,
        Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
        Opt_max_dir_size_kb, Opt_nojournal_checksum,
 };
@@ -1222,6 +1223,7 @@ static const match_table_t tokens = {
        {Opt_discard, "discard"},
        {Opt_nodiscard, "nodiscard"},
        {Opt_init_itable, "init_itable=%u"},
+       {Opt_no_mbcache, "no_mbcache"},
        {Opt_init_itable, "init_itable"},
        {Opt_noinit_itable, "noinit_itable"},
        {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
@@ -1385,6 +1387,7 @@ static const struct mount_opts {
        {Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET},
        {Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR},
        {Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR},
+       {Opt_no_mbcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
        {Opt_commit, 0, MOPT_GTE0},
        {Opt_max_batch_time, 0, MOPT_GTE0},
        {Opt_min_batch_time, 0, MOPT_GTE0},
index 16e28c08d1e8cf54eb0c05d15611a6416185b119..cdc26e54400f039e626edd77ada6120833fb9a02 100644 (file)
@@ -80,7 +80,7 @@
 # define ea_bdebug(bh, fmt, ...)       no_printk(fmt, ##__VA_ARGS__)
 #endif
 
-static void ext4_xattr_cache_insert(struct mb_cache *, struct buffer_head *);
+static void ext4_xattr_cache_insert(struct inode *, struct buffer_head *);
 static struct buffer_head *ext4_xattr_cache_find(struct inode *,
                                                 struct ext4_xattr_header *,
                                                 struct mb_cache_entry **);
@@ -278,7 +278,6 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
        struct ext4_xattr_entry *entry;
        size_t size;
        int error;
-       struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
        ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
                  name_index, name, buffer, (long)buffer_size);
@@ -300,7 +299,7 @@ bad_block:
                error = -EIO;
                goto cleanup;
        }
-       ext4_xattr_cache_insert(ext4_mb_cache, bh);
+       ext4_xattr_cache_insert(inode, bh);
        entry = BFIRST(bh);
        error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);
        if (error == -EIO)
@@ -426,7 +425,6 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
        struct inode *inode = d_inode(dentry);
        struct buffer_head *bh = NULL;
        int error;
-       struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
        ea_idebug(inode, "buffer=%p, buffer_size=%ld",
                  buffer, (long)buffer_size);
@@ -448,7 +446,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
                error = -EIO;
                goto cleanup;
        }
-       ext4_xattr_cache_insert(ext4_mb_cache, bh);
+       ext4_xattr_cache_insert(inode, bh);
        error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
 
 cleanup:
@@ -547,7 +545,8 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
        int error = 0;
        struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
-       ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
+       if (!test_opt(inode->i_sb, NO_MBCACHE))
+               ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
        BUFFER_TRACE(bh, "get_write_access");
        error = ext4_journal_get_write_access(handle, bh);
        if (error)
@@ -788,8 +787,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
        if (i->value && i->value_len > sb->s_blocksize)
                return -ENOSPC;
        if (s->base) {
-               ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
-                                       bs->bh->b_blocknr);
+               if (!test_opt(inode->i_sb, NO_MBCACHE))
+                       ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
+                                               bs->bh->b_blocknr);
                BUFFER_TRACE(bs->bh, "get_write_access");
                error = ext4_journal_get_write_access(handle, bs->bh);
                if (error)
@@ -807,7 +807,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                                if (!IS_LAST_ENTRY(s->first))
                                        ext4_xattr_rehash(header(s->base),
                                                          s->here);
-                               ext4_xattr_cache_insert(ext4_mb_cache,
+                               ext4_xattr_cache_insert(inode,
                                        bs->bh);
                        }
                        unlock_buffer(bs->bh);
@@ -892,7 +892,8 @@ inserted:
                                if (error)
                                        goto cleanup_dquot;
                        }
-                       mb_cache_entry_release(ce);
+                       if (ce)
+                               mb_cache_entry_release(ce);
                        ce = NULL;
                } else if (bs->bh && s->base == bs->bh->b_data) {
                        /* We were modifying this block in-place. */
@@ -939,7 +940,7 @@ getblk_failed:
                        memcpy(new_bh->b_data, s->base, new_bh->b_size);
                        set_buffer_uptodate(new_bh);
                        unlock_buffer(new_bh);
-                       ext4_xattr_cache_insert(ext4_mb_cache, new_bh);
+                       ext4_xattr_cache_insert(inode, new_bh);
                        error = ext4_handle_dirty_xattr_block(handle,
                                                              inode, new_bh);
                        if (error)
@@ -1529,12 +1530,17 @@ ext4_xattr_put_super(struct super_block *sb)
  * Returns 0, or a negative error number on failure.
  */
 static void
-ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh)
+ext4_xattr_cache_insert(struct inode *inode, struct buffer_head *bh)
 {
+       struct super_block *sb = inode->i_sb;
+       struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
        __u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
        struct mb_cache_entry *ce;
        int error;
 
+       if (test_opt(sb, NO_MBCACHE))
+               return;
+
        ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS);
        if (!ce) {
                ea_bdebug(bh, "out of memory");
@@ -1609,6 +1615,8 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
        struct mb_cache_entry *ce;
        struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
+       if (test_opt(inode->i_sb, NO_MBCACHE))
+               return NULL;
        if (!header->h_hash)
                return NULL;  /* never share */
        ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);