static int create_journal()

in dm-integrity.c [3701:3936]


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;
	unsigned char *crypt_data = NULL, *crypt_iv = NULL;
	struct skcipher_request *req = 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);
	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->journal_pages);
	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, CRYPTO_ALG_ALLOCATES_MEMORY);
		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->journal_pages);
		if (!ic->journal_io) {
			*error = "Could not allocate memory for journal io";
			r = -ENOMEM;
			goto bad;
		}

		if (blocksize == 1) {
			struct scatterlist *sg;

			req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL);
			if (!req) {
				*error = "Could not allocate crypt request";
				r = -ENOMEM;
				goto bad;
			}

			crypt_iv = kzalloc(ivsize, GFP_KERNEL);
			if (!crypt_iv) {
				*error = "Could not allocate iv";
				r = -ENOMEM;
				goto bad;
			}

			ic->journal_xor = dm_integrity_alloc_page_list(ic->journal_pages);
			if (!ic->journal_xor) {
				*error = "Could not allocate memory for journal xor";
				r = -ENOMEM;
				goto bad;
			}

			sg = kvmalloc_array(ic->journal_pages + 1,
					    sizeof(struct scatterlist),
					    GFP_KERNEL);
			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);

			skcipher_request_set_crypt(req, sg, sg,
						   PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv);
			init_completion(&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 {
			unsigned crypt_len = roundup(ivsize, blocksize);

			req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL);
			if (!req) {
				*error = "Could not allocate crypt request";
				r = -ENOMEM;
				goto bad;
			}

			crypt_iv = kmalloc(ivsize, GFP_KERNEL);
			if (!crypt_iv) {
				*error = "Could not allocate iv";
				r = -ENOMEM;
				goto bad;
			}

			crypt_data = kmalloc(crypt_len, GFP_KERNEL);
			if (!crypt_data) {
				*error = "Unable to allocate crypt data";
				r = -ENOMEM;
				goto bad;
			}

			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 = kvmalloc_array(ic->journal_sections,
							 sizeof(struct skcipher_request *),
							 GFP_KERNEL | __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;
				__le32 section_le = cpu_to_le32(i);

				memset(crypt_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, crypt_iv);
				init_completion(&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_array(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 = kvmalloc(journal_tree_size, GFP_KERNEL);
	if (!ic->journal_tree) {
		*error = "Could not allocate memory for journal tree";
		r = -ENOMEM;
	}
bad:
	kfree(crypt_data);
	kfree(crypt_iv);
	skcipher_request_free(req);

	return r;
}