summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2016-04-25 15:21:06 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2017-01-18 21:38:27 -0900
commit70beb52ed9be1d89a7c177330ad57458f12fdedb (patch)
tree6b840c78fb1df9729f720cd1654b7d53e887039c
parent687567abd7eb3bbc5b6b081fb617f7fd68e90664 (diff)
bcachefs: selectable dirent/xattr hash type
-rw-r--r--drivers/md/bcache/Kconfig1
-rw-r--r--drivers/md/bcache/acl.c5
-rw-r--r--drivers/md/bcache/bcache.h2
-rw-r--r--drivers/md/bcache/dirent.c120
-rw-r--r--drivers/md/bcache/dirent.h13
-rw-r--r--drivers/md/bcache/fs.c46
-rw-r--r--drivers/md/bcache/fs.h3
-rw-r--r--drivers/md/bcache/inode.c8
-rw-r--r--drivers/md/bcache/str_hash.h84
-rw-r--r--drivers/md/bcache/super.c4
-rw-r--r--drivers/md/bcache/xattr.c77
-rw-r--r--drivers/md/bcache/xattr.h2
-rw-r--r--include/uapi/linux/bcache.h64
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);