RDMA/mlx5: Verify that DM operation is reasonable
[linux-2.6-microblaze.git] / drivers / md / dm-era-target.c
index b24e383..d9ac737 100644 (file)
@@ -47,6 +47,7 @@ struct writeset {
 static void writeset_free(struct writeset *ws)
 {
        vfree(ws->bits);
+       ws->bits = NULL;
 }
 
 static int setup_on_disk_bitset(struct dm_disk_bitset *info,
@@ -71,8 +72,6 @@ static size_t bitset_size(unsigned nr_bits)
  */
 static int writeset_alloc(struct writeset *ws, dm_block_t nr_blocks)
 {
-       ws->md.nr_bits = nr_blocks;
-       ws->md.root = INVALID_WRITESET_ROOT;
        ws->bits = vzalloc(bitset_size(nr_blocks));
        if (!ws->bits) {
                DMERR("%s: couldn't allocate in memory bitset", __func__);
@@ -85,12 +84,14 @@ static int writeset_alloc(struct writeset *ws, dm_block_t nr_blocks)
 /*
  * Wipes the in-core bitset, and creates a new on disk bitset.
  */
-static int writeset_init(struct dm_disk_bitset *info, struct writeset *ws)
+static int writeset_init(struct dm_disk_bitset *info, struct writeset *ws,
+                        dm_block_t nr_blocks)
 {
        int r;
 
-       memset(ws->bits, 0, bitset_size(ws->md.nr_bits));
+       memset(ws->bits, 0, bitset_size(nr_blocks));
 
+       ws->md.nr_bits = nr_blocks;
        r = setup_on_disk_bitset(info, ws->md.nr_bits, &ws->md.root);
        if (r) {
                DMERR("%s: setup_on_disk_bitset failed", __func__);
@@ -134,7 +135,7 @@ static int writeset_test_and_set(struct dm_disk_bitset *info,
 {
        int r;
 
-       if (!test_and_set_bit(block, ws->bits)) {
+       if (!test_bit(block, ws->bits)) {
                r = dm_bitset_set_bit(info, ws->md.root, block, &ws->md.root);
                if (r) {
                        /* FIXME: fail mode */
@@ -388,7 +389,7 @@ static void ws_dec(void *context, const void *value)
 
 static int ws_eq(void *context, const void *value1, const void *value2)
 {
-       return !memcmp(value1, value2, sizeof(struct writeset_metadata));
+       return !memcmp(value1, value2, sizeof(struct writeset_disk));
 }
 
 /*----------------------------------------------------------------*/
@@ -564,6 +565,15 @@ static int open_metadata(struct era_metadata *md)
        }
 
        disk = dm_block_data(sblock);
+
+       /* Verify the data block size hasn't changed */
+       if (le32_to_cpu(disk->data_block_size) != md->block_size) {
+               DMERR("changing the data block size (from %u to %llu) is not supported",
+                     le32_to_cpu(disk->data_block_size), md->block_size);
+               r = -EINVAL;
+               goto bad;
+       }
+
        r = dm_tm_open_with_sm(md->bm, SUPERBLOCK_LOCATION,
                               disk->metadata_space_map_root,
                               sizeof(disk->metadata_space_map_root),
@@ -575,10 +585,10 @@ static int open_metadata(struct era_metadata *md)
 
        setup_infos(md);
 
-       md->block_size = le32_to_cpu(disk->data_block_size);
        md->nr_blocks = le32_to_cpu(disk->nr_blocks);
        md->current_era = le32_to_cpu(disk->current_era);
 
+       ws_unpack(&disk->current_writeset, &md->current_writeset->md);
        md->writeset_tree_root = le64_to_cpu(disk->writeset_tree_root);
        md->era_array_root = le64_to_cpu(disk->era_array_root);
        md->metadata_snap = le64_to_cpu(disk->metadata_snap);
@@ -746,6 +756,12 @@ static int metadata_digest_lookup_writeset(struct era_metadata *md,
        ws_unpack(&disk, &d->writeset);
        d->value = cpu_to_le32(key);
 
+       /*
+        * We initialise another bitset info to avoid any caching side effects
+        * with the previous one.
+        */
+       dm_disk_bitset_init(md->tm, &d->info);
+
        d->nr_bits = min(d->writeset.nr_bits, md->nr_blocks);
        d->current_bit = 0;
        d->step = metadata_digest_transcribe_writeset;
@@ -759,12 +775,6 @@ static int metadata_digest_start(struct era_metadata *md, struct digest *d)
                return 0;
 
        memset(d, 0, sizeof(*d));
-
-       /*
-        * We initialise another bitset info to avoid any caching side
-        * effects with the previous one.
-        */
-       dm_disk_bitset_init(md->tm, &d->info);
        d->step = metadata_digest_lookup_writeset;
 
        return 0;
@@ -802,6 +812,8 @@ static struct era_metadata *metadata_open(struct block_device *bdev,
 
 static void metadata_close(struct era_metadata *md)
 {
+       writeset_free(&md->writesets[0]);
+       writeset_free(&md->writesets[1]);
        destroy_persistent_data_objects(md);
        kfree(md);
 }
@@ -839,6 +851,7 @@ static int metadata_resize(struct era_metadata *md, void *arg)
        r = writeset_alloc(&md->writesets[1], *new_size);
        if (r) {
                DMERR("%s: writeset_alloc failed for writeset 1", __func__);
+               writeset_free(&md->writesets[0]);
                return r;
        }
 
@@ -849,6 +862,8 @@ static int metadata_resize(struct era_metadata *md, void *arg)
                            &value, &md->era_array_root);
        if (r) {
                DMERR("%s: dm_array_resize failed", __func__);
+               writeset_free(&md->writesets[0]);
+               writeset_free(&md->writesets[1]);
                return r;
        }
 
@@ -870,7 +885,6 @@ static int metadata_era_archive(struct era_metadata *md)
        }
 
        ws_pack(&md->current_writeset->md, &value);
-       md->current_writeset->md.root = INVALID_WRITESET_ROOT;
 
        keys[0] = md->current_era;
        __dm_bless_for_disk(&value);
@@ -882,6 +896,7 @@ static int metadata_era_archive(struct era_metadata *md)
                return r;
        }
 
+       md->current_writeset->md.root = INVALID_WRITESET_ROOT;
        md->archived_writesets = true;
 
        return 0;
@@ -898,7 +913,7 @@ static int metadata_new_era(struct era_metadata *md)
        int r;
        struct writeset *new_writeset = next_writeset(md);
 
-       r = writeset_init(&md->bitset_info, new_writeset);
+       r = writeset_init(&md->bitset_info, new_writeset, md->nr_blocks);
        if (r) {
                DMERR("%s: writeset_init failed", __func__);
                return r;
@@ -951,7 +966,7 @@ static int metadata_commit(struct era_metadata *md)
        int r;
        struct dm_block *sblock;
 
-       if (md->current_writeset->md.root != SUPERBLOCK_LOCATION) {
+       if (md->current_writeset->md.root != INVALID_WRITESET_ROOT) {
                r = dm_bitset_flush(&md->bitset_info, md->current_writeset->md.root,
                                    &md->current_writeset->md.root);
                if (r) {
@@ -1225,8 +1240,10 @@ static void process_deferred_bios(struct era *era)
        int r;
        struct bio_list deferred_bios, marked_bios;
        struct bio *bio;
+       struct blk_plug plug;
        bool commit_needed = false;
        bool failed = false;
+       struct writeset *ws = era->md->current_writeset;
 
        bio_list_init(&deferred_bios);
        bio_list_init(&marked_bios);
@@ -1236,9 +1253,11 @@ static void process_deferred_bios(struct era *era)
        bio_list_init(&era->deferred_bios);
        spin_unlock(&era->deferred_lock);
 
+       if (bio_list_empty(&deferred_bios))
+               return;
+
        while ((bio = bio_list_pop(&deferred_bios))) {
-               r = writeset_test_and_set(&era->md->bitset_info,
-                                         era->md->current_writeset,
+               r = writeset_test_and_set(&era->md->bitset_info, ws,
                                          get_block(era, bio));
                if (r < 0) {
                        /*
@@ -1246,7 +1265,6 @@ static void process_deferred_bios(struct era *era)
                         * FIXME: finish.
                         */
                        failed = true;
-
                } else if (r == 0)
                        commit_needed = true;
 
@@ -1262,9 +1280,19 @@ static void process_deferred_bios(struct era *era)
        if (failed)
                while ((bio = bio_list_pop(&marked_bios)))
                        bio_io_error(bio);
-       else
-               while ((bio = bio_list_pop(&marked_bios)))
+       else {
+               blk_start_plug(&plug);
+               while ((bio = bio_list_pop(&marked_bios))) {
+                       /*
+                        * Only update the in-core writeset if the on-disk one
+                        * was updated too.
+                        */
+                       if (commit_needed)
+                               set_bit(get_block(era, bio), ws->bits);
                        submit_bio_noacct(bio);
+               }
+               blk_finish_plug(&plug);
+       }
 }
 
 static void process_rpc_calls(struct era *era)
@@ -1473,15 +1501,6 @@ static int era_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
        era->md = md;
 
-       era->nr_blocks = calc_nr_blocks(era);
-
-       r = metadata_resize(era->md, &era->nr_blocks);
-       if (r) {
-               ti->error = "couldn't resize metadata";
-               era_destroy(era);
-               return -ENOMEM;
-       }
-
        era->wq = alloc_ordered_workqueue("dm-" DM_MSG_PREFIX, WQ_MEM_RECLAIM);
        if (!era->wq) {
                ti->error = "could not create workqueue for metadata object";
@@ -1556,16 +1575,24 @@ static int era_preresume(struct dm_target *ti)
        dm_block_t new_size = calc_nr_blocks(era);
 
        if (era->nr_blocks != new_size) {
-               r = in_worker1(era, metadata_resize, &new_size);
-               if (r)
+               r = metadata_resize(era->md, &new_size);
+               if (r) {
+                       DMERR("%s: metadata_resize failed", __func__);
+                       return r;
+               }
+
+               r = metadata_commit(era->md);
+               if (r) {
+                       DMERR("%s: metadata_commit failed", __func__);
                        return r;
+               }
 
                era->nr_blocks = new_size;
        }
 
        start_worker(era);
 
-       r = in_worker0(era, metadata_new_era);
+       r = in_worker0(era, metadata_era_rollover);
        if (r) {
                DMERR("%s: metadata_era_rollover failed", __func__);
                return r;