summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm-integrity.c379
1 files changed, 196 insertions, 183 deletions
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index ea779cca8b45..ecb0b592f5a0 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -2429,6 +2429,200 @@ static int get_mac(struct crypto_shash **hash, struct alg_spec *a, char **error,
return 0;
}
+static int create_journal(struct dm_integrity_c *ic, char **error)
+{
+ int r = 0;
+ unsigned i;
+ __u64 journal_pages, journal_desc_size, journal_tree_size;
+
+ journal_pages = roundup((__u64)ic->journal_sections * ic->journal_section_sectors,
+ PAGE_SIZE >> SECTOR_SHIFT) >> (PAGE_SHIFT - SECTOR_SHIFT);
+ journal_desc_size = journal_pages * sizeof(struct page_list);
+ if (journal_pages >= totalram_pages - totalhigh_pages || journal_desc_size > ULONG_MAX) {
+ *error = "Journal doesn't fit into memory";
+ r = -ENOMEM;
+ goto bad;
+ }
+ ic->journal_pages = journal_pages;
+
+ ic->journal = dm_integrity_alloc_page_list(ic);
+ if (!ic->journal) {
+ *error = "Could not allocate memory for journal";
+ r = -ENOMEM;
+ goto bad;
+ }
+ if (ic->journal_crypt_alg.alg_string) {
+ unsigned ivsize, blocksize;
+ struct journal_completion comp;
+
+ comp.ic = ic;
+ ic->journal_crypt = crypto_alloc_skcipher(ic->journal_crypt_alg.alg_string, 0, 0);
+ if (IS_ERR(ic->journal_crypt)) {
+ *error = "Invalid journal cipher";
+ r = PTR_ERR(ic->journal_crypt);
+ ic->journal_crypt = NULL;
+ goto bad;
+ }
+ ivsize = crypto_skcipher_ivsize(ic->journal_crypt);
+ blocksize = crypto_skcipher_blocksize(ic->journal_crypt);
+
+ if (ic->journal_crypt_alg.key) {
+ r = crypto_skcipher_setkey(ic->journal_crypt, ic->journal_crypt_alg.key,
+ ic->journal_crypt_alg.key_size);
+ if (r) {
+ *error = "Error setting encryption key";
+ goto bad;
+ }
+ }
+ DEBUG_print("cipher %s, block size %u iv size %u\n",
+ ic->journal_crypt_alg.alg_string, blocksize, ivsize);
+
+ ic->journal_io = dm_integrity_alloc_page_list(ic);
+ if (!ic->journal_io) {
+ *error = "Could not allocate memory for journal io";
+ r = -ENOMEM;
+ goto bad;
+ }
+
+ if (blocksize == 1) {
+ struct scatterlist *sg;
+ SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt);
+ unsigned char iv[ivsize];
+ skcipher_request_set_tfm(req, ic->journal_crypt);
+
+ ic->journal_xor = dm_integrity_alloc_page_list(ic);
+ if (!ic->journal_xor) {
+ *error = "Could not allocate memory for journal xor";
+ r = -ENOMEM;
+ goto bad;
+ }
+
+ sg = dm_integrity_kvmalloc((ic->journal_pages + 1) * sizeof(struct scatterlist), 0);
+ if (!sg) {
+ *error = "Unable to allocate sg list";
+ r = -ENOMEM;
+ goto bad;
+ }
+ sg_init_table(sg, ic->journal_pages + 1);
+ for (i = 0; i < ic->journal_pages; i++) {
+ char *va = lowmem_page_address(ic->journal_xor[i].page);
+ clear_page(va);
+ sg_set_buf(&sg[i], va, PAGE_SIZE);
+ }
+ sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids);
+ memset(iv, 0x00, ivsize);
+
+ skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, iv);
+ comp.comp = COMPLETION_INITIALIZER_ONSTACK(comp.comp);
+ comp.in_flight = (atomic_t)ATOMIC_INIT(1);
+ if (do_crypt(true, req, &comp))
+ wait_for_completion(&comp.comp);
+ kvfree(sg);
+ r = dm_integrity_failed(ic);
+ if (r) {
+ *error = "Unable to encrypt journal";
+ goto bad;
+ }
+ DEBUG_bytes(lowmem_page_address(ic->journal_xor[0].page), 64, "xor data");
+
+ crypto_free_skcipher(ic->journal_crypt);
+ ic->journal_crypt = NULL;
+ } else {
+ SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt);
+ unsigned char iv[ivsize];
+ unsigned crypt_len = roundup(ivsize, blocksize);
+ unsigned char crypt_data[crypt_len];
+
+ skcipher_request_set_tfm(req, ic->journal_crypt);
+
+ ic->journal_scatterlist = dm_integrity_alloc_journal_scatterlist(ic, ic->journal);
+ if (!ic->journal_scatterlist) {
+ *error = "Unable to allocate sg list";
+ r = -ENOMEM;
+ goto bad;
+ }
+ ic->journal_io_scatterlist = dm_integrity_alloc_journal_scatterlist(ic, ic->journal_io);
+ if (!ic->journal_io_scatterlist) {
+ *error = "Unable to allocate sg list";
+ r = -ENOMEM;
+ goto bad;
+ }
+ ic->sk_requests = dm_integrity_kvmalloc(ic->journal_sections * sizeof(struct skcipher_request *), __GFP_ZERO);
+ if (!ic->sk_requests) {
+ *error = "Unable to allocate sk requests";
+ r = -ENOMEM;
+ goto bad;
+ }
+ for (i = 0; i < ic->journal_sections; i++) {
+ struct scatterlist sg;
+ struct skcipher_request *section_req;
+ __u32 section_le = cpu_to_le32(i);
+
+ memset(iv, 0x00, ivsize);
+ memset(crypt_data, 0x00, crypt_len);
+ memcpy(crypt_data, &section_le, min((size_t)crypt_len, sizeof(section_le)));
+
+ sg_init_one(&sg, crypt_data, crypt_len);
+ skcipher_request_set_crypt(req, &sg, &sg, crypt_len, iv);
+ comp.comp = COMPLETION_INITIALIZER_ONSTACK(comp.comp);
+ comp.in_flight = (atomic_t)ATOMIC_INIT(1);
+ if (do_crypt(true, req, &comp))
+ wait_for_completion(&comp.comp);
+
+ r = dm_integrity_failed(ic);
+ if (r) {
+ *error = "Unable to generate iv";
+ goto bad;
+ }
+
+ section_req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL);
+ if (!section_req) {
+ *error = "Unable to allocate crypt request";
+ r = -ENOMEM;
+ goto bad;
+ }
+ section_req->iv = kmalloc(ivsize * 2, GFP_KERNEL);
+ if (!section_req->iv) {
+ skcipher_request_free(section_req);
+ *error = "Unable to allocate iv";
+ r = -ENOMEM;
+ goto bad;
+ }
+ memcpy(section_req->iv + ivsize, crypt_data, ivsize);
+ section_req->cryptlen = (size_t)ic->journal_section_sectors << SECTOR_SHIFT;
+ ic->sk_requests[i] = section_req;
+ DEBUG_bytes(crypt_data, ivsize, "iv(%u)", i);
+ }
+ }
+ }
+
+ for (i = 0; i < N_COMMIT_IDS; i++) {
+ unsigned j;
+retest_commit_id:
+ for (j = 0; j < i; j++) {
+ if (ic->commit_ids[j] == ic->commit_ids[i]) {
+ ic->commit_ids[i] = cpu_to_le64(le64_to_cpu(ic->commit_ids[i]) + 1);
+ goto retest_commit_id;
+ }
+ }
+ DEBUG_print("commit id %u: %016llx\n", i, ic->commit_ids[i]);
+ }
+
+ journal_tree_size = (__u64)ic->journal_entries * sizeof(struct journal_node);
+ if (journal_tree_size > ULONG_MAX) {
+ *error = "Journal doesn't fit into memory";
+ r = -ENOMEM;
+ goto bad;
+ }
+ ic->journal_tree = dm_integrity_kvmalloc(journal_tree_size, 0);
+ if (!ic->journal_tree) {
+ *error = "Could not allocate memory for journal tree";
+ r = -ENOMEM;
+ }
+bad:
+ return r;
+}
+
/*
* Construct a integrity mapping: <dev_path> <offset> <tag_size>
*
@@ -2461,7 +2655,6 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
};
unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
bool should_write_sb;
- __u64 journal_pages, journal_desc_size, journal_tree_size;
__u64 threshold;
unsigned long long start;
@@ -2761,189 +2954,9 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
}
dm_bufio_set_sector_offset(ic->bufio, ic->start + ic->initial_sectors);
- journal_pages = roundup((__u64)ic->journal_sections * ic->journal_section_sectors,
- PAGE_SIZE >> SECTOR_SHIFT) >> (PAGE_SHIFT - SECTOR_SHIFT);
- journal_desc_size = journal_pages * sizeof(struct page_list);
- if (journal_pages >= totalram_pages - totalhigh_pages || journal_desc_size > ULONG_MAX) {
- ti->error = "Journal doesn't fit into memory";
- r = -ENOMEM;
- goto bad;
- }
- ic->journal_pages = journal_pages;
-
- ic->journal = dm_integrity_alloc_page_list(ic);
- if (!ic->journal) {
- ti->error = "Could not allocate memory for journal";
- r = -ENOMEM;
- goto bad;
- }
- if (ic->journal_crypt_alg.alg_string) {
- unsigned ivsize, blocksize;
- struct journal_completion comp;
- comp.ic = ic;
-
- ic->journal_crypt = crypto_alloc_skcipher(ic->journal_crypt_alg.alg_string, 0, 0);
- if (IS_ERR(ic->journal_crypt)) {
- ti->error = "Invalid journal cipher";
- r = PTR_ERR(ic->journal_crypt);
- ic->journal_crypt = NULL;
- goto bad;
- }
- ivsize = crypto_skcipher_ivsize(ic->journal_crypt);
- blocksize = crypto_skcipher_blocksize(ic->journal_crypt);
-
- if (ic->journal_crypt_alg.key) {
- r = crypto_skcipher_setkey(ic->journal_crypt, ic->journal_crypt_alg.key,
- ic->journal_crypt_alg.key_size);
- if (r) {
- ti->error = "Error setting encryption key";
- goto bad;
- }
- }
- DEBUG_print("cipher %s, block size %u iv size %u\n",
- ic->journal_crypt_alg.alg_string, blocksize, ivsize);
-
- ic->journal_io = dm_integrity_alloc_page_list(ic);
- if (!ic->journal_io) {
- ti->error = "Could not allocate memory for journal io";
- r = -ENOMEM;
- goto bad;
- }
-
- if (blocksize == 1) {
- struct scatterlist *sg;
- SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt);
- unsigned char iv[ivsize];
- skcipher_request_set_tfm(req, ic->journal_crypt);
-
- ic->journal_xor = dm_integrity_alloc_page_list(ic);
- if (!ic->journal_xor) {
- ti->error = "Could not allocate memory for journal xor";
- r = -ENOMEM;
- goto bad;
- }
-
- sg = dm_integrity_kvmalloc((ic->journal_pages + 1) * sizeof(struct scatterlist), 0);
- if (!sg) {
- ti->error = "Unable to allocate sg list";
- r = -ENOMEM;
- goto bad;
- }
- sg_init_table(sg, ic->journal_pages + 1);
- for (i = 0; i < ic->journal_pages; i++) {
- char *va = lowmem_page_address(ic->journal_xor[i].page);
- clear_page(va);
- sg_set_buf(&sg[i], va, PAGE_SIZE);
- }
- sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids);
- memset(iv, 0x00, ivsize);
-
- skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, iv);
- comp.comp = COMPLETION_INITIALIZER_ONSTACK(comp.comp);
- comp.in_flight = (atomic_t)ATOMIC_INIT(1);
- if (do_crypt(true, req, &comp))
- wait_for_completion(&comp.comp);
- kvfree(sg);
- if ((r = dm_integrity_failed(ic))) {
- ti->error = "Unable to encrypt journal";
- goto bad;
- }
- DEBUG_bytes(lowmem_page_address(ic->journal_xor[0].page), 64, "xor data");
-
- crypto_free_skcipher(ic->journal_crypt);
- ic->journal_crypt = NULL;
- } else {
- SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt);
- unsigned char iv[ivsize];
- unsigned crypt_len = roundup(ivsize, blocksize);
- unsigned char crypt_data[crypt_len];
-
- skcipher_request_set_tfm(req, ic->journal_crypt);
-
- ic->journal_scatterlist = dm_integrity_alloc_journal_scatterlist(ic, ic->journal);
- if (!ic->journal_scatterlist) {
- ti->error = "Unable to allocate sg list";
- r = -ENOMEM;
- goto bad;
- }
- ic->journal_io_scatterlist = dm_integrity_alloc_journal_scatterlist(ic, ic->journal_io);
- if (!ic->journal_io_scatterlist) {
- ti->error = "Unable to allocate sg list";
- r = -ENOMEM;
- goto bad;
- }
- ic->sk_requests = dm_integrity_kvmalloc(ic->journal_sections * sizeof(struct skcipher_request *), __GFP_ZERO);
- if (!ic->sk_requests) {
- ti->error = "Unable to allocate sk requests";
- r = -ENOMEM;
- goto bad;
- }
- for (i = 0; i < ic->journal_sections; i++) {
- struct scatterlist sg;
- struct skcipher_request *section_req;
- __u32 section_le = cpu_to_le32(i);
-
- memset(iv, 0x00, ivsize);
- memset(crypt_data, 0x00, crypt_len);
- memcpy(crypt_data, &section_le, min((size_t)crypt_len, sizeof(section_le)));
-
- sg_init_one(&sg, crypt_data, crypt_len);
- skcipher_request_set_crypt(req, &sg, &sg, crypt_len, iv);
- comp.comp = COMPLETION_INITIALIZER_ONSTACK(comp.comp);
- comp.in_flight = (atomic_t)ATOMIC_INIT(1);
- if (do_crypt(true, req, &comp))
- wait_for_completion(&comp.comp);
-
- if ((r = dm_integrity_failed(ic))) {
- ti->error = "Unable to generate iv";
- goto bad;
- }
-
- section_req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL);
- if (!section_req) {
- ti->error = "Unable to allocate crypt request";
- r = -ENOMEM;
- goto bad;
- }
- section_req->iv = kmalloc(ivsize * 2, GFP_KERNEL);
- if (!section_req->iv) {
- skcipher_request_free(section_req);
- ti->error = "Unable to allocate iv";
- r = -ENOMEM;
- goto bad;
- }
- memcpy(section_req->iv + ivsize, crypt_data, ivsize);
- section_req->cryptlen = (size_t)ic->journal_section_sectors << SECTOR_SHIFT;
- ic->sk_requests[i] = section_req;
- DEBUG_bytes(crypt_data, ivsize, "iv(%u)", i);
- }
- }
- }
-
- for (i = 0; i < N_COMMIT_IDS; i++) {
- unsigned j;
-retest_commit_id:
- for (j = 0; j < i; j++) {
- if (ic->commit_ids[j] == ic->commit_ids[i]) {
- ic->commit_ids[i] = cpu_to_le64(le64_to_cpu(ic->commit_ids[i]) + 1);
- goto retest_commit_id;
- }
- }
- DEBUG_print("commit id %u: %016llx\n", i, ic->commit_ids[i]);
- }
-
- journal_tree_size = (__u64)ic->journal_entries * sizeof(struct journal_node);
- if (journal_tree_size > ULONG_MAX) {
- ti->error = "Journal doesn't fit into memory";
- r = -ENOMEM;
- goto bad;
- }
- ic->journal_tree = dm_integrity_kvmalloc(journal_tree_size, 0);
- if (!ic->journal_tree) {
- ti->error = "Could not allocate memory for journal tree";
- r = -ENOMEM;
+ r = create_journal(ic, &ti->error);
+ if (r)
goto bad;
- }
if (should_write_sb) {
int r;