diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2017-04-18 16:51:50 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2017-04-24 12:04:32 -0400 |
commit | 56b67a4f292f14548f4046979d46d07bcf8ba971 (patch) | |
tree | 2b7648bdcbc66160eafe5b93d6445a90afef4998 /drivers/md/dm-integrity.c | |
parent | e2460f2a4bc740fae9e23f14d653cf53e90b3f9a (diff) |
dm integrity: various small changes and cleanups
Some coding style changes.
Fix a bug that the array test_tag has insufficient size if the digest
size of internal has is bigger than the tag size.
The function __fls is undefined for zero argument, this patch fixes
undefined behavior if the user sets zero interleave_sectors.
Fix the limit of optional arguments to 8.
Don't allocate crypt_data on the stack to avoid a BUG with debug kernel.
Rename all optional argument names to have underscores rather than
dashes.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md/dm-integrity.c')
-rw-r--r-- | drivers/md/dm-integrity.c | 116 |
1 files changed, 62 insertions, 54 deletions
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index e26a079b41ea..95cdffbb206c 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c | |||
@@ -27,8 +27,8 @@ | |||
27 | #define DEFAULT_JOURNAL_WATERMARK 50 | 27 | #define DEFAULT_JOURNAL_WATERMARK 50 |
28 | #define DEFAULT_SYNC_MSEC 10000 | 28 | #define DEFAULT_SYNC_MSEC 10000 |
29 | #define DEFAULT_MAX_JOURNAL_SECTORS 131072 | 29 | #define DEFAULT_MAX_JOURNAL_SECTORS 131072 |
30 | #define MIN_INTERLEAVE_SECTORS 3 | 30 | #define MIN_LOG2_INTERLEAVE_SECTORS 3 |
31 | #define MAX_INTERLEAVE_SECTORS 31 | 31 | #define MAX_LOG2_INTERLEAVE_SECTORS 31 |
32 | #define METADATA_WORKQUEUE_MAX_ACTIVE 16 | 32 | #define METADATA_WORKQUEUE_MAX_ACTIVE 16 |
33 | 33 | ||
34 | /* | 34 | /* |
@@ -414,7 +414,7 @@ static void page_list_location(struct dm_integrity_c *ic, unsigned section, unsi | |||
414 | { | 414 | { |
415 | unsigned sector; | 415 | unsigned sector; |
416 | 416 | ||
417 | access_journal_check(ic, section, offset, false, "access_journal"); | 417 | access_journal_check(ic, section, offset, false, "page_list_location"); |
418 | 418 | ||
419 | sector = section * ic->journal_section_sectors + offset; | 419 | sector = section * ic->journal_section_sectors + offset; |
420 | 420 | ||
@@ -1211,7 +1211,7 @@ static void integrity_metadata(struct work_struct *w) | |||
1211 | unsigned digest_size = crypto_shash_digestsize(ic->internal_hash); | 1211 | unsigned digest_size = crypto_shash_digestsize(ic->internal_hash); |
1212 | struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); | 1212 | struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); |
1213 | char *checksums; | 1213 | char *checksums; |
1214 | unsigned extra_space = digest_size > ic->tag_size ? digest_size - ic->tag_size : 0; | 1214 | unsigned extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0; |
1215 | char checksums_onstack[ic->tag_size + extra_space]; | 1215 | char checksums_onstack[ic->tag_size + extra_space]; |
1216 | unsigned sectors_to_process = dio->range.n_sectors; | 1216 | unsigned sectors_to_process = dio->range.n_sectors; |
1217 | sector_t sector = dio->range.logical_sector; | 1217 | sector_t sector = dio->range.logical_sector; |
@@ -1820,7 +1820,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start, | |||
1820 | unlikely(from_replay) && | 1820 | unlikely(from_replay) && |
1821 | #endif | 1821 | #endif |
1822 | ic->internal_hash) { | 1822 | ic->internal_hash) { |
1823 | unsigned char test_tag[ic->tag_size]; | 1823 | char test_tag[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)]; |
1824 | 1824 | ||
1825 | integrity_sector_checksum(ic, sec + (l - j), | 1825 | integrity_sector_checksum(ic, sec + (l - j), |
1826 | (char *)access_journal_data(ic, i, l), test_tag); | 1826 | (char *)access_journal_data(ic, i, l), test_tag); |
@@ -2135,11 +2135,11 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type, | |||
2135 | arg_count += !!ic->journal_mac_alg.alg_string; | 2135 | arg_count += !!ic->journal_mac_alg.alg_string; |
2136 | DMEMIT("%s %llu %u %c %u", ic->dev->name, (unsigned long long)ic->start, | 2136 | DMEMIT("%s %llu %u %c %u", ic->dev->name, (unsigned long long)ic->start, |
2137 | ic->tag_size, ic->mode, arg_count); | 2137 | ic->tag_size, ic->mode, arg_count); |
2138 | DMEMIT(" journal-sectors:%u", ic->initial_sectors - SB_SECTORS); | 2138 | DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS); |
2139 | DMEMIT(" interleave-sectors:%u", 1U << ic->sb->log2_interleave_sectors); | 2139 | DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors); |
2140 | DMEMIT(" buffer-sectors:%u", 1U << ic->log2_buffer_sectors); | 2140 | DMEMIT(" buffer_sectors:%u", 1U << ic->log2_buffer_sectors); |
2141 | DMEMIT(" journal-watermark:%u", (unsigned)watermark_percentage); | 2141 | DMEMIT(" journal_watermark:%u", (unsigned)watermark_percentage); |
2142 | DMEMIT(" commit-time:%u", ic->autocommit_msec); | 2142 | DMEMIT(" commit_time:%u", ic->autocommit_msec); |
2143 | 2143 | ||
2144 | #define EMIT_ALG(a, n) \ | 2144 | #define EMIT_ALG(a, n) \ |
2145 | do { \ | 2145 | do { \ |
@@ -2149,9 +2149,9 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type, | |||
2149 | DMEMIT(":%s", ic->a.key_string);\ | 2149 | DMEMIT(":%s", ic->a.key_string);\ |
2150 | } \ | 2150 | } \ |
2151 | } while (0) | 2151 | } while (0) |
2152 | EMIT_ALG(internal_hash_alg, "internal-hash"); | 2152 | EMIT_ALG(internal_hash_alg, "internal_hash"); |
2153 | EMIT_ALG(journal_crypt_alg, "journal-crypt"); | 2153 | EMIT_ALG(journal_crypt_alg, "journal_crypt"); |
2154 | EMIT_ALG(journal_mac_alg, "journal-mac"); | 2154 | EMIT_ALG(journal_mac_alg, "journal_mac"); |
2155 | break; | 2155 | break; |
2156 | } | 2156 | } |
2157 | } | 2157 | } |
@@ -2213,6 +2213,7 @@ static int initialize_superblock(struct dm_integrity_c *ic, unsigned journal_sec | |||
2213 | unsigned journal_sections; | 2213 | unsigned journal_sections; |
2214 | int test_bit; | 2214 | int test_bit; |
2215 | 2215 | ||
2216 | memset(ic->sb, 0, SB_SECTORS << SECTOR_SHIFT); | ||
2216 | memcpy(ic->sb->magic, SB_MAGIC, 8); | 2217 | memcpy(ic->sb->magic, SB_MAGIC, 8); |
2217 | ic->sb->version = SB_VERSION; | 2218 | ic->sb->version = SB_VERSION; |
2218 | ic->sb->integrity_tag_size = cpu_to_le16(ic->tag_size); | 2219 | ic->sb->integrity_tag_size = cpu_to_le16(ic->tag_size); |
@@ -2225,9 +2226,11 @@ static int initialize_superblock(struct dm_integrity_c *ic, unsigned journal_sec | |||
2225 | journal_sections = 1; | 2226 | journal_sections = 1; |
2226 | ic->sb->journal_sections = cpu_to_le32(journal_sections); | 2227 | ic->sb->journal_sections = cpu_to_le32(journal_sections); |
2227 | 2228 | ||
2229 | if (!interleave_sectors) | ||
2230 | interleave_sectors = DEFAULT_INTERLEAVE_SECTORS; | ||
2228 | ic->sb->log2_interleave_sectors = __fls(interleave_sectors); | 2231 | ic->sb->log2_interleave_sectors = __fls(interleave_sectors); |
2229 | ic->sb->log2_interleave_sectors = max((__u8)MIN_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors); | 2232 | ic->sb->log2_interleave_sectors = max((__u8)MIN_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors); |
2230 | ic->sb->log2_interleave_sectors = min((__u8)MAX_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors); | 2233 | ic->sb->log2_interleave_sectors = min((__u8)MAX_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors); |
2231 | 2234 | ||
2232 | ic->provided_data_sectors = 0; | 2235 | ic->provided_data_sectors = 0; |
2233 | for (test_bit = fls64(ic->device_sectors) - 1; test_bit >= 3; test_bit--) { | 2236 | for (test_bit = fls64(ic->device_sectors) - 1; test_bit >= 3; test_bit--) { |
@@ -2238,7 +2241,7 @@ static int initialize_superblock(struct dm_integrity_c *ic, unsigned journal_sec | |||
2238 | ic->provided_data_sectors = prev_data_sectors; | 2241 | ic->provided_data_sectors = prev_data_sectors; |
2239 | } | 2242 | } |
2240 | 2243 | ||
2241 | if (!le64_to_cpu(ic->provided_data_sectors)) | 2244 | if (!ic->provided_data_sectors) |
2242 | return -EINVAL; | 2245 | return -EINVAL; |
2243 | 2246 | ||
2244 | ic->sb->provided_data_sectors = cpu_to_le64(ic->provided_data_sectors); | 2247 | ic->sb->provided_data_sectors = cpu_to_le64(ic->provided_data_sectors); |
@@ -2444,6 +2447,12 @@ static int create_journal(struct dm_integrity_c *ic, char **error) | |||
2444 | int r = 0; | 2447 | int r = 0; |
2445 | unsigned i; | 2448 | unsigned i; |
2446 | __u64 journal_pages, journal_desc_size, journal_tree_size; | 2449 | __u64 journal_pages, journal_desc_size, journal_tree_size; |
2450 | unsigned char *crypt_data = NULL; | ||
2451 | |||
2452 | ic->commit_ids[0] = cpu_to_le64(0x1111111111111111ULL); | ||
2453 | ic->commit_ids[1] = cpu_to_le64(0x2222222222222222ULL); | ||
2454 | ic->commit_ids[2] = cpu_to_le64(0x3333333333333333ULL); | ||
2455 | ic->commit_ids[3] = cpu_to_le64(0x4444444444444444ULL); | ||
2447 | 2456 | ||
2448 | journal_pages = roundup((__u64)ic->journal_sections * ic->journal_section_sectors, | 2457 | journal_pages = roundup((__u64)ic->journal_sections * ic->journal_section_sectors, |
2449 | PAGE_SIZE >> SECTOR_SHIFT) >> (PAGE_SHIFT - SECTOR_SHIFT); | 2458 | PAGE_SIZE >> SECTOR_SHIFT) >> (PAGE_SHIFT - SECTOR_SHIFT); |
@@ -2541,7 +2550,13 @@ static int create_journal(struct dm_integrity_c *ic, char **error) | |||
2541 | SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt); | 2550 | SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt); |
2542 | unsigned char iv[ivsize]; | 2551 | unsigned char iv[ivsize]; |
2543 | unsigned crypt_len = roundup(ivsize, blocksize); | 2552 | unsigned crypt_len = roundup(ivsize, blocksize); |
2544 | unsigned char crypt_data[crypt_len]; | 2553 | |
2554 | crypt_data = kmalloc(crypt_len, GFP_KERNEL); | ||
2555 | if (!crypt_data) { | ||
2556 | *error = "Unable to allocate crypt data"; | ||
2557 | r = -ENOMEM; | ||
2558 | goto bad; | ||
2559 | } | ||
2545 | 2560 | ||
2546 | skcipher_request_set_tfm(req, ic->journal_crypt); | 2561 | skcipher_request_set_tfm(req, ic->journal_crypt); |
2547 | 2562 | ||
@@ -2630,38 +2645,38 @@ retest_commit_id: | |||
2630 | r = -ENOMEM; | 2645 | r = -ENOMEM; |
2631 | } | 2646 | } |
2632 | bad: | 2647 | bad: |
2648 | kfree(crypt_data); | ||
2633 | return r; | 2649 | return r; |
2634 | } | 2650 | } |
2635 | 2651 | ||
2636 | /* | 2652 | /* |
2637 | * Construct a integrity mapping: <dev_path> <offset> <tag_size> | 2653 | * Construct a integrity mapping |
2638 | * | 2654 | * |
2639 | * Arguments: | 2655 | * Arguments: |
2640 | * device | 2656 | * device |
2641 | * offset from the start of the device | 2657 | * offset from the start of the device |
2642 | * tag size | 2658 | * tag size |
2643 | * D - direct writes, J - journal writes | 2659 | * D - direct writes, J - journal writes, R - recovery mode |
2644 | * number of optional arguments | 2660 | * number of optional arguments |
2645 | * optional arguments: | 2661 | * optional arguments: |
2646 | * journal-sectors | 2662 | * journal_sectors |
2647 | * interleave-sectors | 2663 | * interleave_sectors |
2648 | * buffer-sectors | 2664 | * buffer_sectors |
2649 | * journal-watermark | 2665 | * journal_watermark |
2650 | * commit-time | 2666 | * commit_time |
2651 | * internal-hash | 2667 | * internal_hash |
2652 | * journal-crypt | 2668 | * journal_crypt |
2653 | * journal-mac | 2669 | * journal_mac |
2654 | */ | 2670 | */ |
2655 | static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) | 2671 | static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) |
2656 | { | 2672 | { |
2657 | struct dm_integrity_c *ic; | 2673 | struct dm_integrity_c *ic; |
2658 | char dummy; | 2674 | char dummy; |
2659 | int r; | 2675 | int r; |
2660 | unsigned i; | ||
2661 | unsigned extra_args; | 2676 | unsigned extra_args; |
2662 | struct dm_arg_set as; | 2677 | struct dm_arg_set as; |
2663 | static struct dm_arg _args[] = { | 2678 | static struct dm_arg _args[] = { |
2664 | {0, 7, "Invalid number of feature args"}, | 2679 | {0, 8, "Invalid number of feature args"}, |
2665 | }; | 2680 | }; |
2666 | unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec; | 2681 | unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec; |
2667 | bool should_write_sb; | 2682 | bool should_write_sb; |
@@ -2683,11 +2698,6 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
2683 | ti->private = ic; | 2698 | ti->private = ic; |
2684 | ti->per_io_data_size = sizeof(struct dm_integrity_io); | 2699 | ti->per_io_data_size = sizeof(struct dm_integrity_io); |
2685 | 2700 | ||
2686 | ic->commit_ids[0] = cpu_to_le64(0x1111111111111111ULL); | ||
2687 | ic->commit_ids[1] = cpu_to_le64(0x2222222222222222ULL); | ||
2688 | ic->commit_ids[2] = cpu_to_le64(0x3333333333333333ULL); | ||
2689 | ic->commit_ids[3] = cpu_to_le64(0x4444444444444444ULL); | ||
2690 | |||
2691 | ic->in_progress = RB_ROOT; | 2701 | ic->in_progress = RB_ROOT; |
2692 | init_waitqueue_head(&ic->endio_wait); | 2702 | init_waitqueue_head(&ic->endio_wait); |
2693 | bio_list_init(&ic->flush_bio_list); | 2703 | bio_list_init(&ic->flush_bio_list); |
@@ -2718,7 +2728,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
2718 | if (!strcmp(argv[3], "J") || !strcmp(argv[3], "D") || !strcmp(argv[3], "R")) | 2728 | if (!strcmp(argv[3], "J") || !strcmp(argv[3], "D") || !strcmp(argv[3], "R")) |
2719 | ic->mode = argv[3][0]; | 2729 | ic->mode = argv[3][0]; |
2720 | else { | 2730 | else { |
2721 | ti->error = "Invalid mode (expecting J or D)"; | 2731 | ti->error = "Invalid mode (expecting J, D, R)"; |
2722 | r = -EINVAL; | 2732 | r = -EINVAL; |
2723 | goto bad; | 2733 | goto bad; |
2724 | } | 2734 | } |
@@ -2746,29 +2756,29 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
2746 | ti->error = "Not enough feature arguments"; | 2756 | ti->error = "Not enough feature arguments"; |
2747 | goto bad; | 2757 | goto bad; |
2748 | } | 2758 | } |
2749 | if (sscanf(opt_string, "journal-sectors:%u%c", &val, &dummy) == 1) | 2759 | if (sscanf(opt_string, "journal_sectors:%u%c", &val, &dummy) == 1) |
2750 | journal_sectors = val; | 2760 | journal_sectors = val; |
2751 | else if (sscanf(opt_string, "interleave-sectors:%u%c", &val, &dummy) == 1) | 2761 | else if (sscanf(opt_string, "interleave_sectors:%u%c", &val, &dummy) == 1) |
2752 | interleave_sectors = val; | 2762 | interleave_sectors = val; |
2753 | else if (sscanf(opt_string, "buffer-sectors:%u%c", &val, &dummy) == 1) | 2763 | else if (sscanf(opt_string, "buffer_sectors:%u%c", &val, &dummy) == 1) |
2754 | buffer_sectors = val; | 2764 | buffer_sectors = val; |
2755 | else if (sscanf(opt_string, "journal-watermark:%u%c", &val, &dummy) == 1 && val <= 100) | 2765 | else if (sscanf(opt_string, "journal_watermark:%u%c", &val, &dummy) == 1 && val <= 100) |
2756 | journal_watermark = val; | 2766 | journal_watermark = val; |
2757 | else if (sscanf(opt_string, "commit-time:%u%c", &val, &dummy) == 1) | 2767 | else if (sscanf(opt_string, "commit_time:%u%c", &val, &dummy) == 1) |
2758 | sync_msec = val; | 2768 | sync_msec = val; |
2759 | else if (!memcmp(opt_string, "internal-hash:", strlen("internal-hash:"))) { | 2769 | else if (!memcmp(opt_string, "internal_hash:", strlen("internal_hash:"))) { |
2760 | r = get_alg_and_key(opt_string, &ic->internal_hash_alg, &ti->error, | 2770 | r = get_alg_and_key(opt_string, &ic->internal_hash_alg, &ti->error, |
2761 | "Invalid internal-hash argument"); | 2771 | "Invalid internal_hash argument"); |
2762 | if (r) | 2772 | if (r) |
2763 | goto bad; | 2773 | goto bad; |
2764 | } else if (!memcmp(opt_string, "journal-crypt:", strlen("journal-crypt:"))) { | 2774 | } else if (!memcmp(opt_string, "journal_crypt:", strlen("journal_crypt:"))) { |
2765 | r = get_alg_and_key(opt_string, &ic->journal_crypt_alg, &ti->error, | 2775 | r = get_alg_and_key(opt_string, &ic->journal_crypt_alg, &ti->error, |
2766 | "Invalid journal-crypt argument"); | 2776 | "Invalid journal_crypt argument"); |
2767 | if (r) | 2777 | if (r) |
2768 | goto bad; | 2778 | goto bad; |
2769 | } else if (!memcmp(opt_string, "journal-mac:", strlen("journal-mac:"))) { | 2779 | } else if (!memcmp(opt_string, "journal_mac:", strlen("journal_mac:"))) { |
2770 | r = get_alg_and_key(opt_string, &ic->journal_mac_alg, &ti->error, | 2780 | r = get_alg_and_key(opt_string, &ic->journal_mac_alg, &ti->error, |
2771 | "Invalid journal-mac argument"); | 2781 | "Invalid journal_mac argument"); |
2772 | if (r) | 2782 | if (r) |
2773 | goto bad; | 2783 | goto bad; |
2774 | } else { | 2784 | } else { |
@@ -2877,12 +2887,10 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
2877 | should_write_sb = false; | 2887 | should_write_sb = false; |
2878 | if (memcmp(ic->sb->magic, SB_MAGIC, 8)) { | 2888 | if (memcmp(ic->sb->magic, SB_MAGIC, 8)) { |
2879 | if (ic->mode != 'R') { | 2889 | if (ic->mode != 'R') { |
2880 | for (i = 0; i < 512; i += 8) { | 2890 | if (memchr_inv(ic->sb, 0, SB_SECTORS << SECTOR_SHIFT)) { |
2881 | if (*(__u64 *)((__u8 *)ic->sb + i)) { | 2891 | r = -EINVAL; |
2882 | r = -EINVAL; | 2892 | ti->error = "The device is not initialized"; |
2883 | ti->error = "The device is not initialized"; | 2893 | goto bad; |
2884 | goto bad; | ||
2885 | } | ||
2886 | } | 2894 | } |
2887 | } | 2895 | } |
2888 | 2896 | ||
@@ -2906,8 +2914,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
2906 | goto bad; | 2914 | goto bad; |
2907 | } | 2915 | } |
2908 | /* make sure that ti->max_io_len doesn't overflow */ | 2916 | /* make sure that ti->max_io_len doesn't overflow */ |
2909 | if (ic->sb->log2_interleave_sectors < MIN_INTERLEAVE_SECTORS || | 2917 | if (ic->sb->log2_interleave_sectors < MIN_LOG2_INTERLEAVE_SECTORS || |
2910 | ic->sb->log2_interleave_sectors > MAX_INTERLEAVE_SECTORS) { | 2918 | ic->sb->log2_interleave_sectors > MAX_LOG2_INTERLEAVE_SECTORS) { |
2911 | r = -EINVAL; | 2919 | r = -EINVAL; |
2912 | ti->error = "Invalid interleave_sectors in the superblock"; | 2920 | ti->error = "Invalid interleave_sectors in the superblock"; |
2913 | goto bad; | 2921 | goto bad; |