diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-04-25 15:21:06 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-01-18 21:38:27 -0900 |
commit | 70beb52ed9be1d89a7c177330ad57458f12fdedb (patch) | |
tree | 6b840c78fb1df9729f720cd1654b7d53e887039c | |
parent | 687567abd7eb3bbc5b6b081fb617f7fd68e90664 (diff) |
bcachefs: selectable dirent/xattr hash type
-rw-r--r-- | drivers/md/bcache/Kconfig | 1 | ||||
-rw-r--r-- | drivers/md/bcache/acl.c | 5 | ||||
-rw-r--r-- | drivers/md/bcache/bcache.h | 2 | ||||
-rw-r--r-- | drivers/md/bcache/dirent.c | 120 | ||||
-rw-r--r-- | drivers/md/bcache/dirent.h | 13 | ||||
-rw-r--r-- | drivers/md/bcache/fs.c | 46 | ||||
-rw-r--r-- | drivers/md/bcache/fs.h | 3 | ||||
-rw-r--r-- | drivers/md/bcache/inode.c | 8 | ||||
-rw-r--r-- | drivers/md/bcache/str_hash.h | 84 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 4 | ||||
-rw-r--r-- | drivers/md/bcache/xattr.c | 77 | ||||
-rw-r--r-- | drivers/md/bcache/xattr.h | 2 | ||||
-rw-r--r-- | include/uapi/linux/bcache.h | 64 |
13 files changed, 241 insertions, 188 deletions
diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig index a221dbff75b6..5532b1f36a36 100644 --- a/drivers/md/bcache/Kconfig +++ b/drivers/md/bcache/Kconfig @@ -2,6 +2,7 @@ config BCACHE tristate "Block device as cache" select LIBCRC32C + select CRYPTO_SHA1 select FS_POSIX_ACL select LZ4_COMPRESS select LZ4_DECOMPRESS diff --git a/drivers/md/bcache/acl.c b/drivers/md/bcache/acl.c index 35f11b392300..aaec01208042 100644 --- a/drivers/md/bcache/acl.c +++ b/drivers/md/bcache/acl.c @@ -133,7 +133,6 @@ fail: struct posix_acl *bch_get_acl(struct inode *inode, int type) { - struct cache_set *c = inode->i_sb->s_fs_info; int name_index; char *value = NULL; struct posix_acl *acl; @@ -149,12 +148,12 @@ struct posix_acl *bch_get_acl(struct inode *inode, int type) default: BUG(); } - ret = bch_xattr_get(c, inode->i_ino, "", NULL, 0, name_index); + ret = bch_xattr_get(inode, "", NULL, 0, name_index); if (ret > 0) { value = kmalloc(ret, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); - ret = bch_xattr_get(c, inode->i_ino, "", value, + ret = bch_xattr_get(inode, "", value, ret, name_index); } if (ret > 0) diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index eb29c1e2792f..0e0350c06133 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -529,6 +529,8 @@ struct cache_set { u8 meta_replicas_have; u8 data_replicas_have; + + u8 str_hash_type; } sb; struct cache_sb disk_sb; diff --git a/drivers/md/bcache/dirent.c b/drivers/md/bcache/dirent.c index 44c2f34a6658..4c8b2cdb2d8e 100644 --- a/drivers/md/bcache/dirent.c +++ b/drivers/md/bcache/dirent.c @@ -4,61 +4,27 @@ #include "btree_update.h" #include "extents.h" #include "dirent.h" +#include "fs.h" #include "keylist.h" -#include "siphash.h" +#include "str_hash.h" -#include "linux/crc32c.h" -#include "linux/cryptohash.h" - -#if 0 -static u64 bch_dirent_hash(const struct qstr *name) -{ - union { - u32 b[SHA_DIGEST_WORDS]; - u64 ret; - } digest; - - unsigned done = 0; - - sha_init(digest.b); - - while (done < name->len) { - u32 workspace[SHA_WORKSPACE_WORDS]; - u8 message[SHA_MESSAGE_BYTES]; - unsigned bytes = min_t(unsigned, name->len - done, - SHA_MESSAGE_BYTES); - - memcpy(message, name->name + done, bytes); - memset(message + bytes, 0, SHA_MESSAGE_BYTES - bytes); - sha_transform(digest.b, message, workspace); - done += bytes; - } - - /* [0,2) reserved for dots */ - - return (digest.ret >= 2 ? digest.ret : 2) & S64_MAX; -} - -static const SIPHASH_KEY bch_siphash_key; - -static u64 bch_dirent_hash(const struct qstr *name) +static struct bpos bch_dirent_pos(struct bch_inode_info *ei, + const struct qstr *name) { - u64 hash = SipHash24(&bch_siphash_key, - name->name, name->len) >> 1; + struct bch_str_hash_ctx ctx; + u64 hash; - /* [0,2) reserved for dots */ + bch_str_hash_init(&ctx, ei->str_hash_type); - return (hash >= 2 ? hash : 2); -} -#endif + bch_str_hash_update(&ctx, ei->str_hash_type, + &ei->str_hash_seed, sizeof(ei->str_hash_seed)); + bch_str_hash_update(&ctx, ei->str_hash_type, name->name, name->len); -static u64 bch_dirent_hash(const struct qstr *name) -{ - u64 hash = crc32c(0, name->name, name->len); + hash = bch_str_hash_end(&ctx, ei->str_hash_type); /* [0,2) reserved for dots */ - return (hash >= 2 ? hash : 2); + return POS(ei->vfs_inode.i_ino, hash >= 2 ? hash : 2); } static unsigned dirent_name_bytes(struct bkey_s_c_dirent d) @@ -217,10 +183,11 @@ static struct bkey_s_c __dirent_find_hole(struct btree_iter *iter, return (struct bkey_s_c) { .k = ERR_PTR(-ENOSPC) }; } -int bch_dirent_create(struct cache_set *c, u64 dir_inum, u8 type, - const struct qstr *name, u64 dst_inum, - u64 *journal_seq) +int bch_dirent_create(struct inode *dir, u8 type, + const struct qstr *name, u64 dst_inum) { + struct cache_set *c = dir->i_sb->s_fs_info; + struct bch_inode_info *ei = to_bch_ei(dir); struct btree_iter iter; struct bkey_s_c k; struct bkey_i_dirent *dirent; @@ -231,10 +198,10 @@ int bch_dirent_create(struct cache_set *c, u64 dir_inum, u8 type, return -ENOMEM; bch_btree_iter_init_intent(&iter, c, BTREE_ID_DIRENTS, - POS(dir_inum, bch_dirent_hash(name))); + bch_dirent_pos(ei, name)); do { - k = __dirent_find_hole(&iter, dir_inum, name); + k = __dirent_find_hole(&iter, dir->i_ino, name); if (IS_ERR(k.k)) { ret = bch_btree_iter_unlock(&iter) ?: PTR_ERR(k.k); break; @@ -243,7 +210,7 @@ int bch_dirent_create(struct cache_set *c, u64 dir_inum, u8 type, dirent->k.p = k.k->p; ret = bch_btree_insert_at(&iter, &keylist_single(&dirent->k_i), - NULL, journal_seq, + NULL, &ei->journal_seq, BTREE_INSERT_ATOMIC); /* * XXX: if we ever cleanup whiteouts, we may need to rewind @@ -258,10 +225,12 @@ int bch_dirent_create(struct cache_set *c, u64 dir_inum, u8 type, } int bch_dirent_rename(struct cache_set *c, - u64 src_dir, const struct qstr *src_name, - u64 dst_dir, const struct qstr *dst_name, + struct inode *src_dir, const struct qstr *src_name, + struct inode *dst_dir, const struct qstr *dst_name, u64 *journal_seq, enum bch_rename_mode mode) { + struct bch_inode_info *src_ei = to_bch_ei(src_dir); + struct bch_inode_info *dst_ei = to_bch_ei(dst_dir); struct btree_iter src_iter; struct btree_iter dst_iter; struct bkey_s_c old_src, old_dst; @@ -283,9 +252,9 @@ int bch_dirent_rename(struct cache_set *c, goto out; bch_btree_iter_init_intent(&src_iter, c, BTREE_ID_DIRENTS, - POS(src_dir, bch_dirent_hash(src_name))); + bch_dirent_pos(src_ei, src_name)); bch_btree_iter_init_intent(&dst_iter, c, BTREE_ID_DIRENTS, - POS(dst_dir, bch_dirent_hash(dst_name))); + bch_dirent_pos(dst_ei, dst_name)); bch_btree_iter_link(&src_iter, &dst_iter); do { @@ -304,17 +273,23 @@ int bch_dirent_rename(struct cache_set *c, * lock ordering. */ if (bkey_cmp(src_iter.pos, dst_iter.pos) < 0) { - old_src = __dirent_find(&src_iter, src_dir, src_name); + old_src = __dirent_find(&src_iter, src_dir->i_ino, + src_name); old_dst = mode == BCH_RENAME - ? __dirent_find_hole(&dst_iter, dst_dir, dst_name) - : __dirent_find(&dst_iter, dst_dir, dst_name); + ? __dirent_find_hole(&dst_iter, dst_dir->i_ino, + dst_name) + : __dirent_find(&dst_iter, dst_dir->i_ino, + dst_name); } else { old_dst = mode == BCH_RENAME - ? __dirent_find_hole(&dst_iter, dst_dir, dst_name) - : __dirent_find(&dst_iter, dst_dir, dst_name); + ? __dirent_find_hole(&dst_iter, dst_dir->i_ino, + dst_name) + : __dirent_find(&dst_iter, dst_dir->i_ino, + dst_name); - old_src = __dirent_find(&src_iter, src_dir, src_name); + old_src = __dirent_find(&src_iter, src_dir->i_ino, + src_name); } if (IS_ERR(old_src.k)) { @@ -368,20 +343,20 @@ err: goto out; } -int bch_dirent_delete(struct cache_set *c, u64 dir_inum, - const struct qstr *name, - u64 *journal_seq) +int bch_dirent_delete(struct inode *dir, const struct qstr *name) { + struct cache_set *c = dir->i_sb->s_fs_info; + struct bch_inode_info *ei = to_bch_ei(dir); struct btree_iter iter; struct bkey_s_c k; struct bkey_i delete; int ret = -ENOENT; bch_btree_iter_init_intent(&iter, c, BTREE_ID_DIRENTS, - POS(dir_inum, bch_dirent_hash(name))); + bch_dirent_pos(ei, name)); do { - k = __dirent_find(&iter, dir_inum, name); + k = __dirent_find(&iter, dir->i_ino, name); if (IS_ERR(k.k)) return bch_btree_iter_unlock(&iter) ?: PTR_ERR(k.k); @@ -391,7 +366,7 @@ int bch_dirent_delete(struct cache_set *c, u64 dir_inum, ret = bch_btree_insert_at(&iter, &keylist_single(&delete), - NULL, journal_seq, + NULL, &ei->journal_seq, BTREE_INSERT_NOFAIL| BTREE_INSERT_ATOMIC); /* @@ -405,17 +380,18 @@ int bch_dirent_delete(struct cache_set *c, u64 dir_inum, return ret; } -u64 bch_dirent_lookup(struct cache_set *c, u64 dir_inum, - const struct qstr *name) +u64 bch_dirent_lookup(struct inode *dir, const struct qstr *name) { + struct cache_set *c = dir->i_sb->s_fs_info; + struct bch_inode_info *ei = to_bch_ei(dir); struct btree_iter iter; struct bkey_s_c k; u64 inum = 0; bch_btree_iter_init(&iter, c, BTREE_ID_DIRENTS, - POS(dir_inum, bch_dirent_hash(name))); + bch_dirent_pos(ei, name)); - k = __dirent_find(&iter, dir_inum, name); + k = __dirent_find(&iter, dir->i_ino, name); if (!IS_ERR(k.k)) inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum); diff --git a/drivers/md/bcache/dirent.h b/drivers/md/bcache/dirent.h index dee59955efd9..63b4aa07f432 100644 --- a/drivers/md/bcache/dirent.h +++ b/drivers/md/bcache/dirent.h @@ -9,9 +9,8 @@ struct file; struct dir_context; struct cache_set; -int bch_dirent_create(struct cache_set *, u64, u8, const struct qstr *, - u64, u64 *); -int bch_dirent_delete(struct cache_set *, u64, const struct qstr *, u64 *); +int bch_dirent_create(struct inode *, u8, const struct qstr *, u64); +int bch_dirent_delete(struct inode *, const struct qstr *); enum bch_rename_mode { BCH_RENAME, @@ -19,10 +18,12 @@ enum bch_rename_mode { BCH_RENAME_EXCHANGE, }; -int bch_dirent_rename(struct cache_set *, u64, const struct qstr *, u64, - const struct qstr *, u64 *, enum bch_rename_mode); +int bch_dirent_rename(struct cache_set *, + struct inode *, const struct qstr *, + struct inode *, const struct qstr *, + u64 *, enum bch_rename_mode); -u64 bch_dirent_lookup(struct cache_set *, u64, const struct qstr *); +u64 bch_dirent_lookup(struct inode *, const struct qstr *); int bch_empty_dir(struct cache_set *, u64); int bch_readdir(struct file *, struct dir_context *); diff --git a/drivers/md/bcache/fs.c b/drivers/md/bcache/fs.c index 2b51a7c86b46..ad00dbbb8a5f 100644 --- a/drivers/md/bcache/fs.c +++ b/drivers/md/bcache/fs.c @@ -19,6 +19,7 @@ #include <linux/compat.h> #include <linux/module.h> #include <linux/mount.h> +#include <linux/random.h> #include <linux/statfs.h> #include <linux/xattr.h> @@ -228,6 +229,9 @@ static struct inode *bch_vfs_inode_create(struct cache_set *c, bi->i_ctime = cpu_to_le64(now); bi->i_nlink = cpu_to_le32(S_ISDIR(mode) ? 2 : 1); + get_random_bytes(&bi->i_hash_seed, sizeof(bi->i_hash_seed)); + SET_INODE_STR_HASH_TYPE(bi, c->sb.str_hash_type); + ret = bch_inode_create(c, &bkey_inode.k_i, BLOCKDEV_INODE_MAX, 0, &c->unused_inode_hint); @@ -271,11 +275,10 @@ static int bch_vfs_dirent_create(struct cache_set *c, struct inode *dir, u8 type, const struct qstr *name, struct inode *dst) { - struct bch_inode_info *ei = to_bch_ei(dst); int ret; - ret = bch_dirent_create(c, dir->i_ino, type, name, - dst->i_ino, &ei->journal_seq); + ret = bch_dirent_create(dir, type, name, + dst->i_ino); if (unlikely(ret)) return ret; @@ -287,14 +290,18 @@ static int bch_vfs_dirent_create(struct cache_set *c, struct inode *dir, static int __bch_create(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { + struct bch_inode_info *dir_ei = to_bch_ei(dir); struct cache_set *c = dir->i_sb->s_fs_info; struct inode *inode; + struct bch_inode_info *ei; int ret; inode = bch_vfs_inode_create(c, dir, mode, rdev); if (unlikely(IS_ERR(inode))) return PTR_ERR(inode); + ei = to_bch_ei(inode); + ret = bch_vfs_dirent_create(c, dir, mode_to_type(mode), &dentry->d_name, inode); if (unlikely(ret)) { @@ -303,6 +310,9 @@ static int __bch_create(struct inode *dir, struct dentry *dentry, return ret; } + if (dir_ei->journal_seq > ei->journal_seq) + ei->journal_seq = dir_ei->journal_seq; + d_instantiate(dentry, inode); return 0; } @@ -312,11 +322,10 @@ static int __bch_create(struct inode *dir, struct dentry *dentry, static struct dentry *bch_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { - struct cache_set *c = dir->i_sb->s_fs_info; struct inode *inode = NULL; u64 inum; - inum = bch_dirent_lookup(c, dir->i_ino, &dentry->d_name); + inum = bch_dirent_lookup(dir, &dentry->d_name); if (inum) inode = bch_vfs_inode_get(dir->i_sb, inum); @@ -365,7 +374,6 @@ static int bch_link(struct dentry *old_dentry, struct inode *dir, static int bch_unlink(struct inode *dir, struct dentry *dentry) { - struct cache_set *c = dir->i_sb->s_fs_info; struct bch_inode_info *dir_ei = to_bch_ei(dir); struct inode *inode = dentry->d_inode; struct bch_inode_info *ei = to_bch_ei(inode); @@ -373,8 +381,7 @@ static int bch_unlink(struct inode *dir, struct dentry *dentry) lockdep_assert_held(&inode->i_rwsem); - ret = bch_dirent_delete(c, dir->i_ino, &dentry->d_name, - &dir_ei->journal_seq); + ret = bch_dirent_delete(dir, &dentry->d_name); if (ret) return ret; @@ -486,8 +493,8 @@ static int bch_rename(struct inode *old_dir, struct dentry *old_dentry, return -ENOTEMPTY; ret = bch_dirent_rename(c, - old_dir->i_ino, &old_dentry->d_name, - new_dir->i_ino, &new_dentry->d_name, + old_dir, &old_dentry->d_name, + new_dir, &new_dentry->d_name, &ei->journal_seq, BCH_RENAME_OVERWRITE); if (unlikely(ret)) return ret; @@ -498,8 +505,8 @@ static int bch_rename(struct inode *old_dir, struct dentry *old_dentry, lockdep_assert_held(&new_inode->i_rwsem); ret = bch_dirent_rename(c, - old_dir->i_ino, &old_dentry->d_name, - new_dir->i_ino, &new_dentry->d_name, + old_dir, &old_dentry->d_name, + new_dir, &new_dentry->d_name, &ei->journal_seq, BCH_RENAME_OVERWRITE); if (unlikely(ret)) return ret; @@ -508,8 +515,8 @@ static int bch_rename(struct inode *old_dir, struct dentry *old_dentry, inode_dec_link_count(new_inode); } else if (S_ISDIR(old_inode->i_mode)) { ret = bch_dirent_rename(c, - old_dir->i_ino, &old_dentry->d_name, - new_dir->i_ino, &new_dentry->d_name, + old_dir, &old_dentry->d_name, + new_dir, &new_dentry->d_name, &ei->journal_seq, BCH_RENAME); if (unlikely(ret)) return ret; @@ -518,8 +525,8 @@ static int bch_rename(struct inode *old_dir, struct dentry *old_dentry, inode_dec_link_count(old_dir); } else { ret = bch_dirent_rename(c, - old_dir->i_ino, &old_dentry->d_name, - new_dir->i_ino, &new_dentry->d_name, + old_dir, &old_dentry->d_name, + new_dir, &new_dentry->d_name, &ei->journal_seq, BCH_RENAME); if (unlikely(ret)) return ret; @@ -547,8 +554,8 @@ static int bch_rename_exchange(struct inode *old_dir, struct dentry *old_dentry, int ret; ret = bch_dirent_rename(c, - old_dir->i_ino, &old_dentry->d_name, - new_dir->i_ino, &new_dentry->d_name, + old_dir, &old_dentry->d_name, + new_dir, &new_dentry->d_name, &ei->journal_seq, BCH_RENAME_EXCHANGE); if (unlikely(ret)) return ret; @@ -1023,6 +1030,9 @@ static void bch_inode_init(struct bch_inode_info *ei, inode->i_ctime = ns_to_timespec(le64_to_cpu(bi->i_ctime)); bch_inode_flags_to_vfs(inode); + ei->str_hash_seed = le64_to_cpu(bi->i_hash_seed); + ei->str_hash_type = INODE_STR_HASH_TYPE(bi); + inode->i_mapping->a_ops = &bch_address_space_operations; switch (inode->i_mode & S_IFMT) { diff --git a/drivers/md/bcache/fs.h b/drivers/md/bcache/fs.h index a2922163479e..6c12579e9d72 100644 --- a/drivers/md/bcache/fs.h +++ b/drivers/md/bcache/fs.h @@ -40,6 +40,9 @@ struct bch_inode_info { atomic_long_t i_sectors_dirty_count; atomic64_t i_sectors; + + u64 str_hash_seed; + u8 str_hash_type; }; enum { diff --git a/drivers/md/bcache/inode.c b/drivers/md/bcache/inode.c index 18a665b37683..c9469fd115c8 100644 --- a/drivers/md/bcache/inode.c +++ b/drivers/md/bcache/inode.c @@ -59,14 +59,20 @@ static const char *bch_inode_invalid(const struct cache_set *c, return "nonzero offset"; switch (k.k->type) { - case BCH_INODE_FS: + case BCH_INODE_FS: { + struct bkey_s_c_inode inode = bkey_s_c_to_inode(k); + if (bkey_val_bytes(k.k) != sizeof(struct bch_inode)) return "incorrect value size"; if (k.k->p.inode < BLOCKDEV_INODE_MAX) return "fs inode in blockdev range"; + if (INODE_STR_HASH_TYPE(inode.v) >= BCH_STR_HASH_NR) + return "invalid str hash type"; + return NULL; + } case BCH_INODE_BLOCKDEV: if (bkey_val_bytes(k.k) != sizeof(struct bch_inode_blockdev)) return "incorrect value size"; diff --git a/drivers/md/bcache/str_hash.h b/drivers/md/bcache/str_hash.h new file mode 100644 index 000000000000..e25862e9bc2d --- /dev/null +++ b/drivers/md/bcache/str_hash.h @@ -0,0 +1,84 @@ + +#include "siphash.h" +#include <crypto/sha1_base.h> +#include <linux/crc32c.h> + +static const SIPHASH_KEY bch_siphash_key = { + .k0 = cpu_to_le64(0x5a9585fd80087730ULL), + .k1 = cpu_to_le64(0xc8de666d50b45664ULL ), +}; + +struct bch_str_hash_ctx { + union { + u32 crc32c; + u64 crc64; + SIPHASH_CTX siphash; + struct shash_desc sha1; + }; +}; + +static inline void bch_str_hash_init(struct bch_str_hash_ctx *ctx, + enum bch_str_hash_type type) +{ + switch (type) { + case BCH_STR_HASH_CRC32C: + ctx->crc32c = ~0; + break; + case BCH_STR_HASH_CRC64: + ctx->crc64 = ~0; + break; + case BCH_STR_HASH_SIPHASH: + SipHash24_Init(&ctx->siphash, &bch_siphash_key); + break; + case BCH_STR_HASH_SHA1: + sha1_base_init(&ctx->sha1); + break; + default: + BUG(); + } +} + +static inline void bch_str_hash_update(struct bch_str_hash_ctx *ctx, + enum bch_str_hash_type type, + const void *data, size_t len) +{ + switch (type) { + case BCH_STR_HASH_CRC32C: + ctx->crc32c = crc32c(ctx->crc32c, data, len); + break; + case BCH_STR_HASH_CRC64: + ctx->crc64 = bch_crc64_update(ctx->crc64, data, len); + break; + case BCH_STR_HASH_SIPHASH: + SipHash24_Update(&ctx->siphash, data, len); + break; + case BCH_STR_HASH_SHA1: + crypto_sha1_update(&ctx->sha1, data, len); + break; + default: + BUG(); + } +} + +static inline u64 bch_str_hash_end(struct bch_str_hash_ctx *ctx, + enum bch_str_hash_type type) +{ + switch (type) { + case BCH_STR_HASH_CRC32C: + return ctx->crc32c; + case BCH_STR_HASH_CRC64: + return ctx->crc64 >> 1; + case BCH_STR_HASH_SIPHASH: + return SipHash24_End(&ctx->siphash) >> 1; + case BCH_STR_HASH_SHA1: { + u8 out[SHA1_DIGEST_SIZE]; + u64 ret; + + crypto_sha1_finup(&ctx->sha1, NULL, 0, out); + memcpy(&ret, &out, sizeof(ret)); + return ret >> 1; + } + default: + BUG(); + } +} diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index faddbd4ac749..7b5b22764af1 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -39,6 +39,7 @@ #include <linux/kthread.h> #include <linux/module.h> #include <linux/percpu.h> +#include <linux/random.h> #include <linux/reboot.h> #include <linux/sysfs.h> @@ -566,6 +567,7 @@ static int cache_sb_to_cache_set(struct cache_set *c, struct cache_sb *src) c->sb.meta_replicas_have= CACHE_SET_META_REPLICAS_HAVE(src); c->sb.data_replicas_have= CACHE_SET_DATA_REPLICAS_HAVE(src); + c->sb.str_hash_type = CACHE_SET_STR_HASH_TYPE(src); pr_debug("set version = %llu", le64_to_cpu(dst->version)); return 0; @@ -1363,6 +1365,8 @@ static const char *run_cache_set(struct cache_set *c) inode.k.p.inode = BCACHE_ROOT_INO; inode.v.i_mode = cpu_to_le16(S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO); inode.v.i_nlink = cpu_to_le32(2); + get_random_bytes(&inode.v.i_hash_seed, sizeof(inode.v.i_hash_seed)); + SET_INODE_STR_HASH_TYPE(&inode.v, c->sb.str_hash_type); err = "error creating root directory"; if (bch_btree_insert(c, BTREE_ID_INODES, diff --git a/drivers/md/bcache/xattr.c b/drivers/md/bcache/xattr.c index 650808cf1e3b..dca982563c93 100644 --- a/drivers/md/bcache/xattr.c +++ b/drivers/md/bcache/xattr.c @@ -5,65 +5,26 @@ #include "extents.h" #include "fs.h" #include "keylist.h" -#include "siphash.h" +#include "str_hash.h" #include "xattr.h" -#include "linux/crc32c.h" -#include "linux/cryptohash.h" -#include "linux/posix_acl_xattr.h" -#include "linux/xattr.h" +#include <linux/posix_acl_xattr.h> +#include <linux/xattr.h> -#if 0 -/* - * XXX: should really include x_type here - */ -static u64 bch_xattr_hash(const struct qstr *name) +static struct bpos bch_xattr_pos(struct bch_inode_info *ei, + const struct qstr *name, u8 type) { - union { - u32 b[SHA_DIGEST_WORDS]; - u64 ret; - } digest; + struct bch_str_hash_ctx ctx; - unsigned done = 0; + bch_str_hash_init(&ctx, ei->str_hash_type); - sha_init(digest.b); + bch_str_hash_update(&ctx, ei->str_hash_type, + &ei->str_hash_seed, sizeof(ei->str_hash_seed)); + bch_str_hash_update(&ctx, ei->str_hash_type, &type, sizeof(type)); + bch_str_hash_update(&ctx, ei->str_hash_type, name->name, name->len); - while (done < name->len) { - u32 workspace[SHA_WORKSPACE_WORDS]; - u8 message[SHA_MESSAGE_BYTES]; - unsigned bytes = min_t(unsigned, name->len - done, - SHA_MESSAGE_BYTES); - - memcpy(message, name->name + done, bytes); - memset(message + bytes, 0, SHA_MESSAGE_BYTES - bytes); - sha_transform(digest.b, message, workspace); - done += bytes; - } - - return digest.ret; -} - -static const SIPHASH_KEY bch_siphash_key; - -static u64 bch_xattr_hash(const struct qstr *name, u8 type) -{ -#if 0 - SIPHASH_CTX ctx; - - SipHash24_Init(&ctx, &bch_siphash_key); - SipHash24_Update(&ctx, &type, sizeof(type)); - SipHash24_Update(&ctx, name->name, name->len); - - return SipHash24_End(&ctx) >> 1; -#else - return SipHash24(&bch_siphash_key, name->name, name->len) >> 1; -#endif -} -#endif - -static u64 bch_xattr_hash(const struct qstr *name, u8 type) -{ - return crc32c(0, name->name, name->len); + return POS(ei->vfs_inode.i_ino, + bch_str_hash_end(&ctx, ei->str_hash_type)); } #define xattr_val(_xattr) ((_xattr)->x_name + (_xattr)->x_name_len) @@ -141,9 +102,11 @@ const struct bkey_ops bch_bkey_xattr_ops = { .val_to_text = bch_xattr_to_text, }; -int bch_xattr_get(struct cache_set *c, u64 inum, const char *name, +int bch_xattr_get(struct inode *inode, const char *name, void *buffer, size_t size, int type) { + struct cache_set *c = inode->i_sb->s_fs_info; + struct bch_inode_info *ei = to_bch_ei(inode); struct qstr qname = (struct qstr) QSTR_INIT(name, strlen(name)); struct btree_iter iter; struct bkey_s_c k; @@ -151,7 +114,7 @@ int bch_xattr_get(struct cache_set *c, u64 inum, const char *name, int ret = -ENODATA; for_each_btree_key_with_holes(&iter, c, BTREE_ID_XATTRS, - POS(inum, bch_xattr_hash(&qname, type)), k) { + bch_xattr_pos(ei, &qname, type), k) { switch (k.k->type) { case BCH_XATTR: xattr = bkey_s_c_to_xattr(k).v; @@ -200,8 +163,7 @@ int bch_xattr_set(struct inode *inode, const char *name, insert_flags |= BTREE_INSERT_NOFAIL; bch_btree_iter_init_intent(&iter, c, BTREE_ID_XATTRS, - POS(inode->i_ino, - bch_xattr_hash(&qname, type))); + bch_xattr_pos(ei, &qname, type)); while ((k = bch_btree_iter_peek_with_holes(&iter)).k) { switch (k.k->type) { @@ -358,8 +320,7 @@ static int bch_xattr_get_handler(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *buffer, size_t size) { - return bch_xattr_get(inode->i_sb->s_fs_info, inode->i_ino, - name, buffer, size, handler->flags); + return bch_xattr_get(inode, name, buffer, size, handler->flags); } static int bch_xattr_set_handler(const struct xattr_handler *handler, diff --git a/drivers/md/bcache/xattr.h b/drivers/md/bcache/xattr.h index 839d47ef6910..675529d328d0 100644 --- a/drivers/md/bcache/xattr.h +++ b/drivers/md/bcache/xattr.h @@ -7,7 +7,7 @@ extern const struct bkey_ops bch_bkey_xattr_ops; struct dentry; struct xattr_handler; -int bch_xattr_get(struct cache_set *, u64, const char *, void *, size_t, int); +int bch_xattr_get(struct inode *, const char *, void *, size_t, int); int bch_xattr_set(struct inode *, const char *, const void *, size_t, int, int); ssize_t bch_xattr_list(struct dentry *, char *, size_t); diff --git a/include/uapi/linux/bcache.h b/include/uapi/linux/bcache.h index 4c8a456cbe19..e2ac852913e9 100644 --- a/include/uapi/linux/bcache.h +++ b/include/uapi/linux/bcache.h @@ -483,6 +483,31 @@ enum bch_inode_types { BCH_INODE_BLOCKDEV = 129, }; +struct bch_inode { + struct bch_val v; + + __le16 i_mode; + __le16 pad; + __le32 i_flags; + + /* Nanoseconds */ + __le64 i_atime; + __le64 i_ctime; + __le64 i_mtime; + + __le64 i_size; + __le64 i_sectors; + + __le32 i_uid; + __le32 i_gid; + __le32 i_nlink; + + __le32 i_dev; + + __le64 i_hash_seed; +} __attribute__((packed)); +BKEY_VAL_TYPE(inode, BCH_INODE_FS); + enum { /* * User flags (get/settable with FS_IOC_*FLAGS, correspond to FS_*_FL @@ -501,6 +526,8 @@ enum { __BCH_INODE_HAS_XATTRS = 7, /* has xattrs in xattr btree */ }; +LE32_BITMASK(INODE_STR_HASH_TYPE, struct bch_inode, i_flags, 28, 32); + #define BCH_INODE_SYNC (1 << __BCH_INODE_SYNC) #define BCH_INODE_IMMUTABLE (1 << __BCH_INODE_IMMUTABLE) #define BCH_INODE_APPEND (1 << __BCH_INODE_APPEND) @@ -510,29 +537,6 @@ enum { #define BCH_INODE_I_SECTORS_DIRTY (1 << __BCH_INODE_I_SECTORS_DIRTY) #define BCH_INODE_HAS_XATTRS (1 << __BCH_INODE_HAS_XATTRS) -struct bch_inode { - struct bch_val v; - - __le16 i_mode; - __le16 pad; - __le32 i_flags; - - /* Nanoseconds */ - __le64 i_atime; - __le64 i_ctime; - __le64 i_mtime; - - __le64 i_size; - __le64 i_sectors; - - __le32 i_uid; - __le32 i_gid; - __le32 i_nlink; - - __le32 i_dev; -} __attribute__((packed)); -BKEY_VAL_TYPE(inode, BCH_INODE_FS); - struct bch_inode_blockdev { struct bch_val v; @@ -751,14 +755,16 @@ LE64_BITMASK(CACHE_BTREE_NODE_SIZE, struct cache_sb, flags, 20, 36); LE64_BITMASK(CACHE_SET_META_REPLICAS_HAVE,struct cache_sb, flags, 36, 40); LE64_BITMASK(CACHE_SET_DATA_REPLICAS_HAVE,struct cache_sb, flags, 40, 44); -LE64_BITMASK(CACHE_SET_DIRENT_CSUM_TYPE,struct cache_sb, flags, 44, 48); -enum { - BCH_DIRENT_CSUM_CRC32C = 0, - BCH_DIRENT_CSUM_CRC64 = 1, - BCH_DIRENT_CSUM_SIPHASH = 2, - BCH_DIRENT_CSUM_SHA1 = 3, +LE64_BITMASK(CACHE_SET_STR_HASH_TYPE,struct cache_sb, flags, 44, 48); +enum bch_str_hash_type { + BCH_STR_HASH_CRC32C = 0, + BCH_STR_HASH_CRC64 = 1, + BCH_STR_HASH_SIPHASH = 2, + BCH_STR_HASH_SHA1 = 3, }; +#define BCH_STR_HASH_NR 4 + LE64_BITMASK(CACHE_DATA_PREFERRED_CSUM_TYPE, struct cache_sb, flags, 48, 52); LE64_BITMASK(CACHE_COMPRESSION_TYPE, struct cache_sb, flags, 52, 56); |