dm integrity: allow resize of the integrity device
[linux-2.6-microblaze.git] / drivers / md / dm-integrity.c
index 3c10a67..fafd9ec 100644 (file)
@@ -2833,9 +2833,29 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
 static void dm_integrity_resume(struct dm_target *ti)
 {
        struct dm_integrity_c *ic = (struct dm_integrity_c *)ti->private;
+       __u64 old_provided_data_sectors = le64_to_cpu(ic->sb->provided_data_sectors);
        int r;
+
        DEBUG_print("resume\n");
 
+       if (ic->provided_data_sectors != old_provided_data_sectors) {
+               if (ic->provided_data_sectors > old_provided_data_sectors &&
+                   ic->mode == 'B' &&
+                   ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit) {
+                       rw_journal_sectors(ic, REQ_OP_READ, 0, 0,
+                                          ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
+                       block_bitmap_op(ic, ic->journal, old_provided_data_sectors,
+                                       ic->provided_data_sectors - old_provided_data_sectors, BITMAP_OP_SET);
+                       rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
+                                          ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
+               }
+
+               ic->sb->provided_data_sectors = cpu_to_le64(ic->provided_data_sectors);
+               r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
+               if (unlikely(r))
+                       dm_integrity_io_error(ic, "writing superblock", r);
+       }
+
        if (ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP)) {
                DEBUG_print("resume dirty_bitmap\n");
                rw_journal_sectors(ic, REQ_OP_READ, 0, 0,
@@ -3078,6 +3098,24 @@ static int calculate_device_limits(struct dm_integrity_c *ic)
        return 0;
 }
 
+static void get_provided_data_sectors(struct dm_integrity_c *ic)
+{
+       if (!ic->meta_dev) {
+               int test_bit;
+               ic->provided_data_sectors = 0;
+               for (test_bit = fls64(ic->meta_device_sectors) - 1; test_bit >= 3; test_bit--) {
+                       __u64 prev_data_sectors = ic->provided_data_sectors;
+
+                       ic->provided_data_sectors |= (sector_t)1 << test_bit;
+                       if (calculate_device_limits(ic))
+                               ic->provided_data_sectors = prev_data_sectors;
+               }
+       } else {
+               ic->provided_data_sectors = ic->data_device_sectors;
+               ic->provided_data_sectors &= ~(sector_t)(ic->sectors_per_block - 1);
+       }
+}
+
 static int initialize_superblock(struct dm_integrity_c *ic, unsigned journal_sectors, unsigned interleave_sectors)
 {
        unsigned journal_sections;
@@ -3105,20 +3143,15 @@ static int initialize_superblock(struct dm_integrity_c *ic, unsigned journal_sec
                ic->sb->log2_interleave_sectors = max((__u8)MIN_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors);
                ic->sb->log2_interleave_sectors = min((__u8)MAX_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors);
 
-               ic->provided_data_sectors = 0;
-               for (test_bit = fls64(ic->meta_device_sectors) - 1; test_bit >= 3; test_bit--) {
-                       __u64 prev_data_sectors = ic->provided_data_sectors;
-
-                       ic->provided_data_sectors |= (sector_t)1 << test_bit;
-                       if (calculate_device_limits(ic))
-                               ic->provided_data_sectors = prev_data_sectors;
-               }
+               get_provided_data_sectors(ic);
                if (!ic->provided_data_sectors)
                        return -EINVAL;
        } else {
                ic->sb->log2_interleave_sectors = 0;
-               ic->provided_data_sectors = ic->data_device_sectors;
-               ic->provided_data_sectors &= ~(sector_t)(ic->sectors_per_block - 1);
+
+               get_provided_data_sectors(ic);
+               if (!ic->provided_data_sectors)
+                       return -EINVAL;
 
 try_smaller_buffer:
                ic->sb->journal_sections = cpu_to_le32(0);
@@ -3925,16 +3958,16 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                        goto bad;
                }
        }
-       ic->provided_data_sectors = le64_to_cpu(ic->sb->provided_data_sectors);
-       if (ic->provided_data_sectors != le64_to_cpu(ic->sb->provided_data_sectors)) {
-               /* test for overflow */
+       if (!!(ic->sb->flags & cpu_to_le32(SB_FLAG_HAVE_JOURNAL_MAC)) != !!ic->journal_mac_alg.alg_string) {
                r = -EINVAL;
-               ti->error = "The superblock has 64-bit device size, but the kernel was compiled with 32-bit sectors";
+               ti->error = "Journal mac mismatch";
                goto bad;
        }
-       if (!!(ic->sb->flags & cpu_to_le32(SB_FLAG_HAVE_JOURNAL_MAC)) != !!ic->journal_mac_alg.alg_string) {
+
+       get_provided_data_sectors(ic);
+       if (!ic->provided_data_sectors) {
                r = -EINVAL;
-               ti->error = "Journal mac mismatch";
+               ti->error = "The device is too small";
                goto bad;
        }
 
@@ -4206,7 +4239,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
 
 static struct target_type integrity_target = {
        .name                   = "integrity",
-       .version                = {1, 5, 0},
+       .version                = {1, 6, 0},
        .module                 = THIS_MODULE,
        .features               = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
        .ctr                    = dm_integrity_ctr,