bcache: increase super block version for cache device and backing device
[platform/kernel/linux-starfive.git] / drivers / md / bcache / super.c
index a234c4c..c6ef410 100644 (file)
@@ -13,6 +13,7 @@
 #include "extents.h"
 #include "request.h"
 #include "writeback.h"
+#include "features.h"
 
 #include <linux/blkdev.h>
 #include <linux/debugfs.h>
@@ -79,11 +80,20 @@ static const char *read_super_common(struct cache_sb *sb,  struct block_device *
        if (sb->nbuckets < 1 << 7)
                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)
+       err = "Bad block size (not power of 2)";
+       if (!is_power_of_2(sb->block_size))
+               goto err;
+
+       err = "Bad block size (larger than page size)";
+       if (sb->block_size > PAGE_SECTORS)
+               goto err;
+
+       err = "Bad bucket size (not power of 2)";
+       if (!is_power_of_2(sb->bucket_size))
+               goto err;
+
+       err = "Bad bucket size (smaller than page size)";
+       if (sb->bucket_size < PAGE_SECTORS)
                goto err;
 
        err = "Invalid superblock: device too small";
@@ -185,6 +195,7 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev,
                sb->data_offset = BDEV_DATA_START_DEFAULT;
                break;
        case BCACHE_SB_VERSION_BDEV_WITH_OFFSET:
+       case BCACHE_SB_VERSION_BDEV_WITH_FEATURES:
                sb->data_offset = le64_to_cpu(s->data_offset);
 
                err = "Bad data offset";
@@ -198,6 +209,14 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev,
                if (err)
                        goto err;
                break;
+       case BCACHE_SB_VERSION_CDEV_WITH_FEATURES:
+               err = read_super_common(sb, bdev, s);
+               if (err)
+                       goto err;
+               sb->feature_compat = le64_to_cpu(s->feature_compat);
+               sb->feature_incompat = le64_to_cpu(s->feature_incompat);
+               sb->feature_ro_compat = le64_to_cpu(s->feature_ro_compat);
+               break;
        default:
                err = "Unsupported superblock version";
                goto err;
@@ -232,7 +251,6 @@ static void __write_super(struct cache_sb *sb, struct cache_sb_disk *out,
                        offset_in_page(out));
 
        out->offset             = cpu_to_le64(sb->offset);
-       out->version            = cpu_to_le64(sb->version);
 
        memcpy(out->uuid,       sb->uuid, 16);
        memcpy(out->set_uuid,   sb->set_uuid, 16);
@@ -248,6 +266,13 @@ static void __write_super(struct cache_sb *sb, struct cache_sb_disk *out,
        for (i = 0; i < sb->keys; i++)
                out->d[i] = cpu_to_le64(sb->d[i]);
 
+       if (sb->version >= BCACHE_SB_VERSION_CDEV_WITH_FEATURES) {
+               out->feature_compat    = cpu_to_le64(sb->feature_compat);
+               out->feature_incompat  = cpu_to_le64(sb->feature_incompat);
+               out->feature_ro_compat = cpu_to_le64(sb->feature_ro_compat);
+       }
+
+       out->version            = cpu_to_le64(sb->version);
        out->csum = csum_set(out);
 
        pr_debug("ver %llu, flags %llu, seq %llu\n",
@@ -304,17 +329,20 @@ void bcache_write_super(struct cache_set *c)
 {
        struct closure *cl = &c->sb_write;
        struct cache *ca;
-       unsigned int i;
+       unsigned int i, version = BCACHE_SB_VERSION_CDEV_WITH_UUID;
 
        down(&c->sb_write_mutex);
        closure_init(cl, &c->cl);
 
        c->sb.seq++;
 
+       if (c->sb.version > version)
+               version = c->sb.version;
+
        for_each_cache(ca, c, i) {
                struct bio *bio = &ca->sb_bio;
 
-               ca->sb.version          = BCACHE_SB_VERSION_CDEV_WITH_UUID;
+               ca->sb.version          = version;
                ca->sb.seq              = c->sb.seq;
                ca->sb.last_mount       = c->sb.last_mount;
 
@@ -1830,6 +1858,13 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
        c->sb.bucket_size       = sb->bucket_size;
        c->sb.nr_in_set         = sb->nr_in_set;
        c->sb.last_mount        = sb->last_mount;
+       c->sb.version           = sb->version;
+       if (c->sb.version >= BCACHE_SB_VERSION_CDEV_WITH_FEATURES) {
+               c->sb.feature_compat = sb->feature_compat;
+               c->sb.feature_ro_compat = sb->feature_ro_compat;
+               c->sb.feature_incompat = sb->feature_incompat;
+       }
+
        c->bucket_bits          = ilog2(sb->bucket_size);
        c->block_bits           = ilog2(sb->block_size);
        c->nr_uuids             = bucket_bytes(c) / sizeof(struct uuid_entry);
@@ -1864,21 +1899,43 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
        iter_size = (sb->bucket_size / sb->block_size + 1) *
                sizeof(struct btree_iter_set);
 
-       if (!(c->devices = kcalloc(c->nr_uuids, sizeof(void *), GFP_KERNEL)) ||
-           mempool_init_slab_pool(&c->search, 32, bch_search_cache) ||
-           mempool_init_kmalloc_pool(&c->bio_meta, 2,
-                               sizeof(struct bbio) + sizeof(struct bio_vec) *
-                               bucket_pages(c)) ||
-           mempool_init_kmalloc_pool(&c->fill_iter, 1, iter_size) ||
-           bioset_init(&c->bio_split, 4, offsetof(struct bbio, bio),
-                       BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER) ||
-           !(c->uuids = alloc_bucket_pages(GFP_KERNEL, c)) ||
-           !(c->moving_gc_wq = alloc_workqueue("bcache_gc",
-                                               WQ_MEM_RECLAIM, 0)) ||
-           bch_journal_alloc(c) ||
-           bch_btree_cache_alloc(c) ||
-           bch_open_buckets_alloc(c) ||
-           bch_bset_sort_state_init(&c->sort, ilog2(c->btree_pages)))
+       c->devices = kcalloc(c->nr_uuids, sizeof(void *), GFP_KERNEL);
+       if (!c->devices)
+               goto err;
+
+       if (mempool_init_slab_pool(&c->search, 32, bch_search_cache))
+               goto err;
+
+       if (mempool_init_kmalloc_pool(&c->bio_meta, 2,
+                       sizeof(struct bbio) +
+                       sizeof(struct bio_vec) * bucket_pages(c)))
+               goto err;
+
+       if (mempool_init_kmalloc_pool(&c->fill_iter, 1, iter_size))
+               goto err;
+
+       if (bioset_init(&c->bio_split, 4, offsetof(struct bbio, bio),
+                       BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER))
+               goto err;
+
+       c->uuids = alloc_bucket_pages(GFP_KERNEL, c);
+       if (!c->uuids)
+               goto err;
+
+       c->moving_gc_wq = alloc_workqueue("bcache_gc", WQ_MEM_RECLAIM, 0);
+       if (!c->moving_gc_wq)
+               goto err;
+
+       if (bch_journal_alloc(c))
+               goto err;
+
+       if (bch_btree_cache_alloc(c))
+               goto err;
+
+       if (bch_open_buckets_alloc(c))
+               goto err;
+
+       if (bch_bset_sort_state_init(&c->sort, ilog2(c->btree_pages)))
                goto err;
 
        c->congested_read_threshold_us  = 2000;
@@ -2123,7 +2180,14 @@ found:
            sysfs_create_link(&c->kobj, &ca->kobj, buf))
                goto err;
 
-       if (ca->sb.seq > c->sb.seq) {
+       /*
+        * A special case is both ca->sb.seq and c->sb.seq are 0,
+        * such condition happens on a new created cache device whose
+        * super block is never flushed yet. In this case c->sb.version
+        * and other members should be updated too, otherwise we will
+        * have a mistaken super block version in cache set.
+        */
+       if (ca->sb.seq > c->sb.seq || c->sb.seq == 0) {
                c->sb.version           = ca->sb.version;
                memcpy(c->sb.set_uuid, ca->sb.set_uuid, 16);
                c->sb.flags             = ca->sb.flags;