diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2015-08-21 00:31:48 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2016-10-07 09:20:53 -0800 |
commit | f8dc664ea9d6cb6ee99ba27340bff475aba8a306 (patch) | |
tree | 1780516832bc2058d739546bd95d863c3a4affc3 | |
parent | 67946cfae71f53429f51f70a924180dcd9e86413 (diff) |
bcache: selectable checksum type
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | drivers/md/bcache/Kconfig | 1 | ||||
-rw-r--r-- | drivers/md/bcache/bcache.h | 18 | ||||
-rw-r--r-- | drivers/md/bcache/btree.c | 9 | ||||
-rw-r--r-- | drivers/md/bcache/journal.c | 6 | ||||
-rw-r--r-- | drivers/md/bcache/request.c | 7 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 68 | ||||
-rw-r--r-- | drivers/md/bcache/sysfs.c | 38 | ||||
-rw-r--r-- | drivers/md/bcache/util.c | 9 |
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; |