From 2903381fce71004a7ce24d40fad53ba8236a3921 Mon Sep 17 00:00:00 2001
From: Kent Overstreet <koverstreet@google.com>
Date: Thu, 11 Apr 2013 15:14:35 -0700
Subject: [PATCH] bcache: Take data offset from the bdev superblock.

Add a new superblock version, and consolidate related defines.

Signed-off-by: Gabriel de Perthuis <g2p.code+bcache@gmail.com>
Signed-off-by: Kent Overstreet <koverstreet@google.com>
---
 drivers/md/bcache/bcache.h  |  47 ++++++++++++----
 drivers/md/bcache/request.c |   2 +-
 drivers/md/bcache/super.c   | 108 +++++++++++++++++++++---------------
 3 files changed, 100 insertions(+), 57 deletions(-)

diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index f05723565f17..340146d7c17f 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -223,11 +223,17 @@ struct bkey {
 #define BKEY_PADDED(key)					\
 	union { struct bkey key; uint64_t key ## _pad[BKEY_PAD]; }
 
-/* Version 1: Backing device
+/* Version 0: Cache device
+ * Version 1: Backing device
  * Version 2: Seed pointer into btree node checksum
- * Version 3: New UUID format
+ * Version 3: Cache device with new UUID format
+ * Version 4: Backing device with data offset
  */
-#define BCACHE_SB_VERSION	3
+#define BCACHE_SB_VERSION_CDEV			0
+#define BCACHE_SB_VERSION_BDEV			1
+#define BCACHE_SB_VERSION_CDEV_WITH_UUID	3
+#define BCACHE_SB_VERSION_BDEV_WITH_OFFSET	4
+#define BCACHE_SB_MAX_VERSION			4
 
 #define SB_SECTOR		8
 #define SB_SIZE			4096
@@ -236,13 +242,12 @@ struct bkey {
 /* SB_JOURNAL_BUCKETS must be divisible by BITS_PER_LONG */
 #define MAX_CACHES_PER_SET	8
 
-#define BDEV_DATA_START		16	/* sectors */
+#define BDEV_DATA_START_DEFAULT	16	/* sectors */
 
 struct cache_sb {
 	uint64_t		csum;
 	uint64_t		offset;	/* sector where this sb was written */
 	uint64_t		version;
-#define CACHE_BACKING_DEV	1
 
 	uint8_t			magic[16];
 
@@ -257,12 +262,28 @@ struct cache_sb {
 	uint64_t		seq;
 	uint64_t		pad[8];
 
-	uint64_t		nbuckets;	/* device size */
-	uint16_t		block_size;	/* sectors */
-	uint16_t		bucket_size;	/* sectors */
+	union {
+	struct {
+		/* Cache devices */
+		uint64_t	nbuckets;	/* device size */
+
+		uint16_t	block_size;	/* sectors */
+		uint16_t	bucket_size;	/* sectors */
 
-	uint16_t		nr_in_set;
-	uint16_t		nr_this_dev;
+		uint16_t	nr_in_set;
+		uint16_t	nr_this_dev;
+	};
+	struct {
+		/* Backing devices */
+		uint64_t	data_offset;
+
+		/*
+		 * block_size from the cache device section is still used by
+		 * backing devices, so don't add anything here until we fix
+		 * things to not need it for backing devices anymore
+		 */
+	};
+	};
 
 	uint32_t		last_mount;	/* time_t */
 
@@ -861,6 +882,12 @@ static inline bool key_merging_disabled(struct cache_set *c)
 #endif
 }
 
+static inline bool SB_IS_BDEV(const struct cache_sb *sb)
+{
+	return sb->version == BCACHE_SB_VERSION_BDEV
+		|| sb->version == BCACHE_SB_VERSION_BDEV_WITH_OFFSET;
+}
+
 struct bbio {
 	unsigned		submit_time_us;
 	union {
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 83731dc36f34..e5ff12e52d5b 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -1220,7 +1220,7 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio)
 	part_stat_unlock();
 
 	bio->bi_bdev = dc->bdev;
-	bio->bi_sector += BDEV_DATA_START;
+	bio->bi_sector += dc->sb.data_offset;
 
 	if (cached_dev_get(dc)) {
 		s = search_alloc(bio, d);
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 5fa3cd2d9ff0..f1e69f2fad37 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -110,15 +110,7 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev,
 
 	sb->flags		= le64_to_cpu(s->flags);
 	sb->seq			= le64_to_cpu(s->seq);
-
-	sb->nbuckets		= le64_to_cpu(s->nbuckets);
-	sb->block_size		= le16_to_cpu(s->block_size);
-	sb->bucket_size		= le16_to_cpu(s->bucket_size);
-
-	sb->nr_in_set		= le16_to_cpu(s->nr_in_set);
-	sb->nr_this_dev		= le16_to_cpu(s->nr_this_dev);
 	sb->last_mount		= le32_to_cpu(s->last_mount);
-
 	sb->first_bucket	= le16_to_cpu(s->first_bucket);
 	sb->keys		= le16_to_cpu(s->keys);
 
@@ -147,53 +139,77 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev,
 	if (bch_is_zero(sb->uuid, 16))
 		goto err;
 
-	err = "Unsupported superblock version";
-	if (sb->version > BCACHE_SB_VERSION)
-		goto err;
+	switch (sb->version) {
+	case BCACHE_SB_VERSION_BDEV:
+		sb->block_size	= le16_to_cpu(s->block_size);
+		sb->data_offset	= BDEV_DATA_START_DEFAULT;
+		break;
+	case BCACHE_SB_VERSION_BDEV_WITH_OFFSET:
+		sb->block_size	= le16_to_cpu(s->block_size);
+		sb->data_offset	= le64_to_cpu(s->data_offset);
+
+		err = "Bad data offset";
+		if (sb->data_offset < BDEV_DATA_START_DEFAULT)
+			goto err;
 
-	err = "Bad block/bucket size";
-	if (!is_power_of_2(sb->block_size) || sb->block_size > PAGE_SECTORS ||
-	    !is_power_of_2(sb->bucket_size) || sb->bucket_size < PAGE_SECTORS)
-		goto err;
+		break;
+	case BCACHE_SB_VERSION_CDEV:
+	case BCACHE_SB_VERSION_CDEV_WITH_UUID:
+		sb->nbuckets	= le64_to_cpu(s->nbuckets);
+		sb->block_size	= le16_to_cpu(s->block_size);
+		sb->bucket_size	= le16_to_cpu(s->bucket_size);
 
-	err = "Too many buckets";
-	if (sb->nbuckets > LONG_MAX)
-		goto err;
+		sb->nr_in_set	= le16_to_cpu(s->nr_in_set);
+		sb->nr_this_dev	= le16_to_cpu(s->nr_this_dev);
 
-	err = "Not enough buckets";
-	if (sb->nbuckets < 1 << 7)
-		goto err;
+		err = "Too many buckets";
+		if (sb->nbuckets > LONG_MAX)
+			goto err;
 
-	err = "Invalid superblock: device too small";
-	if (get_capacity(bdev->bd_disk) < sb->bucket_size * sb->nbuckets)
-		goto err;
+		err = "Not enough buckets";
+		if (sb->nbuckets < 1 << 7)
+			goto err;
 
-	if (sb->version == CACHE_BACKING_DEV)
-		goto out;
+		err = "Bad block/bucket size";
+		if (!is_power_of_2(sb->block_size) ||
+		    sb->block_size > PAGE_SECTORS ||
+		    !is_power_of_2(sb->bucket_size) ||
+		    sb->bucket_size < PAGE_SECTORS)
+			goto err;
 
-	err = "Bad UUID";
-	if (bch_is_zero(sb->set_uuid, 16))
-		goto err;
+		err = "Invalid superblock: device too small";
+		if (get_capacity(bdev->bd_disk) < sb->bucket_size * sb->nbuckets)
+			goto err;
 
-	err = "Bad cache device number in set";
-	if (!sb->nr_in_set ||
-	    sb->nr_in_set <= sb->nr_this_dev ||
-	    sb->nr_in_set > MAX_CACHES_PER_SET)
-		goto err;
+		err = "Bad UUID";
+		if (bch_is_zero(sb->set_uuid, 16))
+			goto err;
 
-	err = "Journal buckets not sequential";
-	for (i = 0; i < sb->keys; i++)
-		if (sb->d[i] != sb->first_bucket + i)
+		err = "Bad cache device number in set";
+		if (!sb->nr_in_set ||
+		    sb->nr_in_set <= sb->nr_this_dev ||
+		    sb->nr_in_set > MAX_CACHES_PER_SET)
 			goto err;
 
-	err = "Too many journal buckets";
-	if (sb->first_bucket + sb->keys > sb->nbuckets)
-		goto err;
+		err = "Journal buckets not sequential";
+		for (i = 0; i < sb->keys; i++)
+			if (sb->d[i] != sb->first_bucket + i)
+				goto err;
 
-	err = "Invalid superblock: first bucket comes before end of super";
-	if (sb->first_bucket * sb->bucket_size < 16)
+		err = "Too many journal buckets";
+		if (sb->first_bucket + sb->keys > sb->nbuckets)
+			goto err;
+
+		err = "Invalid superblock: first bucket comes before end of super";
+		if (sb->first_bucket * sb->bucket_size < 16)
+			goto err;
+
+		break;
+	default:
+		err = "Unsupported superblock version";
 		goto err;
-out:
+	}
+
 	sb->last_mount = get_seconds();
 	err = NULL;
 
@@ -286,7 +302,7 @@ void bcache_write_super(struct cache_set *c)
 	for_each_cache(ca, c, i) {
 		struct bio *bio = &ca->sb_bio;
 
-		ca->sb.version		= BCACHE_SB_VERSION;
+		ca->sb.version		= BCACHE_SB_VERSION_CDEV_WITH_UUID;
 		ca->sb.seq		= c->sb.seq;
 		ca->sb.last_mount	= c->sb.last_mount;
 
@@ -1049,7 +1065,7 @@ static const char *register_bdev(struct cache_sb *sb, struct page *sb_page,
 
 	g = dc->disk.disk;
 
-	set_capacity(g, dc->bdev->bd_part->nr_sects - 16);
+	set_capacity(g, dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
 
 	bch_cached_dev_request_init(dc);
 
@@ -1802,7 +1818,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
 	if (err)
 		goto err_close;
 
-	if (sb->version == CACHE_BACKING_DEV) {
+	if (SB_IS_BDEV(sb)) {
 		struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
 
 		err = register_bdev(sb, sb_page, bdev, dc);
-- 
GitLab