Commit 1b364dc9 authored by Andreas Dilger's avatar Andreas Dilger Committed by Sasha Levin

xattr: Option to disable meta-data block cache

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: default avatarPhilipp Hahn <hahn@univention.de>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
parent 9a66bc6e
...@@ -1008,6 +1008,7 @@ struct ext4_inode_info { ...@@ -1008,6 +1008,7 @@ struct ext4_inode_info {
/* /*
* Mount flags set via mount options or defaults * 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_GRPID 0x00004 /* Create files with directory's group */
#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ #define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ #define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
......
...@@ -1144,6 +1144,7 @@ enum { ...@@ -1144,6 +1144,7 @@ enum {
Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
Opt_inode_readahead_blks, Opt_journal_ioprio, Opt_inode_readahead_blks, Opt_journal_ioprio,
Opt_dioread_nolock, Opt_dioread_lock, Opt_dioread_nolock, Opt_dioread_lock,
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, Opt_nojournal_checksum, Opt_max_dir_size_kb, Opt_nojournal_checksum,
}; };
...@@ -1222,6 +1223,7 @@ static const match_table_t tokens = { ...@@ -1222,6 +1223,7 @@ static const match_table_t tokens = {
{Opt_discard, "discard"}, {Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"}, {Opt_nodiscard, "nodiscard"},
{Opt_init_itable, "init_itable=%u"}, {Opt_init_itable, "init_itable=%u"},
{Opt_no_mbcache, "no_mbcache"},
{Opt_init_itable, "init_itable"}, {Opt_init_itable, "init_itable"},
{Opt_noinit_itable, "noinit_itable"}, {Opt_noinit_itable, "noinit_itable"},
{Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
...@@ -1385,6 +1387,7 @@ static const struct mount_opts { ...@@ -1385,6 +1387,7 @@ static const struct mount_opts {
{Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET}, {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_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR},
{Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, 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_commit, 0, MOPT_GTE0},
{Opt_max_batch_time, 0, MOPT_GTE0}, {Opt_max_batch_time, 0, MOPT_GTE0},
{Opt_min_batch_time, 0, MOPT_GTE0}, {Opt_min_batch_time, 0, MOPT_GTE0},
......
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
# define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__) # define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif #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 *, static struct buffer_head *ext4_xattr_cache_find(struct inode *,
struct ext4_xattr_header *, struct ext4_xattr_header *,
struct mb_cache_entry **); struct mb_cache_entry **);
...@@ -278,7 +278,6 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, ...@@ -278,7 +278,6 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
struct ext4_xattr_entry *entry; struct ext4_xattr_entry *entry;
size_t size; size_t size;
int error; int error;
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
name_index, name, buffer, (long)buffer_size); name_index, name, buffer, (long)buffer_size);
...@@ -300,7 +299,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, ...@@ -300,7 +299,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
error = -EIO; error = -EIO;
goto cleanup; goto cleanup;
} }
ext4_xattr_cache_insert(ext4_mb_cache, bh); ext4_xattr_cache_insert(inode, bh);
entry = BFIRST(bh); entry = BFIRST(bh);
error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1); error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);
if (error == -EIO) if (error == -EIO)
...@@ -426,7 +425,6 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) ...@@ -426,7 +425,6 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
int error; int error;
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
ea_idebug(inode, "buffer=%p, buffer_size=%ld", ea_idebug(inode, "buffer=%p, buffer_size=%ld",
buffer, (long)buffer_size); buffer, (long)buffer_size);
...@@ -448,7 +446,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) ...@@ -448,7 +446,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
error = -EIO; error = -EIO;
goto cleanup; 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); error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
cleanup: cleanup:
...@@ -547,7 +545,8 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, ...@@ -547,7 +545,8 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
int error = 0; int error = 0;
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); 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"); BUFFER_TRACE(bh, "get_write_access");
error = ext4_journal_get_write_access(handle, bh); error = ext4_journal_get_write_access(handle, bh);
if (error) if (error)
...@@ -788,8 +787,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -788,8 +787,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
if (i->value && i->value_len > sb->s_blocksize) if (i->value && i->value_len > sb->s_blocksize)
return -ENOSPC; return -ENOSPC;
if (s->base) { if (s->base) {
ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev, if (!test_opt(inode->i_sb, NO_MBCACHE))
bs->bh->b_blocknr); ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
bs->bh->b_blocknr);
BUFFER_TRACE(bs->bh, "get_write_access"); BUFFER_TRACE(bs->bh, "get_write_access");
error = ext4_journal_get_write_access(handle, bs->bh); error = ext4_journal_get_write_access(handle, bs->bh);
if (error) if (error)
...@@ -807,7 +807,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -807,7 +807,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
if (!IS_LAST_ENTRY(s->first)) if (!IS_LAST_ENTRY(s->first))
ext4_xattr_rehash(header(s->base), ext4_xattr_rehash(header(s->base),
s->here); s->here);
ext4_xattr_cache_insert(ext4_mb_cache, ext4_xattr_cache_insert(inode,
bs->bh); bs->bh);
} }
unlock_buffer(bs->bh); unlock_buffer(bs->bh);
...@@ -892,7 +892,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -892,7 +892,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
if (error) if (error)
goto cleanup_dquot; goto cleanup_dquot;
} }
mb_cache_entry_release(ce); if (ce)
mb_cache_entry_release(ce);
ce = NULL; ce = NULL;
} else if (bs->bh && s->base == bs->bh->b_data) { } else if (bs->bh && s->base == bs->bh->b_data) {
/* We were modifying this block in-place. */ /* We were modifying this block in-place. */
...@@ -939,7 +940,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -939,7 +940,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
memcpy(new_bh->b_data, s->base, new_bh->b_size); memcpy(new_bh->b_data, s->base, new_bh->b_size);
set_buffer_uptodate(new_bh); set_buffer_uptodate(new_bh);
unlock_buffer(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, error = ext4_handle_dirty_xattr_block(handle,
inode, new_bh); inode, new_bh);
if (error) if (error)
...@@ -1529,12 +1530,17 @@ ext4_xattr_put_super(struct super_block *sb) ...@@ -1529,12 +1530,17 @@ ext4_xattr_put_super(struct super_block *sb)
* Returns 0, or a negative error number on failure. * Returns 0, or a negative error number on failure.
*/ */
static void 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); __u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
struct mb_cache_entry *ce; struct mb_cache_entry *ce;
int error; int error;
if (test_opt(sb, NO_MBCACHE))
return;
ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS); ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS);
if (!ce) { if (!ce) {
ea_bdebug(bh, "out of memory"); ea_bdebug(bh, "out of memory");
...@@ -1609,6 +1615,8 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header, ...@@ -1609,6 +1615,8 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
struct mb_cache_entry *ce; struct mb_cache_entry *ce;
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); 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) if (!header->h_hash)
return NULL; /* never share */ return NULL; /* never share */
ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment