summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2016-05-02 22:46:47 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-10-07 12:36:26 -0800
commit5a48df1974fbf518bb48fe26ea3284059de27b5e (patch)
tree5cccbba91c4c7a487ef4de6f6217518f9a78861e
parent674494d51635cbde844e7583710292f094164bc5 (diff)
fix bch_cache_set_add_cache
-rw-r--r--drivers/md/bcache/btree_gc.c4
-rw-r--r--drivers/md/bcache/journal.c10
-rw-r--r--drivers/md/bcache/journal.h12
-rw-r--r--drivers/md/bcache/super.c67
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;