RDMA/mlx5: Verify that DM operation is reasonable
[linux-2.6-microblaze.git] / drivers / md / dm-integrity.c
index 46b5d54..781942a 100644 (file)
@@ -35,7 +35,7 @@
 #define MIN_LOG2_INTERLEAVE_SECTORS    3
 #define MAX_LOG2_INTERLEAVE_SECTORS    31
 #define METADATA_WORKQUEUE_MAX_ACTIVE  16
-#define RECALC_SECTORS                 8192
+#define RECALC_SECTORS                 32768
 #define RECALC_WRITE_SUPER             16
 #define BITMAP_BLOCK_SIZE              4096    /* don't change it */
 #define BITMAP_FLUSH_INTERVAL          (10 * HZ)
@@ -262,6 +262,7 @@ struct dm_integrity_c {
        bool journal_uptodate;
        bool just_formatted;
        bool recalculate_flag;
+       bool reset_recalculate_flag;
        bool discard;
        bool fix_padding;
        bool fix_hmac;
@@ -1428,8 +1429,10 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se
                if (op == TAG_READ) {
                        memcpy(tag, dp, to_copy);
                } else if (op == TAG_WRITE) {
-                       memcpy(dp, tag, to_copy);
-                       dm_bufio_mark_partial_buffer_dirty(b, *metadata_offset, *metadata_offset + to_copy);
+                       if (memcmp(dp, tag, to_copy)) {
+                               memcpy(dp, tag, to_copy);
+                               dm_bufio_mark_partial_buffer_dirty(b, *metadata_offset, *metadata_offset + to_copy);
+                       }
                } else {
                        /* e.g.: op == TAG_CMP */
 
@@ -2686,26 +2689,30 @@ next_chunk:
        if (unlikely(dm_integrity_failed(ic)))
                goto err;
 
-       io_req.bi_op = REQ_OP_READ;
-       io_req.bi_op_flags = 0;
-       io_req.mem.type = DM_IO_VMA;
-       io_req.mem.ptr.addr = ic->recalc_buffer;
-       io_req.notify.fn = NULL;
-       io_req.client = ic->io;
-       io_loc.bdev = ic->dev->bdev;
-       io_loc.sector = get_data_sector(ic, area, offset);
-       io_loc.count = n_sectors;
+       if (!ic->discard) {
+               io_req.bi_op = REQ_OP_READ;
+               io_req.bi_op_flags = 0;
+               io_req.mem.type = DM_IO_VMA;
+               io_req.mem.ptr.addr = ic->recalc_buffer;
+               io_req.notify.fn = NULL;
+               io_req.client = ic->io;
+               io_loc.bdev = ic->dev->bdev;
+               io_loc.sector = get_data_sector(ic, area, offset);
+               io_loc.count = n_sectors;
 
-       r = dm_io(&io_req, 1, &io_loc, NULL);
-       if (unlikely(r)) {
-               dm_integrity_io_error(ic, "reading data", r);
-               goto err;
-       }
+               r = dm_io(&io_req, 1, &io_loc, NULL);
+               if (unlikely(r)) {
+                       dm_integrity_io_error(ic, "reading data", r);
+                       goto err;
+               }
 
-       t = ic->recalc_tags;
-       for (i = 0; i < n_sectors; i += ic->sectors_per_block) {
-               integrity_sector_checksum(ic, logical_sector + i, ic->recalc_buffer + (i << SECTOR_SHIFT), t);
-               t += ic->tag_size;
+               t = ic->recalc_tags;
+               for (i = 0; i < n_sectors; i += ic->sectors_per_block) {
+                       integrity_sector_checksum(ic, logical_sector + i, ic->recalc_buffer + (i << SECTOR_SHIFT), t);
+                       t += ic->tag_size;
+               }
+       } else {
+               t = ic->recalc_tags + (n_sectors >> ic->sb->log2_sectors_per_block) * ic->tag_size;
        }
 
        metadata_block = get_metadata_sector_and_offset(ic, area, offset, &metadata_offset);
@@ -3134,7 +3141,8 @@ static void dm_integrity_resume(struct dm_target *ti)
                rw_journal_sectors(ic, REQ_OP_READ, 0, 0,
                                   ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                if (ic->mode == 'B') {
-                       if (ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit) {
+                       if (ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit &&
+                           !ic->reset_recalculate_flag) {
                                block_bitmap_copy(ic, ic->recalc_bitmap, ic->journal);
                                block_bitmap_copy(ic, ic->may_write_bitmap, ic->journal);
                                if (!block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors,
@@ -3156,7 +3164,8 @@ static void dm_integrity_resume(struct dm_target *ti)
                        }
                } else {
                        if (!(ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit &&
-                             block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_TEST_ALL_CLEAR))) {
+                             block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_TEST_ALL_CLEAR)) ||
+                           ic->reset_recalculate_flag) {
                                ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING);
                                ic->sb->recalc_sector = cpu_to_le64(0);
                        }
@@ -3169,6 +3178,10 @@ static void dm_integrity_resume(struct dm_target *ti)
                        dm_integrity_io_error(ic, "writing superblock", r);
        } else {
                replay_journal(ic);
+               if (ic->reset_recalculate_flag) {
+                       ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING);
+                       ic->sb->recalc_sector = cpu_to_le64(0);
+               }
                if (ic->mode == 'B') {
                        ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
                        ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit;
@@ -3242,6 +3255,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                arg_count += !!ic->meta_dev;
                arg_count += ic->sectors_per_block != 1;
                arg_count += !!(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING));
+               arg_count += ic->reset_recalculate_flag;
                arg_count += ic->discard;
                arg_count += ic->mode == 'J';
                arg_count += ic->mode == 'J';
@@ -3261,6 +3275,8 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                        DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT);
                if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
                        DMEMIT(" recalculate");
+               if (ic->reset_recalculate_flag)
+                       DMEMIT(" reset_recalculate");
                if (ic->discard)
                        DMEMIT(" allow_discards");
                DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS);
@@ -3914,7 +3930,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        unsigned extra_args;
        struct dm_arg_set as;
        static const struct dm_arg _args[] = {
-               {0, 17, "Invalid number of feature args"},
+               {0, 18, "Invalid number of feature args"},
        };
        unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
        bool should_write_sb;
@@ -4039,6 +4055,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                        if (val >= (uint64_t)UINT_MAX * 1000 / HZ) {
                                r = -EINVAL;
                                ti->error = "Invalid bitmap_flush_interval argument";
+                               goto bad;
                        }
                        ic->bitmap_flush_interval = msecs_to_jiffies(val);
                } else if (!strncmp(opt_string, "internal_hash:", strlen("internal_hash:"))) {
@@ -4058,6 +4075,9 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                                goto bad;
                } else if (!strcmp(opt_string, "recalculate")) {
                        ic->recalculate_flag = true;
+               } else if (!strcmp(opt_string, "reset_recalculate")) {
+                       ic->recalculate_flag = true;
+                       ic->reset_recalculate_flag = true;
                } else if (!strcmp(opt_string, "allow_discards")) {
                        ic->discard = true;
                } else if (!strcmp(opt_string, "fix_padding")) {
@@ -4348,11 +4368,13 @@ try_smaller_buffer:
                        goto bad;
                }
                INIT_WORK(&ic->recalc_work, integrity_recalc);
-               ic->recalc_buffer = vmalloc(RECALC_SECTORS << SECTOR_SHIFT);
-               if (!ic->recalc_buffer) {
-                       ti->error = "Cannot allocate buffer for recalculating";
-                       r = -ENOMEM;
-                       goto bad;
+               if (!ic->discard) {
+                       ic->recalc_buffer = vmalloc(RECALC_SECTORS << SECTOR_SHIFT);
+                       if (!ic->recalc_buffer) {
+                               ti->error = "Cannot allocate buffer for recalculating";
+                               r = -ENOMEM;
+                               goto bad;
+                       }
                }
                ic->recalc_tags = kvmalloc_array(RECALC_SECTORS >> ic->sb->log2_sectors_per_block,
                                                 ic->tag_size, GFP_KERNEL);
@@ -4361,6 +4383,9 @@ try_smaller_buffer:
                        r = -ENOMEM;
                        goto bad;
                }
+               if (ic->discard)
+                       memset(ic->recalc_tags, DISCARD_FILLER,
+                              (RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size);
        } else {
                if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
                        ti->error = "Recalculate can only be specified with internal_hash";
@@ -4554,7 +4579,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
 
 static struct target_type integrity_target = {
        .name                   = "integrity",
-       .version                = {1, 7, 0},
+       .version                = {1, 9, 0},
        .module                 = THIS_MODULE,
        .features               = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
        .ctr                    = dm_integrity_ctr,