Additional arguments:
 
-journal-sectors:number
+journal_sectors:number
        The size of journal, this argument is used only if formatting the
        device. If the device is already formatted, the value from the
        superblock is used.
 
-interleave-sectors:number
+interleave_sectors:number
        The number of interleaved sectors. This values is rounded down to
        a power of two. If the device is already formatted, the value from
        the superblock is used.
 
-buffer-sectors:number
+buffer_sectors:number
        The number of sectors in one buffer. The value is rounded down to
        a power of two.
 
        configurable. The large buffer size means that the I/O size will
        be larger, but there could be less I/Os issued.
 
-journal-watermark:number
+journal_watermark:number
        The journal watermark in percents. When the size of the journal
        exceeds this watermark, the thread that flushes the journal will
        be started.
 
-commit-time:number
+commit_time:number
        Commit time in milliseconds. When this time passes, the journal is
        written. The journal is also written immediatelly if the FLUSH
        request is received.
 
-internal-hash:algorithm(:key)  (the key is optional)
+internal_hash:algorithm(:key)  (the key is optional)
        Use internal hash or crc.
        When this argument is used, the dm-integrity target won't accept
        integrity tags from the upper target, but it will automatically
        from an upper layer target, such as dm-crypt. The upper layer
        target should check the validity of the integrity tags.
 
-journal-crypt:algorithm(:key)  (the key is optional)
+journal_crypt:algorithm(:key)  (the key is optional)
        Encrypt the journal using given algorithm to make sure that the
        attacker can't read the journal. You can use a block cipher here
        (such as "cbc(aes)") or a stream cipher (for example "chacha20",
        the size of files that were written. To protect against this
        situation, you can encrypt the journal.
 
-journal-mac:algorithm(:key)    (the key is optional)
+journal_mac:algorithm(:key)    (the key is optional)
        Protect sector numbers in the journal from accidental or malicious
        modification. To protect against accidental modification, use a
        crc algorithm, to protect against malicious modification, use a
        this stage.
 
 
-The journal mode (D/J), buffer-sectors, journal-watermark, commit-time can
+The journal mode (D/J), buffer_sectors, journal_watermark, commit_time can
 be changed when reloading the target (load an inactive table and swap the
 tables with suspend and resume). The other arguments should not be changed
 when reloading the target because the layout of disk data depend on them
          provides (i.e. the size of the device minus the size of all
          metadata and padding). The user of this target should not send
          bios that access data beyond the "provided data sectors" limit.
-       * flags - a flag is set if journal-mac is used
+       * flags - a flag is set if journal_mac is used
 * journal
        The journal is divided into sections, each section contains:
        * metadata area (4kiB), it contains journal entries
 
 #define DEFAULT_JOURNAL_WATERMARK      50
 #define DEFAULT_SYNC_MSEC              10000
 #define DEFAULT_MAX_JOURNAL_SECTORS    131072
-#define MIN_INTERLEAVE_SECTORS         3
-#define MAX_INTERLEAVE_SECTORS         31
+#define MIN_LOG2_INTERLEAVE_SECTORS    3
+#define MAX_LOG2_INTERLEAVE_SECTORS    31
 #define METADATA_WORKQUEUE_MAX_ACTIVE  16
 
 /*
 {
        unsigned sector;
 
-       access_journal_check(ic, section, offset, false, "access_journal");
+       access_journal_check(ic, section, offset, false, "page_list_location");
 
        sector = section * ic->journal_section_sectors + offset;
 
                unsigned digest_size = crypto_shash_digestsize(ic->internal_hash);
                struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
                char *checksums;
-               unsigned extra_space = digest_size > ic->tag_size ? digest_size - ic->tag_size : 0;
+               unsigned extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
                char checksums_onstack[ic->tag_size + extra_space];
                unsigned sectors_to_process = dio->range.n_sectors;
                sector_t sector = dio->range.logical_sector;
                                    unlikely(from_replay) &&
 #endif
                                    ic->internal_hash) {
-                                       unsigned char test_tag[ic->tag_size];
+                                       char test_tag[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)];
 
                                        integrity_sector_checksum(ic, sec + (l - j),
                                                                  (char *)access_journal_data(ic, i, l), test_tag);
                arg_count += !!ic->journal_mac_alg.alg_string;
                DMEMIT("%s %llu %u %c %u", ic->dev->name, (unsigned long long)ic->start,
                       ic->tag_size, ic->mode, arg_count);
-               DMEMIT(" journal-sectors:%u", ic->initial_sectors - SB_SECTORS);
-               DMEMIT(" interleave-sectors:%u", 1U << ic->sb->log2_interleave_sectors);
-               DMEMIT(" buffer-sectors:%u", 1U << ic->log2_buffer_sectors);
-               DMEMIT(" journal-watermark:%u", (unsigned)watermark_percentage);
-               DMEMIT(" commit-time:%u", ic->autocommit_msec);
+               DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS);
+               DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors);
+               DMEMIT(" buffer_sectors:%u", 1U << ic->log2_buffer_sectors);
+               DMEMIT(" journal_watermark:%u", (unsigned)watermark_percentage);
+               DMEMIT(" commit_time:%u", ic->autocommit_msec);
 
 #define EMIT_ALG(a, n)                                                 \
                do {                                                    \
                                        DMEMIT(":%s", ic->a.key_string);\
                        }                                               \
                } while (0)
-               EMIT_ALG(internal_hash_alg, "internal-hash");
-               EMIT_ALG(journal_crypt_alg, "journal-crypt");
-               EMIT_ALG(journal_mac_alg, "journal-mac");
+               EMIT_ALG(internal_hash_alg, "internal_hash");
+               EMIT_ALG(journal_crypt_alg, "journal_crypt");
+               EMIT_ALG(journal_mac_alg, "journal_mac");
                break;
        }
        }
        unsigned journal_sections;
        int test_bit;
 
+       memset(ic->sb, 0, SB_SECTORS << SECTOR_SHIFT);
        memcpy(ic->sb->magic, SB_MAGIC, 8);
        ic->sb->version = SB_VERSION;
        ic->sb->integrity_tag_size = cpu_to_le16(ic->tag_size);
                journal_sections = 1;
        ic->sb->journal_sections = cpu_to_le32(journal_sections);
 
+       if (!interleave_sectors)
+               interleave_sectors = DEFAULT_INTERLEAVE_SECTORS;
        ic->sb->log2_interleave_sectors = __fls(interleave_sectors);
-       ic->sb->log2_interleave_sectors = max((__u8)MIN_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors);
-       ic->sb->log2_interleave_sectors = min((__u8)MAX_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors);
+       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->device_sectors) - 1; test_bit >= 3; test_bit--) {
                        ic->provided_data_sectors = prev_data_sectors;
        }
 
-       if (!le64_to_cpu(ic->provided_data_sectors))
+       if (!ic->provided_data_sectors)
                return -EINVAL;
 
        ic->sb->provided_data_sectors = cpu_to_le64(ic->provided_data_sectors);
        int r = 0;
        unsigned i;
        __u64 journal_pages, journal_desc_size, journal_tree_size;
+       unsigned char *crypt_data = NULL;
+
+       ic->commit_ids[0] = cpu_to_le64(0x1111111111111111ULL);
+       ic->commit_ids[1] = cpu_to_le64(0x2222222222222222ULL);
+       ic->commit_ids[2] = cpu_to_le64(0x3333333333333333ULL);
+       ic->commit_ids[3] = cpu_to_le64(0x4444444444444444ULL);
 
        journal_pages = roundup((__u64)ic->journal_sections * ic->journal_section_sectors,
                                PAGE_SIZE >> SECTOR_SHIFT) >> (PAGE_SHIFT - SECTOR_SHIFT);
                        SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt);
                        unsigned char iv[ivsize];
                        unsigned crypt_len = roundup(ivsize, blocksize);
-                       unsigned char crypt_data[crypt_len];
+
+                       crypt_data = kmalloc(crypt_len, GFP_KERNEL);
+                       if (!crypt_data) {
+                               *error = "Unable to allocate crypt data";
+                               r = -ENOMEM;
+                               goto bad;
+                       }
 
                        skcipher_request_set_tfm(req, ic->journal_crypt);
 
                r = -ENOMEM;
        }
 bad:
+       kfree(crypt_data);
        return r;
 }
 
 /*
- * Construct a integrity mapping: <dev_path> <offset> <tag_size>
+ * Construct a integrity mapping
  *
  * Arguments:
  *     device
  *     offset from the start of the device
  *     tag size
- *     D - direct writes, J - journal writes
+ *     D - direct writes, J - journal writes, R - recovery mode
  *     number of optional arguments
  *     optional arguments:
- *             journal-sectors
- *             interleave-sectors
- *             buffer-sectors
- *             journal-watermark
- *             commit-time
- *             internal-hash
- *             journal-crypt
- *             journal-mac
+ *             journal_sectors
+ *             interleave_sectors
+ *             buffer_sectors
+ *             journal_watermark
+ *             commit_time
+ *             internal_hash
+ *             journal_crypt
+ *             journal_mac
  */
 static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
 {
        struct dm_integrity_c *ic;
        char dummy;
        int r;
-       unsigned i;
        unsigned extra_args;
        struct dm_arg_set as;
        static struct dm_arg _args[] = {
-               {0, 7, "Invalid number of feature args"},
+               {0, 8, "Invalid number of feature args"},
        };
        unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
        bool should_write_sb;
        ti->private = ic;
        ti->per_io_data_size = sizeof(struct dm_integrity_io);
 
-       ic->commit_ids[0] = cpu_to_le64(0x1111111111111111ULL);
-       ic->commit_ids[1] = cpu_to_le64(0x2222222222222222ULL);
-       ic->commit_ids[2] = cpu_to_le64(0x3333333333333333ULL);
-       ic->commit_ids[3] = cpu_to_le64(0x4444444444444444ULL);
-
        ic->in_progress = RB_ROOT;
        init_waitqueue_head(&ic->endio_wait);
        bio_list_init(&ic->flush_bio_list);
        if (!strcmp(argv[3], "J") || !strcmp(argv[3], "D") || !strcmp(argv[3], "R"))
                ic->mode = argv[3][0];
        else {
-               ti->error = "Invalid mode (expecting J or D)";
+               ti->error = "Invalid mode (expecting J, D, R)";
                r = -EINVAL;
                goto bad;
        }
                        ti->error = "Not enough feature arguments";
                        goto bad;
                }
-               if (sscanf(opt_string, "journal-sectors:%u%c", &val, &dummy) == 1)
+               if (sscanf(opt_string, "journal_sectors:%u%c", &val, &dummy) == 1)
                        journal_sectors = val;
-               else if (sscanf(opt_string, "interleave-sectors:%u%c", &val, &dummy) == 1)
+               else if (sscanf(opt_string, "interleave_sectors:%u%c", &val, &dummy) == 1)
                        interleave_sectors = val;
-               else if (sscanf(opt_string, "buffer-sectors:%u%c", &val, &dummy) == 1)
+               else if (sscanf(opt_string, "buffer_sectors:%u%c", &val, &dummy) == 1)
                        buffer_sectors = val;
-               else if (sscanf(opt_string, "journal-watermark:%u%c", &val, &dummy) == 1 && val <= 100)
+               else if (sscanf(opt_string, "journal_watermark:%u%c", &val, &dummy) == 1 && val <= 100)
                        journal_watermark = val;
-               else if (sscanf(opt_string, "commit-time:%u%c", &val, &dummy) == 1)
+               else if (sscanf(opt_string, "commit_time:%u%c", &val, &dummy) == 1)
                        sync_msec = val;
-               else if (!memcmp(opt_string, "internal-hash:", strlen("internal-hash:"))) {
+               else if (!memcmp(opt_string, "internal_hash:", strlen("internal_hash:"))) {
                        r = get_alg_and_key(opt_string, &ic->internal_hash_alg, &ti->error,
-                                           "Invalid internal-hash argument");
+                                           "Invalid internal_hash argument");
                        if (r)
                                goto bad;
-               } else if (!memcmp(opt_string, "journal-crypt:", strlen("journal-crypt:"))) {
+               } else if (!memcmp(opt_string, "journal_crypt:", strlen("journal_crypt:"))) {
                        r = get_alg_and_key(opt_string, &ic->journal_crypt_alg, &ti->error,
-                                           "Invalid journal-crypt argument");
+                                           "Invalid journal_crypt argument");
                        if (r)
                                goto bad;
-               } else if (!memcmp(opt_string, "journal-mac:", strlen("journal-mac:"))) {
+               } else if (!memcmp(opt_string, "journal_mac:", strlen("journal_mac:"))) {
                        r = get_alg_and_key(opt_string, &ic->journal_mac_alg,  &ti->error,
-                                           "Invalid journal-mac argument");
+                                           "Invalid journal_mac argument");
                        if (r)
                                goto bad;
                } else {
        should_write_sb = false;
        if (memcmp(ic->sb->magic, SB_MAGIC, 8)) {
                if (ic->mode != 'R') {
-                       for (i = 0; i < 512; i += 8) {
-                               if (*(__u64 *)((__u8 *)ic->sb + i)) {
-                                       r = -EINVAL;
-                                       ti->error = "The device is not initialized";
-                                       goto bad;
-                               }
+                       if (memchr_inv(ic->sb, 0, SB_SECTORS << SECTOR_SHIFT)) {
+                               r = -EINVAL;
+                               ti->error = "The device is not initialized";
+                               goto bad;
                        }
                }
 
                goto bad;
        }
        /* make sure that ti->max_io_len doesn't overflow */
-       if (ic->sb->log2_interleave_sectors < MIN_INTERLEAVE_SECTORS ||
-           ic->sb->log2_interleave_sectors > MAX_INTERLEAVE_SECTORS) {
+       if (ic->sb->log2_interleave_sectors < MIN_LOG2_INTERLEAVE_SECTORS ||
+           ic->sb->log2_interleave_sectors > MAX_LOG2_INTERLEAVE_SECTORS) {
                r = -EINVAL;
                ti->error = "Invalid interleave_sectors in the superblock";
                goto bad;