diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-05-02 22:46:47 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-01-18 21:39:26 -0900 |
commit | 8608df7eebff71325610ee94012d68f7bd6509b9 (patch) | |
tree | a25815f3674c2fc7fc063b605b8589abe95e0107 | |
parent | 096f397c5a4038d6fa14fc048eb315e83699c0d0 (diff) |
fix bch_cache_set_add_cache
-rw-r--r-- | drivers/md/bcache/btree_gc.c | 4 | ||||
-rw-r--r-- | drivers/md/bcache/journal.c | 10 | ||||
-rw-r--r-- | drivers/md/bcache/journal.h | 12 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 67 |
4 files changed, 53 insertions, 40 deletions
diff --git a/drivers/md/bcache/btree_gc.c b/drivers/md/bcache/btree_gc.c index c63ab60a116f..cd1c5c2aac20 100644 --- a/drivers/md/bcache/btree_gc.c +++ b/drivers/md/bcache/btree_gc.c @@ -267,8 +267,8 @@ static void bch_mark_metadata(struct cache_set *c) for (j = 0; j < bch_nr_journal_buckets(ca->disk_sb.sb); j++) bch_mark_metadata_bucket(ca, - &ca->buckets[journal_bucket(ca, j)], - true); + &ca->buckets[journal_bucket(ca->disk_sb.sb, j)], + true); spin_lock(&ca->prio_buckets_lock); diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index ccfc5a0beddf..baf0f92b0b41 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -421,7 +421,8 @@ static int journal_read_bucket(struct cache *ca, struct journal_list *jlist, struct bio *bio = &ja->bio; struct jset *j, *data; unsigned blocks, sectors_read, bucket_offset = 0; - u64 sector = bucket_to_sector(ca, journal_bucket(ca, bucket)); + u64 sector = bucket_to_sector(ca, + journal_bucket(ca->disk_sb.sb, bucket)); bool entries_found = false; int ret = 0; @@ -1270,7 +1271,7 @@ int bch_cache_journal_alloc(struct cache *ca) unsigned long r = ca->mi.first_bucket + i; bch_mark_metadata_bucket(ca, &ca->buckets[r], true); - set_journal_bucket(ca, i, r); + set_journal_bucket(ca->disk_sb.sb, i, r); } return 0; @@ -1402,7 +1403,7 @@ static void journal_reclaim_work(struct work_struct *work) blk_queue_discard(bdev_get_queue(ca->disk_sb.bdev))) blkdev_issue_discard(ca->disk_sb.bdev, bucket_to_sector(ca, - journal_bucket(ca, + journal_bucket(ca->disk_sb.sb, ja->last_idx)), ca->mi.bucket_size, GFP_NOIO, 0); @@ -1497,7 +1498,8 @@ static int journal_write_alloc(struct journal *j, unsigned sectors) extent_ptr_append(bkey_i_to_extent(&j->key), (struct bch_extent_ptr) { .offset = bucket_to_sector(ca, - journal_bucket(ca, ja->cur_idx)), + journal_bucket(ca->disk_sb.sb, + ja->cur_idx)), .dev = ca->sb.nr_this_dev, }); replicas++; diff --git a/drivers/md/bcache/journal.h b/drivers/md/bcache/journal.h index c54087472b90..b128ee0d148d 100644 --- a/drivers/md/bcache/journal.h +++ b/drivers/md/bcache/journal.h @@ -231,19 +231,19 @@ ssize_t bch_journal_print_debug(struct journal *, char *); int bch_cache_journal_alloc(struct cache *); -static inline __le64 *__journal_buckets(struct cache *ca) +static inline __le64 *__journal_buckets(struct cache_sb *sb) { - return ca->disk_sb.sb->_data + bch_journal_buckets_offset(ca->disk_sb.sb); + return sb->_data + bch_journal_buckets_offset(sb); } -static inline u64 journal_bucket(struct cache *ca, unsigned nr) +static inline u64 journal_bucket(struct cache_sb *sb, unsigned nr) { - return le64_to_cpu(__journal_buckets(ca)[nr]); + return le64_to_cpu(__journal_buckets(sb)[nr]); } -static inline void set_journal_bucket(struct cache *ca, unsigned nr, u64 bucket) +static inline void set_journal_bucket(struct cache_sb *sb, unsigned nr, u64 bucket) { - __journal_buckets(ca)[nr] = cpu_to_le64(bucket); + __journal_buckets(sb)[nr] = cpu_to_le64(bucket); } int bch_journal_move(struct cache *); diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 4aa5aa0abbd9..2b934e67a944 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -203,9 +203,10 @@ static struct cache_member_cpu cache_mi_to_cpu_mi(struct cache_member *mi) }; } -static const char *validate_cache_super(struct cache_set *c, struct cache *ca) +static const char *validate_cache_super(struct bcache_superblock *disk_sb) { - struct cache_sb *sb = ca->disk_sb.sb; + struct cache_sb *sb = disk_sb->sb; + struct cache_member_cpu mi; u16 block_size; unsigned i; @@ -276,34 +277,32 @@ static const char *validate_cache_super(struct cache_set *c, struct cache *ca) if (le16_to_cpu(sb->u64s) < bch_journal_buckets_offset(sb)) return "Invalid superblock: member info area missing"; - ca->mi = cache_mi_to_cpu_mi(sb->members + sb->nr_this_dev); + mi = cache_mi_to_cpu_mi(sb->members + sb->nr_this_dev); - if (ca->mi.nbuckets > LONG_MAX) + if (mi.nbuckets > LONG_MAX) return "Too many buckets"; - if (ca->mi.nbuckets < 1 << 8) + if (mi.nbuckets < 1 << 8) return "Not enough buckets"; - if (!is_power_of_2(ca->mi.bucket_size) || - ca->mi.bucket_size < PAGE_SECTORS || - ca->mi.bucket_size < block_size) + if (!is_power_of_2(mi.bucket_size) || + mi.bucket_size < PAGE_SECTORS || + mi.bucket_size < block_size) return "Bad bucket size"; - ca->bucket_bits = ilog2(ca->mi.bucket_size); - - if (get_capacity(ca->disk_sb.bdev->bd_disk) < - ca->mi.bucket_size * ca->mi.nbuckets) + if (get_capacity(disk_sb->bdev->bd_disk) < + mi.bucket_size * mi.nbuckets) return "Invalid superblock: device too small"; if (le64_to_cpu(sb->offset) + (__set_blocks(sb, le16_to_cpu(sb->u64s), - block_bytes(c)) << c->block_bits) > - ca->mi.first_bucket << ca->bucket_bits) + block_size << 9) * block_size) > + mi.first_bucket * mi.bucket_size) return "Invalid superblock: first bucket comes before end of super"; for (i = 0; i < bch_nr_journal_buckets(sb); i++) - if (journal_bucket(ca, i) < ca->mi.first_bucket || - journal_bucket(ca, i) >= ca->mi.nbuckets) + if (journal_bucket(sb, i) < mi.first_bucket || + journal_bucket(sb, i) >= mi.nbuckets) return "bad journal bucket"; return NULL; @@ -1877,6 +1876,10 @@ static const char *cache_alloc(struct bcache_superblock *sb, if (c->sb.nr_in_set == 1) bdevname(sb->bdev, c->name); + err = validate_cache_super(sb); + if (err) + return err; + if (cache_set_init_fault("cache_alloc")) return err; @@ -1916,9 +1919,9 @@ static const char *cache_alloc(struct bcache_superblock *sb, if (cache_set_init_fault("cache_alloc")) goto err; - err = validate_cache_super(c, ca); - if (err) - goto err; + ca->mi = cache_mi_to_cpu_mi(ca->disk_sb.sb->members + + ca->disk_sb.sb->nr_this_dev); + ca->bucket_bits = ilog2(ca->mi.bucket_size); /* XXX: tune these */ movinggc_reserve = max_t(size_t, NUM_GC_GENS * 2, @@ -2059,7 +2062,7 @@ int bch_cache_set_add_cache(struct cache_set *c, const char *path) struct bcache_superblock sb; const char *err; struct cache *ca; - struct cache_member *new_mi; + struct cache_member *new_mi = NULL; struct cache_member mi; unsigned nr_this_dev, nr_in_set, u64s; int ret = -EINVAL; @@ -2070,6 +2073,10 @@ int bch_cache_set_add_cache(struct cache_set *c, const char *path) if (err) goto err_unlock; + err = validate_cache_super(&sb); + if (err) + goto err_unlock; + err = can_add_cache(sb.sb, c); if (err) goto err_unlock; @@ -2112,10 +2119,6 @@ have_slot: if (bch_super_realloc(&sb, u64s)) goto err_unlock; - sb.sb->nr_this_dev = nr_this_dev; - sb.sb->nr_in_set = nr_in_set; - sb.sb->u64s = cpu_to_le16(u64s); - new_mi = dynamic_fault("bcache:add:member_info_realloc") ? NULL : kmalloc(sizeof(struct cache_member) * nr_in_set, @@ -2127,9 +2130,15 @@ have_slot: } memcpy(new_mi, c->disk_mi, - sizeof(struct cache_member) * c->sb.nr_in_set); + sizeof(struct cache_member) * nr_in_set); new_mi[nr_this_dev] = mi; + sb.sb->nr_this_dev = nr_this_dev; + sb.sb->nr_in_set = nr_in_set; + sb.sb->u64s = cpu_to_le16(u64s); + memcpy(sb.sb->members, new_mi, + sizeof(struct cache_member) * nr_in_set); + if (cache_set_mi_update(c, new_mi, nr_in_set)) { err = "cannot allocate memory"; ret = -ENOMEM; @@ -2137,8 +2146,9 @@ have_slot: } /* commit new member info */ - kfree(c->disk_mi); - c->disk_mi = new_mi; + swap(c->disk_mi, new_mi); + kfree(new_mi); + new_mi = NULL; c->disk_sb.nr_in_set = nr_in_set; c->sb.nr_in_set = nr_in_set; @@ -2164,8 +2174,9 @@ have_slot: err_put: bch_cache_stop(ca); err_unlock: - mutex_unlock(&bch_register_lock); + kfree(new_mi); free_super(&sb); + mutex_unlock(&bch_register_lock); bch_err(c, "Unable to add device: %s", err); return ret ?: -EINVAL; |