]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Update bcachefs sources to ba398d2906 bcachefs: Fix reflink repair code
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 13 Feb 2022 09:07:30 +0000 (04:07 -0500)
committerKent Overstreet <kent.overstreet@gmail.com>
Sun, 13 Feb 2022 09:08:33 +0000 (04:08 -0500)
13 files changed:
.bcachefs_revision
include/linux/siphash.h [new file with mode: 0644]
libbcachefs/alloc_background.c
libbcachefs/btree_gc.c
libbcachefs/btree_iter.c
libbcachefs/btree_update_leaf.c
libbcachefs/buckets.c
libbcachefs/buckets_waiting_for_journal.c
libbcachefs/buckets_waiting_for_journal.h
libbcachefs/buckets_waiting_for_journal_types.h
libbcachefs/io.c
libbcachefs/sysfs.c
linux/siphash.c [new file with mode: 0644]

index 4bc1040c34c0c35c092b34fa346f2b337019c599..521fa21a482f489899ec084c2004b5a4db543437 100644 (file)
@@ -1 +1 @@
-b84661c042c7d5caaab3f79661d04789070bea78
+ba398d29060ecc2e2c9d6292a94ddc181761de1a
diff --git a/include/linux/siphash.h b/include/linux/siphash.h
new file mode 100644 (file)
index 0000000..bf21591
--- /dev/null
@@ -0,0 +1,145 @@
+/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.
+ *
+ * SipHash: a fast short-input PRF
+ * https://131002.net/siphash/
+ *
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
+ */
+
+#ifndef _LINUX_SIPHASH_H
+#define _LINUX_SIPHASH_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#define SIPHASH_ALIGNMENT __alignof__(u64)
+typedef struct {
+       u64 key[2];
+} siphash_key_t;
+
+static inline bool siphash_key_is_zero(const siphash_key_t *key)
+{
+       return !(key->key[0] | key->key[1]);
+}
+
+u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key);
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key);
+#endif
+
+u64 siphash_1u64(const u64 a, const siphash_key_t *key);
+u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key);
+u64 siphash_3u64(const u64 a, const u64 b, const u64 c,
+                const siphash_key_t *key);
+u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d,
+                const siphash_key_t *key);
+u64 siphash_1u32(const u32 a, const siphash_key_t *key);
+u64 siphash_3u32(const u32 a, const u32 b, const u32 c,
+                const siphash_key_t *key);
+
+static inline u64 siphash_2u32(const u32 a, const u32 b,
+                              const siphash_key_t *key)
+{
+       return siphash_1u64((u64)b << 32 | a, key);
+}
+static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c,
+                              const u32 d, const siphash_key_t *key)
+{
+       return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key);
+}
+
+
+static inline u64 ___siphash_aligned(const __le64 *data, size_t len,
+                                    const siphash_key_t *key)
+{
+       if (__builtin_constant_p(len) && len == 4)
+               return siphash_1u32(le32_to_cpup((const __le32 *)data), key);
+       if (__builtin_constant_p(len) && len == 8)
+               return siphash_1u64(le64_to_cpu(data[0]), key);
+       if (__builtin_constant_p(len) && len == 16)
+               return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+                                   key);
+       if (__builtin_constant_p(len) && len == 24)
+               return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+                                   le64_to_cpu(data[2]), key);
+       if (__builtin_constant_p(len) && len == 32)
+               return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+                                   le64_to_cpu(data[2]), le64_to_cpu(data[3]),
+                                   key);
+       return __siphash_aligned(data, len, key);
+}
+
+/**
+ * siphash - compute 64-bit siphash PRF value
+ * @data: buffer to hash
+ * @size: size of @data
+ * @key: the siphash key
+ */
+static inline u64 siphash(const void *data, size_t len,
+                         const siphash_key_t *key)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+       if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
+               return __siphash_unaligned(data, len, key);
+#endif
+       return ___siphash_aligned(data, len, key);
+}
+
+#define HSIPHASH_ALIGNMENT __alignof__(unsigned long)
+typedef struct {
+       unsigned long key[2];
+} hsiphash_key_t;
+
+u32 __hsiphash_aligned(const void *data, size_t len,
+                      const hsiphash_key_t *key);
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len,
+                        const hsiphash_key_t *key);
+#endif
+
+u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key);
+u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key);
+u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c,
+                 const hsiphash_key_t *key);
+u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d,
+                 const hsiphash_key_t *key);
+
+static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len,
+                                     const hsiphash_key_t *key)
+{
+       if (__builtin_constant_p(len) && len == 4)
+               return hsiphash_1u32(le32_to_cpu(data[0]), key);
+       if (__builtin_constant_p(len) && len == 8)
+               return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+                                    key);
+       if (__builtin_constant_p(len) && len == 12)
+               return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+                                    le32_to_cpu(data[2]), key);
+       if (__builtin_constant_p(len) && len == 16)
+               return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+                                    le32_to_cpu(data[2]), le32_to_cpu(data[3]),
+                                    key);
+       return __hsiphash_aligned(data, len, key);
+}
+
+/**
+ * hsiphash - compute 32-bit hsiphash PRF value
+ * @data: buffer to hash
+ * @size: size of @data
+ * @key: the hsiphash key
+ */
+static inline u32 hsiphash(const void *data, size_t len,
+                          const hsiphash_key_t *key)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+       if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
+               return __hsiphash_unaligned(data, len, key);
+#endif
+       return ___hsiphash_aligned(data, len, key);
+}
+
+#endif /* _LINUX_SIPHASH_H */
index 0a5ec99e7c3ebff0732a8a80145fddd1b130c751..023db6219ad878f8106b439895adf7d8f362a358 100644 (file)
@@ -540,7 +540,8 @@ static void find_reclaimable_buckets_lru(struct bch_fs *c, struct bch_dev *ca)
                        continue;
 
                if (!m.data_type &&
-                   bch2_bucket_needs_journal_commit(c, last_seq_ondisk,
+                   bch2_bucket_needs_journal_commit(&c->buckets_waiting_for_journal,
+                                                    last_seq_ondisk,
                                                     ca->dev_idx, b)) {
                        ca->buckets_waiting_on_journal++;
                        continue;
index 7cab220c74b71494dca1d13d0c9f97ea978bf223..d9944fb8cde6978c2ab39f9c895cb75840933b05 100644 (file)
@@ -1938,30 +1938,17 @@ int bch2_gc_gens(struct bch_fs *c)
                        }
                }
 
-       for_each_member_device(ca, c, i) {
-               for_each_btree_key(&trans, iter, BTREE_ID_alloc,
-                                  POS(ca->dev_idx, ca->mi.first_bucket),
-                                  BTREE_ITER_SLOTS|
-                                  BTREE_ITER_PREFETCH, k, ret) {
-                       if (bkey_cmp(iter.pos, POS(ca->dev_idx, ca->mi.nbuckets)) >= 0)
-                               break;
-
-                       ret = __bch2_trans_do(&trans, NULL, NULL,
-                                             BTREE_INSERT_LAZY_RW|
-                                             BTREE_INSERT_NOFAIL,
-                                       bch2_alloc_write_oldest_gen(&trans, &iter));
-                       if (ret) {
-                               bch_err(c, "error writing oldest_gen: %i", ret);
-                               break;
-                       }
-               }
-               bch2_trans_iter_exit(&trans, &iter);
-
+       for_each_btree_key(&trans, iter, BTREE_ID_alloc, POS_MIN,
+                          BTREE_ITER_PREFETCH, k, ret) {
+               ret = __bch2_trans_do(&trans, NULL, NULL,
+                                     BTREE_INSERT_NOFAIL,
+                               bch2_alloc_write_oldest_gen(&trans, &iter));
                if (ret) {
-                       percpu_ref_put(&ca->ref);
+                       bch_err(c, "error writing oldest_gen: %i", ret);
                        break;
                }
        }
+       bch2_trans_iter_exit(&trans, &iter);
 
        c->gc_gens_btree        = 0;
        c->gc_gens_pos          = POS_MIN;
index 8505ad5c05177827f8b14bc02132005877d4185d..b9cb2ebfcb4704ce7c43007b6b4d5840188af991 100644 (file)
@@ -2317,6 +2317,7 @@ static struct bkey_s_c __bch2_btree_iter_peek(struct btree_iter *iter, struct bp
                        ret = bkey_err(k2);
                        if (ret) {
                                k = k2;
+                               bch2_btree_iter_set_pos(iter, iter->pos);
                                goto out;
                        }
 
index 9d954537f449ea107c5e6069b8392fdbd125bb84..0e6721643fd054dff71329690527ba9c185cdf28 100644 (file)
@@ -399,10 +399,11 @@ static inline void do_btree_insert_one(struct btree_trans *trans,
        }
 }
 
-static noinline void bch2_trans_mark_gc(struct btree_trans *trans)
+static noinline int bch2_trans_mark_gc(struct btree_trans *trans)
 {
        struct bch_fs *c = trans->c;
        struct btree_insert_entry *i;
+       int ret = 0;
 
        trans_for_each_update(trans, i) {
                /*
@@ -411,10 +412,15 @@ static noinline void bch2_trans_mark_gc(struct btree_trans *trans)
                 */
                BUG_ON(i->cached || i->level);
 
-               if (gc_visited(c, gc_pos_btree_node(insert_l(i)->b)))
-                       bch2_mark_update(trans, i->path, i->k,
-                                        i->flags|BTREE_TRIGGER_GC);
+               if (gc_visited(c, gc_pos_btree_node(insert_l(i)->b))) {
+                       ret = bch2_mark_update(trans, i->path, i->k,
+                                              i->flags|BTREE_TRIGGER_GC);
+                       if (ret)
+                               break;
+               }
        }
+
+       return ret;
 }
 
 static inline int
@@ -513,11 +519,17 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
                return BTREE_INSERT_NEED_MARK_REPLICAS;
 
        trans_for_each_update(trans, i)
-               if (BTREE_NODE_TYPE_HAS_MEM_TRIGGERS & (1U << i->bkey_type))
-                       bch2_mark_update(trans, i->path, i->k, i->flags);
+               if (BTREE_NODE_TYPE_HAS_MEM_TRIGGERS & (1U << i->bkey_type)) {
+                       ret = bch2_mark_update(trans, i->path, i->k, i->flags);
+                       if (ret)
+                               return ret;
+               }
 
-       if (unlikely(c->gc_pos.phase))
-               bch2_trans_mark_gc(trans);
+       if (unlikely(c->gc_pos.phase)) {
+               ret = bch2_trans_mark_gc(trans);
+               if  (ret)
+                       return ret;
+       }
 
        trans_for_each_update(trans, i)
                do_btree_insert_one(trans, i);
index b9f09b8250ca9a3a62d692247ba7aeb4b457f41b..50fcc075dc240a5ea58a8563254f3c2e66ab84e1 100644 (file)
@@ -537,11 +537,15 @@ static int bch2_mark_alloc(struct btree_trans *trans,
        }
 
        if (old_u.data_type && !new_u.data_type && new_u.journal_seq) {
-               ret = bch2_set_bucket_needs_journal_commit(c,
+               ret = bch2_set_bucket_needs_journal_commit(&c->buckets_waiting_for_journal,
+                               c->journal.flushed_seq_ondisk,
                                new_u.dev, new_u.bucket,
                                new_u.journal_seq);
-               if (ret)
+               if (ret) {
+                       bch2_fs_fatal_error(c,
+                               "error setting bucket_needs_journal_commit: %i", ret);
                        return ret;
+               }
        }
 
        ca = bch_dev_bkey_exists(c, new_u.dev);
index 56b37b24fcca35718e0485601c0641976aa23603..2e5b955080de46676ca04dc2796a97c55e840f60 100644 (file)
@@ -2,36 +2,46 @@
 
 #include "bcachefs.h"
 #include "buckets_waiting_for_journal.h"
-#include <linux/jhash.h>
+#include <linux/random.h>
 
-static u32 hash_seeds[] = {
-       2168153708,
-       1262039142,
-       1183479835,
-};
+static inline struct bucket_hashed *
+bucket_hash(struct buckets_waiting_for_journal_table *t,
+           unsigned hash_seed_idx, u64 dev_bucket)
+{
+       unsigned h = siphash_1u64(dev_bucket, &t->hash_seeds[hash_seed_idx]);
+
+       BUG_ON(!is_power_of_2(t->size));
+
+       return t->d + (h & (t->size - 1));
+}
 
-static inline unsigned bucket_hash(u64 dev_bucket, unsigned hash_seed_idx)
+static void bucket_table_init(struct buckets_waiting_for_journal_table *t, size_t size)
 {
-       return jhash_2words(dev_bucket << 32, dev_bucket, hash_seeds[hash_seed_idx]);
+       unsigned i;
+
+       t->size = size;
+       for (i = 0; i < ARRAY_SIZE(t->hash_seeds); i++)
+               get_random_bytes(&t->hash_seeds[i], sizeof(t->hash_seeds[i]));
+       memset(t->d, 0, sizeof(t->d[0]) * size);
 }
 
-bool bch2_bucket_needs_journal_commit(struct bch_fs *c,
+bool bch2_bucket_needs_journal_commit(struct buckets_waiting_for_journal *b,
                                      u64 flushed_seq,
                                      unsigned dev, u64 bucket)
 {
-       struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
+       struct buckets_waiting_for_journal_table *t;
        u64 dev_bucket = (u64) dev << 56 | bucket;
        bool ret = false;
        unsigned i;
 
        mutex_lock(&b->lock);
-       BUG_ON(!is_power_of_2(b->nr));
+       t = b->t;
 
-       for (i = 0; i < ARRAY_SIZE(hash_seeds); i++) {
-               u32 h = bucket_hash(dev_bucket, i) & (b->nr - 1);
+       for (i = 0; i < ARRAY_SIZE(t->hash_seeds); i++) {
+               struct bucket_hashed *h = bucket_hash(t, i, dev_bucket);
 
-               if (b->d[h].dev_bucket == dev_bucket) {
-                       ret = b->d[h].journal_seq > flushed_seq;
+               if (h->dev_bucket == dev_bucket) {
+                       ret = h->journal_seq > flushed_seq;
                        break;
                }
        }
@@ -41,84 +51,92 @@ bool bch2_bucket_needs_journal_commit(struct bch_fs *c,
        return ret;
 }
 
-static int bch2_buckets_waiting_for_journal_rehash(struct bch_fs *c)
+static bool bucket_table_insert(struct buckets_waiting_for_journal_table *t,
+                               struct bucket_hashed *new,
+                               u64 flushed_seq)
 {
-       struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
-       u64 flushed_seq = c->journal.flushed_seq_ondisk;
-       unsigned i, j, h, new_nr = b->nr * 2, elements = 0;
-       struct bucket_hashed *new_table;
+       struct bucket_hashed *last_evicted = NULL;
+       unsigned tries, i;
 
-       new_table = kvmalloc_array(new_nr, sizeof(*new_table), __GFP_ZERO);
-       if (!new_table)
-               return -ENOMEM;
+       for (tries = 0; tries < 10; tries++) {
+               struct bucket_hashed *old, *victim = NULL;
 
-       for (i = 0; i < b->nr; i++) {
-               if (b->d[i].journal_seq < flushed_seq)
-                       continue;
+               for (i = 0; i < ARRAY_SIZE(t->hash_seeds); i++) {
+                       old = bucket_hash(t, i, new->dev_bucket);
 
-               for (j = 0; j < ARRAY_SIZE(hash_seeds); j++) {
-                       h = bucket_hash(b->d[i].dev_bucket, j);
-                       if ((h & (b->nr - 1)) == i)
-                               break;
-               }
+                       if (old->dev_bucket == new->dev_bucket ||
+                           old->journal_seq <= flushed_seq) {
+                               *old = *new;
+                               return true;
+                       }
 
-               BUG_ON(j == ARRAY_SIZE(hash_seeds));
-               BUG_ON(new_table[h & (new_nr - 1)].dev_bucket);
+                       if (last_evicted != old)
+                               victim = old;
+               }
 
-               new_table[h & (new_nr - 1)] = b->d[i];
+               /* hashed to same slot 3 times: */
+               if (!victim)
+                       break;
 
-               elements++;
+               /* Failed to find an empty slot: */
+               swap(*new, *victim);
+               last_evicted = victim;
        }
 
-       kvfree(b->d);
-       b->nr   = new_nr;
-       b->d    = new_table;
-       return 0;
+       return false;
 }
 
-int bch2_set_bucket_needs_journal_commit(struct bch_fs *c, unsigned dev, u64 bucket,
+int bch2_set_bucket_needs_journal_commit(struct buckets_waiting_for_journal *b,
+                                        u64 flushed_seq,
+                                        unsigned dev, u64 bucket,
                                         u64 journal_seq)
 {
-       struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
-       struct bucket_hashed new = {
+       struct buckets_waiting_for_journal_table *t, *n;
+       struct bucket_hashed tmp, new = {
                .dev_bucket     = (u64) dev << 56 | bucket,
                .journal_seq    = journal_seq,
-       }, *last_evicted = NULL;
-       u64 flushed_seq = c->journal.flushed_seq_ondisk;
-       unsigned tries, i;
+       };
+       size_t i, new_size, nr_elements = 1, nr_rehashes = 0;
        int ret = 0;
 
        mutex_lock(&b->lock);
-       BUG_ON(!is_power_of_2(b->nr));
-retry:
-       for (tries = 0; tries < 5; tries++) {
-               struct bucket_hashed *old, *victim = NULL;
 
-               for (i = 0; i < ARRAY_SIZE(hash_seeds); i++) {
-                       old = b->d + (bucket_hash(new.dev_bucket, i) & (b->nr - 1));
+       if (likely(bucket_table_insert(b->t, &new, flushed_seq)))
+               goto out;
 
-                       if (old->dev_bucket == new.dev_bucket ||
-                           old->journal_seq <= flushed_seq) {
-                               *old = new;
-                               goto out;
-                       }
+       t = b->t;
+       for (i = 0; i < t->size; i++)
+               nr_elements += t->d[i].journal_seq > flushed_seq;
 
-                       if (last_evicted != old)
-                               victim = old;
-               }
+       new_size = nr_elements < t->size / 3 ? t->size : t->size * 2;
 
-               /* hashed to same slot 3 times: */
-               if (!victim)
-                       break;
+       n = kvmalloc(sizeof(*n) + sizeof(n->d[0]) * new_size, GFP_KERNEL);
+       if (!n) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
-               /* Failed to find an empty slot: */
-               swap(new, *victim);
-               last_evicted = victim;
+retry_rehash:
+       nr_rehashes++;
+       bucket_table_init(n, new_size);
+
+       tmp = new;
+       BUG_ON(!bucket_table_insert(n, &tmp, flushed_seq));
+
+       for (i = 0; i < t->size; i++) {
+               if (t->d[i].journal_seq <= flushed_seq)
+                       continue;
+
+               tmp = t->d[i];
+               if (!bucket_table_insert(n, &tmp, flushed_seq))
+                       goto retry_rehash;
        }
 
-       ret = bch2_buckets_waiting_for_journal_rehash(c);
-       if (!ret)
-               goto retry;
+       b->t = n;
+       kvfree(t);
+
+       pr_debug("took %zu rehashes, table at %zu/%zu elements",
+                nr_rehashes, nr_elements, b->t->size);
 out:
        mutex_unlock(&b->lock);
 
@@ -129,19 +147,21 @@ void bch2_fs_buckets_waiting_for_journal_exit(struct bch_fs *c)
 {
        struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
 
-       kvfree(b->d);
+       kvfree(b->t);
 }
 
+#define INITIAL_TABLE_SIZE     8
+
 int bch2_fs_buckets_waiting_for_journal_init(struct bch_fs *c)
 {
        struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
 
        mutex_init(&b->lock);
 
-       b->nr = 8;
-       b->d = kvmalloc_array(b->nr, sizeof(*b->d), __GFP_ZERO);
-       if (!b->d)
+       b->t = kvmalloc(sizeof(*b->t) + sizeof(b->t->d[0]) * INITIAL_TABLE_SIZE, GFP_KERNEL);
+       if (!b->t)
                return -ENOMEM;
 
+       bucket_table_init(b->t, INITIAL_TABLE_SIZE);
        return 0;
 }
index 079a591c500abd472fd4eb22d9e04ea27e0c1699..d2ae19cbe18c484e50ac5f04af80ae91bd79a4af 100644 (file)
@@ -4,8 +4,10 @@
 
 #include "buckets_waiting_for_journal_types.h"
 
-bool bch2_bucket_needs_journal_commit(struct bch_fs *, u64, unsigned, u64);
-int bch2_set_bucket_needs_journal_commit(struct bch_fs *, unsigned, u64, u64);
+bool bch2_bucket_needs_journal_commit(struct buckets_waiting_for_journal *,
+                                     u64, unsigned, u64);
+int bch2_set_bucket_needs_journal_commit(struct buckets_waiting_for_journal *,
+                                        u64, unsigned, u64, u64);
 
 void bch2_fs_buckets_waiting_for_journal_exit(struct bch_fs *);
 int bch2_fs_buckets_waiting_for_journal_init(struct bch_fs *);
index 99d17ffb7e9470271174299dca41f706a495c237..fea7f944d0ed38e61cb4e4fc38319c29d4a913b4 100644 (file)
@@ -2,15 +2,22 @@
 #ifndef _BUCKETS_WAITING_FOR_JOURNAL_TYPES_H
 #define _BUCKETS_WAITING_FOR_JOURNAL_TYPES_H
 
+#include <linux/siphash.h>
+
 struct bucket_hashed {
        u64                     dev_bucket;
        u64                     journal_seq;
 };
 
+struct buckets_waiting_for_journal_table {
+       size_t                  size;
+       siphash_key_t           hash_seeds[3];
+       struct bucket_hashed    d[];
+};
+
 struct buckets_waiting_for_journal {
        struct mutex            lock;
-       size_t                  nr;
-       struct bucket_hashed    *d;
+       struct buckets_waiting_for_journal_table *t;
 };
 
 #endif /* _BUCKETS_WAITING_FOR_JOURNAL_TYPES_H */
index 73558cd0035029acf44b0616d68de261174e73ba..f0e93de4680d20c61eb6ec4b423db59b129c943a 100644 (file)
@@ -1893,9 +1893,8 @@ static void bch2_read_endio(struct bio *bio)
                return;
        }
 
-       if (rbio->pick.ptr.cached &&
-           (((rbio->flags & BCH_READ_RETRY_IF_STALE) && race_fault()) ||
-            ptr_stale(ca, &rbio->pick.ptr))) {
+       if (((rbio->flags & BCH_READ_RETRY_IF_STALE) && race_fault()) ||
+           ptr_stale(ca, &rbio->pick.ptr)) {
                atomic_long_inc(&c->read_realloc_races);
 
                if (rbio->flags & BCH_READ_RETRY_IF_STALE)
index ed9a095063e8f684098f5a12d5e1541236a00bba..b727845dd64b73d4ea51fe8842c9f03ca899ad23 100644 (file)
@@ -499,6 +499,17 @@ STORE(bch2_fs)
 
        /* Debugging: */
 
+       if (!test_bit(BCH_FS_RW, &c->flags))
+               return -EROFS;
+
+       if (attr == &sysfs_prune_cache) {
+               struct shrink_control sc;
+
+               sc.gfp_mask = GFP_KERNEL;
+               sc.nr_to_scan = strtoul_or_return(buf);
+               c->btree_cache.shrink.scan_objects(&c->btree_cache.shrink, &sc);
+       }
+
        if (attr == &sysfs_trigger_gc) {
                /*
                 * Full gc is currently incompatible with btree key cache:
@@ -512,14 +523,6 @@ STORE(bch2_fs)
 #endif
        }
 
-       if (attr == &sysfs_prune_cache) {
-               struct shrink_control sc;
-
-               sc.gfp_mask = GFP_KERNEL;
-               sc.nr_to_scan = strtoul_or_return(buf);
-               c->btree_cache.shrink.scan_objects(&c->btree_cache.shrink, &sc);
-       }
-
 #ifdef CONFIG_BCACHEFS_TESTS
        if (attr == &sysfs_perf_test) {
                char *tmp = kstrdup(buf, GFP_KERNEL), *p = tmp;
diff --git a/linux/siphash.c b/linux/siphash.c
new file mode 100644 (file)
index 0000000..f8dbece
--- /dev/null
@@ -0,0 +1,552 @@
+/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.
+ *
+ * SipHash: a fast short-input PRF
+ * https://131002.net/siphash/
+ *
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
+ */
+
+#include <linux/siphash.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
+
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+#include <linux/dcache.h>
+#include <asm/word-at-a-time.h>
+#endif
+
+#define SIPROUND \
+       do { \
+       v0 += v1; v1 = rol64(v1, 13); v1 ^= v0; v0 = rol64(v0, 32); \
+       v2 += v3; v3 = rol64(v3, 16); v3 ^= v2; \
+       v0 += v3; v3 = rol64(v3, 21); v3 ^= v0; \
+       v2 += v1; v1 = rol64(v1, 17); v1 ^= v2; v2 = rol64(v2, 32); \
+       } while (0)
+
+#define PREAMBLE(len) \
+       u64 v0 = 0x736f6d6570736575ULL; \
+       u64 v1 = 0x646f72616e646f6dULL; \
+       u64 v2 = 0x6c7967656e657261ULL; \
+       u64 v3 = 0x7465646279746573ULL; \
+       u64 b = ((u64)(len)) << 56; \
+       v3 ^= key->key[1]; \
+       v2 ^= key->key[0]; \
+       v1 ^= key->key[1]; \
+       v0 ^= key->key[0];
+
+#define POSTAMBLE \
+       v3 ^= b; \
+       SIPROUND; \
+       SIPROUND; \
+       v0 ^= b; \
+       v2 ^= 0xff; \
+       SIPROUND; \
+       SIPROUND; \
+       SIPROUND; \
+       SIPROUND; \
+       return (v0 ^ v1) ^ (v2 ^ v3);
+
+u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key)
+{
+       const u8 *end = data + len - (len % sizeof(u64));
+       const u8 left = len & (sizeof(u64) - 1);
+       u64 m;
+       PREAMBLE(len)
+       for (; data != end; data += sizeof(u64)) {
+               m = le64_to_cpup(data);
+               v3 ^= m;
+               SIPROUND;
+               SIPROUND;
+               v0 ^= m;
+       }
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+       if (left)
+               b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+                                                 bytemask_from_count(left)));
+#else
+       switch (left) {
+       case 7: b |= ((u64)end[6]) << 48; fallthrough;
+       case 6: b |= ((u64)end[5]) << 40; fallthrough;
+       case 5: b |= ((u64)end[4]) << 32; fallthrough;
+       case 4: b |= le32_to_cpup(data); break;
+       case 3: b |= ((u64)end[2]) << 16; fallthrough;
+       case 2: b |= le16_to_cpup(data); break;
+       case 1: b |= end[0];
+       }
+#endif
+       POSTAMBLE
+}
+EXPORT_SYMBOL(__siphash_aligned);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key)
+{
+       const u8 *end = data + len - (len % sizeof(u64));
+       const u8 left = len & (sizeof(u64) - 1);
+       u64 m;
+       PREAMBLE(len)
+       for (; data != end; data += sizeof(u64)) {
+               m = get_unaligned_le64(data);
+               v3 ^= m;
+               SIPROUND;
+               SIPROUND;
+               v0 ^= m;
+       }
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+       if (left)
+               b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+                                                 bytemask_from_count(left)));
+#else
+       switch (left) {
+       case 7: b |= ((u64)end[6]) << 48; fallthrough;
+       case 6: b |= ((u64)end[5]) << 40; fallthrough;
+       case 5: b |= ((u64)end[4]) << 32; fallthrough;
+       case 4: b |= get_unaligned_le32(end); break;
+       case 3: b |= ((u64)end[2]) << 16; fallthrough;
+       case 2: b |= get_unaligned_le16(end); break;
+       case 1: b |= end[0];
+       }
+#endif
+       POSTAMBLE
+}
+EXPORT_SYMBOL(__siphash_unaligned);
+#endif
+
+/**
+ * siphash_1u64 - compute 64-bit siphash PRF value of a u64
+ * @first: first u64
+ * @key: the siphash key
+ */
+u64 siphash_1u64(const u64 first, const siphash_key_t *key)
+{
+       PREAMBLE(8)
+       v3 ^= first;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= first;
+       POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_1u64);
+
+/**
+ * siphash_2u64 - compute 64-bit siphash PRF value of 2 u64
+ * @first: first u64
+ * @second: second u64
+ * @key: the siphash key
+ */
+u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key)
+{
+       PREAMBLE(16)
+       v3 ^= first;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= first;
+       v3 ^= second;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= second;
+       POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_2u64);
+
+/**
+ * siphash_3u64 - compute 64-bit siphash PRF value of 3 u64
+ * @first: first u64
+ * @second: second u64
+ * @third: third u64
+ * @key: the siphash key
+ */
+u64 siphash_3u64(const u64 first, const u64 second, const u64 third,
+                const siphash_key_t *key)
+{
+       PREAMBLE(24)
+       v3 ^= first;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= first;
+       v3 ^= second;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= second;
+       v3 ^= third;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= third;
+       POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_3u64);
+
+/**
+ * siphash_4u64 - compute 64-bit siphash PRF value of 4 u64
+ * @first: first u64
+ * @second: second u64
+ * @third: third u64
+ * @forth: forth u64
+ * @key: the siphash key
+ */
+u64 siphash_4u64(const u64 first, const u64 second, const u64 third,
+                const u64 forth, const siphash_key_t *key)
+{
+       PREAMBLE(32)
+       v3 ^= first;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= first;
+       v3 ^= second;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= second;
+       v3 ^= third;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= third;
+       v3 ^= forth;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= forth;
+       POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_4u64);
+
+u64 siphash_1u32(const u32 first, const siphash_key_t *key)
+{
+       PREAMBLE(4)
+       b |= first;
+       POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_1u32);
+
+u64 siphash_3u32(const u32 first, const u32 second, const u32 third,
+                const siphash_key_t *key)
+{
+       u64 combined = (u64)second << 32 | first;
+       PREAMBLE(12)
+       v3 ^= combined;
+       SIPROUND;
+       SIPROUND;
+       v0 ^= combined;
+       b |= third;
+       POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_3u32);
+
+#if BITS_PER_LONG == 64
+/* Note that on 64-bit, we make HalfSipHash1-3 actually be SipHash1-3, for
+ * performance reasons. On 32-bit, below, we actually implement HalfSipHash1-3.
+ */
+
+#define HSIPROUND SIPROUND
+#define HPREAMBLE(len) PREAMBLE(len)
+#define HPOSTAMBLE \
+       v3 ^= b; \
+       HSIPROUND; \
+       v0 ^= b; \
+       v2 ^= 0xff; \
+       HSIPROUND; \
+       HSIPROUND; \
+       HSIPROUND; \
+       return (v0 ^ v1) ^ (v2 ^ v3);
+
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
+{
+       const u8 *end = data + len - (len % sizeof(u64));
+       const u8 left = len & (sizeof(u64) - 1);
+       u64 m;
+       HPREAMBLE(len)
+       for (; data != end; data += sizeof(u64)) {
+               m = le64_to_cpup(data);
+               v3 ^= m;
+               HSIPROUND;
+               v0 ^= m;
+       }
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+       if (left)
+               b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+                                                 bytemask_from_count(left)));
+#else
+       switch (left) {
+       case 7: b |= ((u64)end[6]) << 48; fallthrough;
+       case 6: b |= ((u64)end[5]) << 40; fallthrough;
+       case 5: b |= ((u64)end[4]) << 32; fallthrough;
+       case 4: b |= le32_to_cpup(data); break;
+       case 3: b |= ((u64)end[2]) << 16; fallthrough;
+       case 2: b |= le16_to_cpup(data); break;
+       case 1: b |= end[0];
+       }
+#endif
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_aligned);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len,
+                        const hsiphash_key_t *key)
+{
+       const u8 *end = data + len - (len % sizeof(u64));
+       const u8 left = len & (sizeof(u64) - 1);
+       u64 m;
+       HPREAMBLE(len)
+       for (; data != end; data += sizeof(u64)) {
+               m = get_unaligned_le64(data);
+               v3 ^= m;
+               HSIPROUND;
+               v0 ^= m;
+       }
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+       if (left)
+               b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+                                                 bytemask_from_count(left)));
+#else
+       switch (left) {
+       case 7: b |= ((u64)end[6]) << 48; fallthrough;
+       case 6: b |= ((u64)end[5]) << 40; fallthrough;
+       case 5: b |= ((u64)end[4]) << 32; fallthrough;
+       case 4: b |= get_unaligned_le32(end); break;
+       case 3: b |= ((u64)end[2]) << 16; fallthrough;
+       case 2: b |= get_unaligned_le16(end); break;
+       case 1: b |= end[0];
+       }
+#endif
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_unaligned);
+#endif
+
+/**
+ * hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32
+ * @first: first u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key)
+{
+       HPREAMBLE(4)
+       b |= first;
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_1u32);
+
+/**
+ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
+ * @first: first u32
+ * @second: second u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key)
+{
+       u64 combined = (u64)second << 32 | first;
+       HPREAMBLE(8)
+       v3 ^= combined;
+       HSIPROUND;
+       v0 ^= combined;
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_2u32);
+
+/**
+ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
+                 const hsiphash_key_t *key)
+{
+       u64 combined = (u64)second << 32 | first;
+       HPREAMBLE(12)
+       v3 ^= combined;
+       HSIPROUND;
+       v0 ^= combined;
+       b |= third;
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_3u32);
+
+/**
+ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @forth: forth u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
+                 const u32 forth, const hsiphash_key_t *key)
+{
+       u64 combined = (u64)second << 32 | first;
+       HPREAMBLE(16)
+       v3 ^= combined;
+       HSIPROUND;
+       v0 ^= combined;
+       combined = (u64)forth << 32 | third;
+       v3 ^= combined;
+       HSIPROUND;
+       v0 ^= combined;
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_4u32);
+#else
+#define HSIPROUND \
+       do { \
+       v0 += v1; v1 = rol32(v1, 5); v1 ^= v0; v0 = rol32(v0, 16); \
+       v2 += v3; v3 = rol32(v3, 8); v3 ^= v2; \
+       v0 += v3; v3 = rol32(v3, 7); v3 ^= v0; \
+       v2 += v1; v1 = rol32(v1, 13); v1 ^= v2; v2 = rol32(v2, 16); \
+       } while (0)
+
+#define HPREAMBLE(len) \
+       u32 v0 = 0; \
+       u32 v1 = 0; \
+       u32 v2 = 0x6c796765U; \
+       u32 v3 = 0x74656462U; \
+       u32 b = ((u32)(len)) << 24; \
+       v3 ^= key->key[1]; \
+       v2 ^= key->key[0]; \
+       v1 ^= key->key[1]; \
+       v0 ^= key->key[0];
+
+#define HPOSTAMBLE \
+       v3 ^= b; \
+       HSIPROUND; \
+       v0 ^= b; \
+       v2 ^= 0xff; \
+       HSIPROUND; \
+       HSIPROUND; \
+       HSIPROUND; \
+       return v1 ^ v3;
+
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
+{
+       const u8 *end = data + len - (len % sizeof(u32));
+       const u8 left = len & (sizeof(u32) - 1);
+       u32 m;
+       HPREAMBLE(len)
+       for (; data != end; data += sizeof(u32)) {
+               m = le32_to_cpup(data);
+               v3 ^= m;
+               HSIPROUND;
+               v0 ^= m;
+       }
+       switch (left) {
+       case 3: b |= ((u32)end[2]) << 16; fallthrough;
+       case 2: b |= le16_to_cpup(data); break;
+       case 1: b |= end[0];
+       }
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_aligned);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len,
+                        const hsiphash_key_t *key)
+{
+       const u8 *end = data + len - (len % sizeof(u32));
+       const u8 left = len & (sizeof(u32) - 1);
+       u32 m;
+       HPREAMBLE(len)
+       for (; data != end; data += sizeof(u32)) {
+               m = get_unaligned_le32(data);
+               v3 ^= m;
+               HSIPROUND;
+               v0 ^= m;
+       }
+       switch (left) {
+       case 3: b |= ((u32)end[2]) << 16; fallthrough;
+       case 2: b |= get_unaligned_le16(end); break;
+       case 1: b |= end[0];
+       }
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_unaligned);
+#endif
+
+/**
+ * hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32
+ * @first: first u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key)
+{
+       HPREAMBLE(4)
+       v3 ^= first;
+       HSIPROUND;
+       v0 ^= first;
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_1u32);
+
+/**
+ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
+ * @first: first u32
+ * @second: second u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key)
+{
+       HPREAMBLE(8)
+       v3 ^= first;
+       HSIPROUND;
+       v0 ^= first;
+       v3 ^= second;
+       HSIPROUND;
+       v0 ^= second;
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_2u32);
+
+/**
+ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
+                 const hsiphash_key_t *key)
+{
+       HPREAMBLE(12)
+       v3 ^= first;
+       HSIPROUND;
+       v0 ^= first;
+       v3 ^= second;
+       HSIPROUND;
+       v0 ^= second;
+       v3 ^= third;
+       HSIPROUND;
+       v0 ^= third;
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_3u32);
+
+/**
+ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @forth: forth u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
+                 const u32 forth, const hsiphash_key_t *key)
+{
+       HPREAMBLE(16)
+       v3 ^= first;
+       HSIPROUND;
+       v0 ^= first;
+       v3 ^= second;
+       HSIPROUND;
+       v0 ^= second;
+       v3 ^= third;
+       HSIPROUND;
+       v0 ^= third;
+       v3 ^= forth;
+       HSIPROUND;
+       v0 ^= forth;
+       HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_4u32);
+#endif