Merge tag 'driver-core-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / md / dm-integrity.c
index dab4446fe7d8419ca8887b1efa2c349ff095a1dc..b225b3e445fa43aa57c51828f7f6bea09351fb0c 100644 (file)
@@ -53,6 +53,7 @@
 #define SB_VERSION_1                   1
 #define SB_VERSION_2                   2
 #define SB_VERSION_3                   3
+#define SB_VERSION_4                   4
 #define SB_SECTORS                     8
 #define MAX_SECTORS_PER_BLOCK          8
 
@@ -73,6 +74,7 @@ struct superblock {
 #define SB_FLAG_HAVE_JOURNAL_MAC       0x1
 #define SB_FLAG_RECALCULATING          0x2
 #define SB_FLAG_DIRTY_BITMAP           0x4
+#define SB_FLAG_FIXED_PADDING          0x8
 
 #define        JOURNAL_ENTRY_ROUNDUP           8
 
@@ -250,6 +252,7 @@ struct dm_integrity_c {
        bool journal_uptodate;
        bool just_formatted;
        bool recalculate_flag;
+       bool fix_padding;
 
        struct alg_spec internal_hash_alg;
        struct alg_spec journal_crypt_alg;
@@ -463,7 +466,9 @@ static void wraparound_section(struct dm_integrity_c *ic, unsigned *sec_ptr)
 
 static void sb_set_version(struct dm_integrity_c *ic)
 {
-       if (ic->mode == 'B' || ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP))
+       if (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING))
+               ic->sb->version = SB_VERSION_4;
+       else if (ic->mode == 'B' || ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP))
                ic->sb->version = SB_VERSION_3;
        else if (ic->meta_dev || ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
                ic->sb->version = SB_VERSION_2;
@@ -2955,6 +2960,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                arg_count += !!ic->internal_hash_alg.alg_string;
                arg_count += !!ic->journal_crypt_alg.alg_string;
                arg_count += !!ic->journal_mac_alg.alg_string;
+               arg_count += (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0;
                DMEMIT("%s %llu %u %c %u", ic->dev->name, (unsigned long long)ic->start,
                       ic->tag_size, ic->mode, arg_count);
                if (ic->meta_dev)
@@ -2974,6 +2980,8 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                        DMEMIT(" sectors_per_bit:%llu", (unsigned long long)ic->sectors_per_block << ic->log2_blocks_per_bitmap_bit);
                        DMEMIT(" bitmap_flush_interval:%u", jiffies_to_msecs(ic->bitmap_flush_interval));
                }
+               if ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0)
+                       DMEMIT(" fix_padding");
 
 #define EMIT_ALG(a, n)                                                 \
                do {                                                    \
@@ -3042,8 +3050,14 @@ static int calculate_device_limits(struct dm_integrity_c *ic)
        if (!ic->meta_dev) {
                sector_t last_sector, last_area, last_offset;
 
-               ic->metadata_run = roundup((__u64)ic->tag_size << (ic->sb->log2_interleave_sectors - ic->sb->log2_sectors_per_block),
-                                          (__u64)(1 << SECTOR_SHIFT << METADATA_PADDING_SECTORS)) >> SECTOR_SHIFT;
+               /* we have to maintain excessive padding for compatibility with existing volumes */
+               __u64 metadata_run_padding =
+                       ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING) ?
+                       (__u64)(METADATA_PADDING_SECTORS << SECTOR_SHIFT) :
+                       (__u64)(1 << SECTOR_SHIFT << METADATA_PADDING_SECTORS);
+
+               ic->metadata_run = round_up((__u64)ic->tag_size << (ic->sb->log2_interleave_sectors - ic->sb->log2_sectors_per_block),
+                                           metadata_run_padding) >> SECTOR_SHIFT;
                if (!(ic->metadata_run & (ic->metadata_run - 1)))
                        ic->log2_metadata_run = __ffs(ic->metadata_run);
                else
@@ -3086,6 +3100,8 @@ static int initialize_superblock(struct dm_integrity_c *ic, unsigned journal_sec
                journal_sections = 1;
 
        if (!ic->meta_dev) {
+               if (ic->fix_padding)
+                       ic->sb->flags |= cpu_to_le32(SB_FLAG_FIXED_PADDING);
                ic->sb->journal_sections = cpu_to_le32(journal_sections);
                if (!interleave_sectors)
                        interleave_sectors = DEFAULT_INTERLEAVE_SECTORS;
@@ -3725,6 +3741,8 @@ 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, "fix_padding")) {
+                       ic->fix_padding = true;
                } else {
                        r = -EINVAL;
                        ti->error = "Invalid argument";
@@ -3867,7 +3885,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                        should_write_sb = true;
        }
 
-       if (!ic->sb->version || ic->sb->version > SB_VERSION_3) {
+       if (!ic->sb->version || ic->sb->version > SB_VERSION_4) {
                r = -EINVAL;
                ti->error = "Unknown version";
                goto bad;
@@ -4182,7 +4200,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
 
 static struct target_type integrity_target = {
        .name                   = "integrity",
-       .version                = {1, 3, 0},
+       .version                = {1, 4, 0},
        .module                 = THIS_MODULE,
        .features               = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
        .ctr                    = dm_integrity_ctr,