summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2015-08-21 00:31:48 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-10-07 09:20:53 -0800
commitf8dc664ea9d6cb6ee99ba27340bff475aba8a306 (patch)
tree1780516832bc2058d739546bd95d863c3a4affc3
parent67946cfae71f53429f51f70a924180dcd9e86413 (diff)
bcache: selectable checksum type
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--drivers/md/bcache/Kconfig1
-rw-r--r--drivers/md/bcache/bcache.h18
-rw-r--r--drivers/md/bcache/btree.c9
-rw-r--r--drivers/md/bcache/journal.c6
-rw-r--r--drivers/md/bcache/request.c7
-rw-r--r--drivers/md/bcache/super.c68
-rw-r--r--drivers/md/bcache/sysfs.c38
-rw-r--r--drivers/md/bcache/util.c9
8 files changed, 117 insertions, 39 deletions
diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig
index 4d200883c505..9df7ce5fba48 100644
--- a/drivers/md/bcache/Kconfig
+++ b/drivers/md/bcache/Kconfig
@@ -1,6 +1,7 @@
config BCACHE
tristate "Block device as cache"
+ select LIBCRC32C
---help---
Allows a block device to be used as cache for other devices; uses
a btree for indexing and the layout is optimized for SSDs.
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 6102f4e0f281..b81f9071da0f 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -179,6 +179,7 @@
#include <linux/bcache.h>
#include <linux/bio.h>
+#include <linux/crc32c.h>
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/mutex.h>
@@ -960,16 +961,22 @@ static inline u8 ptr_stale(struct cache_set *c, struct cache *ca,
return gen_after(PTR_BUCKET_GEN(c, ca, k, ptr), PTR_GEN(k, ptr));
}
-/* Btree key macros */
+/* checksumming */
+
+u64 bch_checksum_update(unsigned, u64, const void *, size_t);
+u64 bch_checksum(unsigned, const void *, size_t);
/*
* This is used for various on disk data structures - cache_sb, prio_set, bset,
* jset: The checksum is _always_ the first 8 bytes of these structs
*/
-#define csum_set(i) \
- bch_crc64(((void *) (i)) + sizeof(uint64_t), \
- ((void *) bset_bkey_last(i)) - \
- (((void *) (i)) + sizeof(uint64_t)))
+#define csum_set(i, type) \
+({ \
+ void *start = ((void *) (i)) + sizeof(u64); \
+ void *end = bset_bkey_last(i); \
+ \
+ bch_checksum(type, start, end - start); \
+})
/* Error handling macros */
@@ -1104,7 +1111,6 @@ void bch_write_bdev_super(struct cached_dev *, struct closure *);
struct bcache_device *bch_dev_get_by_inode(struct cache_set *, u64);
extern struct workqueue_struct *bcache_io_wq;
-extern const char * const bch_cache_modes[];
extern struct mutex bch_register_lock;
extern struct list_head bch_cache_sets;
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index b9f22fd42a1d..2396a686d69c 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -219,7 +219,8 @@ static u64 btree_csum_set(struct btree *b, struct bset *i)
u64 crc = b->key.val[0];
void *data = (void *) i + 8, *end = bset_bkey_last(i);
- crc = bch_crc64_update(crc, data, end - data);
+ crc = bch_checksum_update(BSET_CSUM_TYPE(i), crc, data, end - data);
+
return crc ^ 0xffffffffffffffffULL;
}
@@ -266,6 +267,10 @@ void bch_btree_node_read_done(struct btree *b)
if (i->magic != bset_magic(&b->c->sb))
goto err;
+ err = "unknown checksum type";
+ if (BSET_CSUM_TYPE(i) >= BCH_CSUM_NR)
+ goto err;
+
err = "bad checksum";
if (i->csum != btree_csum_set(b, i))
goto err;
@@ -456,6 +461,8 @@ static void do_btree_node_write(struct btree *b)
int n;
i->version = BCACHE_BSET_VERSION;
+
+ SET_BSET_CSUM_TYPE(i, CACHE_PREFERRED_CSUM_TYPE(&b->c->sb));
i->csum = btree_csum_set(b, i);
BUG_ON(b->bio);
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index b881bc468a9f..1e38e2cbcfdb 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -156,7 +156,7 @@ reread: left = ca->sb.bucket_size - offset;
if (bytes > len << 9)
goto reread;
- if (j->csum != csum_set(j)) {
+ if (j->csum != csum_set(j, JSET_CSUM_TYPE(j))) {
pr_info("%u: bad csum, %zu bytes, offset %u",
bucket_index, bytes, offset);
return ret;
@@ -741,7 +741,9 @@ static void journal_write_locked(struct closure *cl)
w->data->magic = jset_magic(&c->sb);
w->data->version = BCACHE_JSET_VERSION;
w->data->last_seq = last_seq(&c->journal);
- w->data->csum = csum_set(w->data);
+
+ SET_JSET_CSUM_TYPE(w->data, CACHE_PREFERRED_CSUM_TYPE(&c->sb));
+ w->data->csum = csum_set(w->data, JSET_CSUM_TYPE(w->data));
sectors = set_blocks(w->data, block_bytes(c)) * c->sb.block_size;
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 1764ebc1b874..f05a73dfdcbd 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -89,15 +89,16 @@ static void bio_csum(struct bio *bio, struct bkey *k)
{
struct bio_vec bv;
struct bvec_iter iter;
- uint64_t csum = 0;
+ u64 crc = 0xffffffffffffffffULL;
bio_for_each_segment(bv, bio, iter) {
void *d = kmap(bv.bv_page) + bv.bv_offset;
- csum = bch_crc64_update(csum, d, bv.bv_len);
+
+ crc = bch_checksum_update(KEY_CSUM(k), crc, d, bv.bv_len);
kunmap(bv.bv_page);
}
- k->val[bch_extent_ptrs(k)] = csum & (~0ULL >> 1);
+ k->val[bch_extent_ptrs(k)] = crc;
}
/* Insert data into cache */
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index a7134e5fa47c..cec6e2037841 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -39,16 +39,6 @@ static const uuid_le invalid_uuid = {
}
};
-/* Default is -1; we skip past it for struct cached_dev's cache mode */
-const char * const bch_cache_modes[] = {
- "default",
- "writethrough",
- "writeback",
- "writearound",
- "none",
- NULL
-};
-
static struct kobject *bcache_kobj;
struct mutex bch_register_lock;
LIST_HEAD(bch_cache_sets);
@@ -63,6 +53,29 @@ static void __bch_cache_remove(struct cache *);
#define BTREE_MAX_PAGES (256 * 1024 / PAGE_SIZE)
+u64 bch_checksum_update(unsigned type, u64 crc, const void *data, size_t len)
+{
+ switch (type) {
+ case BCH_CSUM_NONE:
+ return 0;
+ case BCH_CSUM_CRC32C:
+ return crc32c(crc, data, len);
+ case BCH_CSUM_CRC64:
+ return bch_crc64_update(crc, data, len);
+ default:
+ BUG();
+ }
+}
+
+u64 bch_checksum(unsigned type, const void *data, size_t len)
+{
+ u64 crc = 0xffffffffffffffffULL;
+
+ crc = bch_checksum_update(type, crc, data, len);
+
+ return crc ^ 0xffffffffffffffffULL;
+}
+
struct bcache_device *bch_dev_get_by_inode(struct cache_set *c, u64 inode)
{
struct bcache_device *d;
@@ -161,6 +174,10 @@ static const char *validate_super(struct bcache_superblock *disk_sb,
if (sb->keys < bch_journal_buckets_offset(sb))
goto err;
+ err = "Invalid checksum type";
+ if (CACHE_SB_CSUM_TYPE(sb) >= BCH_CSUM_NR)
+ goto err;
+
break;
default:
err = "Unsupported superblock version";
@@ -268,7 +285,11 @@ retry:
if (order > sb->page_order)
goto retry;
- if (sb->sb->csum != csum_set(sb->sb))
+ if (sb->sb->csum != csum_set(sb->sb,
+ le64_to_cpu(sb->sb->version) <
+ BCACHE_SB_VERSION_CDEV_V3
+ ? BCH_CSUM_CRC64
+ : CACHE_SB_CSUM_TYPE(sb->sb)))
return "Bad checksum";
if (cache_set_init_fault("read_super"))
@@ -312,7 +333,10 @@ static void __write_super(struct bcache_superblock *disk_sb,
out->last_mount = cpu_to_le32(sb->last_mount);
out->first_bucket = cpu_to_le16(sb->first_bucket);
out->keys = cpu_to_le16(sb->keys);
- out->csum = csum_set(out);
+ out->csum =
+ csum_set(out, sb->version < BCACHE_SB_VERSION_CDEV_V3
+ ? BCH_CSUM_CRC64
+ : CACHE_SB_CSUM_TYPE(sb));
pr_debug("ver %llu, flags %llu, seq %llu",
sb->version, sb->flags, sb->seq);
@@ -398,11 +422,10 @@ static void cache_sb_from_cache_set(struct cache_set *c, struct cache *ca)
ca->sb.nr_in_set * sizeof(struct cache_member));
ca->sb.version = BCACHE_SB_VERSION_CDEV;
+ ca->sb.flags = c->sb.flags;
ca->sb.seq = c->sb.seq;
ca->sb.nr_in_set = c->sb.nr_in_set;
ca->sb.last_mount = c->sb.last_mount;
-
- SET_CACHE_SYNC(&ca->sb, CACHE_SYNC(&c->sb));
}
void bcache_write_super(struct cache_set *c)
@@ -421,6 +444,9 @@ void bcache_write_super(struct cache_set *c)
cache_sb_from_cache_set(c, ca);
+ SET_CACHE_SB_CSUM_TYPE(&ca->sb,
+ CACHE_PREFERRED_CSUM_TYPE(&c->sb));
+
bio_reset(bio);
bio->bi_bdev = ca->bdev;
bio->bi_end_io = write_super_endio;
@@ -523,7 +549,11 @@ void bch_prio_write(struct cache *ca)
p->next_bucket = ca->prio_buckets[i + 1];
p->magic = pset_magic(&ca->sb);
- p->csum = bch_crc64(&p->magic, bucket_bytes(ca) - 8);
+
+ SET_PSET_CSUM_TYPE(p, CACHE_PREFERRED_CSUM_TYPE(&ca->set->sb));
+ p->csum = bch_checksum(PSET_CSUM_TYPE(p),
+ &p->magic,
+ bucket_bytes(ca) - 8);
r = bch_bucket_alloc(ca, RESERVE_PRIO, NULL);
BUG_ON(r < 0);
@@ -582,12 +612,14 @@ static void prio_read(struct cache *ca, uint64_t bucket)
prio_io(ca, bucket, REQ_OP_READ, READ_SYNC);
- if (p->csum != bch_crc64(&p->magic, bucket_bytes(ca) - 8))
- pr_warn("bad csum reading priorities");
-
if (p->magic != pset_magic(&ca->sb))
pr_warn("bad magic reading priorities");
+ if (p->csum != bch_checksum(PSET_CSUM_TYPE(p),
+ &p->magic,
+ bucket_bytes(ca) - 8))
+ pr_warn("bad csum reading priorities");
+
bucket = p->next_bucket;
d = p->data;
}
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index 2ac1800dfffa..1c42dda99bcc 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -15,6 +15,13 @@
#include <linux/blkdev.h>
#include <linux/sort.h>
+static const char * const bch_csum_types[] = {
+ "none",
+ "crc32c",
+ "crc64",
+ NULL
+};
+
static const char * const cache_replacement_policies[] = {
"lru",
"fifo",
@@ -22,6 +29,16 @@ static const char * const cache_replacement_policies[] = {
NULL
};
+/* Default is -1; we skip past it for struct cached_dev's cache mode */
+static const char * const bch_cache_modes[] = {
+ "default",
+ "writethrough",
+ "writeback",
+ "writearound",
+ "none",
+ NULL
+};
+
static const char * const error_actions[] = {
"unregister",
"panic",
@@ -113,6 +130,7 @@ rw_attribute(key_merging_disabled);
rw_attribute(gc_always_rewrite);
rw_attribute(expensive_debug_checks);
rw_attribute(cache_replacement_policy);
+rw_attribute(checksum_type);
rw_attribute(btree_shrinker_disabled);
rw_attribute(copy_gc_enabled);
@@ -528,6 +546,11 @@ SHOW(__bch_cache_set)
sysfs_print(writeback_keys_failed,
atomic_long_read(&c->writeback_keys_failed));
+ if (attr == &sysfs_checksum_type)
+ return bch_snprint_string_list(buf, PAGE_SIZE,
+ bch_csum_types,
+ CACHE_PREFERRED_CSUM_TYPE(&c->sb));
+
if (attr == &sysfs_errors)
return bch_snprint_string_list(buf, PAGE_SIZE, error_actions,
c->on_error);
@@ -680,6 +703,20 @@ STORE(__bch_cache_set)
if (test_bit(CACHE_SET_STOPPING, &c->flags))
return -EINTR;
+ if (attr == &sysfs_checksum_type) {
+ ssize_t v = bch_read_string_list(buf, bch_csum_types);
+
+ if (v < 0)
+ return v;
+
+ if (v != CACHE_PREFERRED_CSUM_TYPE(&c->sb)) {
+ SET_CACHE_PREFERRED_CSUM_TYPE(&c->sb, v);
+ bcache_write_super(c);
+ }
+
+ return size;
+ }
+
if (attr == &sysfs_flash_vol_create) {
int r;
u64 v;
@@ -747,6 +784,7 @@ static struct attribute *bch_cache_set_files[] = {
&sysfs_congested_write_threshold_us,
&sysfs_clear_stats,
+ &sysfs_checksum_type,
&sysfs_meta_replicas,
&sysfs_data_replicas,
diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c
index 2bd4044281bf..e758b4bf9aca 100644
--- a/drivers/md/bcache/util.c
+++ b/drivers/md/bcache/util.c
@@ -464,15 +464,6 @@ uint64_t bch_crc64_update(uint64_t crc, const void *_data, size_t len)
return crc;
}
-uint64_t bch_crc64(const void *data, size_t len)
-{
- uint64_t crc = 0xffffffffffffffffULL;
-
- crc = bch_crc64_update(crc, data, len);
-
- return crc ^ 0xffffffffffffffffULL;
-}
-
int bch_kthread_loop_ratelimit(unsigned long *last, unsigned long delay)
{
unsigned long next = *last + delay;