Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm verity: switch to using asynchronous hash crypto API

Use of the synchronous digest API limits dm-verity to using pure
CPU based algorithm providers and rules out the use of off CPU
algorithm providers which are normally asynchronous by nature,
potentially freeing CPU cycles.

This can reduce performance per Watt in situations such as during
boot time when a lot of concurrent file accesses are made to the
protected volume.

Signed-off-by: Gilad Ben-Yossef <gilad@benyossef.com>
CC: Eric Biggers <ebiggers3@gmail.com>
CC: Ondrej Mosnáček <omosnacek+linux-crypto@gmail.com>
Tested-by: Milan Broz <gmazyland@gmail.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>

authored by

Gilad Ben-Yossef and committed by
Mike Snitzer
d1ac3ff0 a1b89132

+160 -74
+2 -2
drivers/md/dm-verity-fec.c
··· 188 188 static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io, 189 189 u8 *want_digest, u8 *data) 190 190 { 191 - if (unlikely(verity_hash(v, verity_io_hash_desc(v, io), 191 + if (unlikely(verity_hash(v, verity_io_hash_req(v, io), 192 192 data, 1 << v->data_dev_block_bits, 193 193 verity_io_real_digest(v, io)))) 194 194 return 0; ··· 397 397 } 398 398 399 399 /* Always re-validate the corrected block against the expected hash */ 400 - r = verity_hash(v, verity_io_hash_desc(v, io), fio->output, 400 + r = verity_hash(v, verity_io_hash_req(v, io), fio->output, 401 401 1 << v->data_dev_block_bits, 402 402 verity_io_real_digest(v, io)); 403 403 if (unlikely(r < 0))
+144 -63
drivers/md/dm-verity-target.c
··· 93 93 } 94 94 95 95 /* 96 - * Wrapper for crypto_shash_init, which handles verity salting. 96 + * Callback function for asynchrnous crypto API completion notification 97 97 */ 98 - static int verity_hash_init(struct dm_verity *v, struct shash_desc *desc) 98 + static void verity_op_done(struct crypto_async_request *base, int err) 99 + { 100 + struct verity_result *res = (struct verity_result *)base->data; 101 + 102 + if (err == -EINPROGRESS) 103 + return; 104 + 105 + res->err = err; 106 + complete(&res->completion); 107 + } 108 + 109 + /* 110 + * Wait for async crypto API callback 111 + */ 112 + static inline int verity_complete_op(struct verity_result *res, int ret) 113 + { 114 + switch (ret) { 115 + case 0: 116 + break; 117 + 118 + case -EINPROGRESS: 119 + case -EBUSY: 120 + ret = wait_for_completion_interruptible(&res->completion); 121 + if (!ret) 122 + ret = res->err; 123 + reinit_completion(&res->completion); 124 + break; 125 + 126 + default: 127 + DMERR("verity_wait_hash: crypto op submission failed: %d", ret); 128 + } 129 + 130 + if (unlikely(ret < 0)) 131 + DMERR("verity_wait_hash: crypto op failed: %d", ret); 132 + 133 + return ret; 134 + } 135 + 136 + static int verity_hash_update(struct dm_verity *v, struct ahash_request *req, 137 + const u8 *data, size_t len, 138 + struct verity_result *res) 139 + { 140 + struct scatterlist sg; 141 + 142 + sg_init_one(&sg, data, len); 143 + ahash_request_set_crypt(req, &sg, NULL, len); 144 + 145 + return verity_complete_op(res, crypto_ahash_update(req)); 146 + } 147 + 148 + /* 149 + * Wrapper for crypto_ahash_init, which handles verity salting. 150 + */ 151 + static int verity_hash_init(struct dm_verity *v, struct ahash_request *req, 152 + struct verity_result *res) 99 153 { 100 154 int r; 101 155 102 - desc->tfm = v->tfm; 103 - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; 156 + ahash_request_set_tfm(req, v->tfm); 157 + ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP | 158 + CRYPTO_TFM_REQ_MAY_BACKLOG, 159 + verity_op_done, (void *)res); 160 + init_completion(&res->completion); 104 161 105 - r = crypto_shash_init(desc); 162 + r = verity_complete_op(res, crypto_ahash_init(req)); 106 163 107 164 if (unlikely(r < 0)) { 108 - DMERR("crypto_shash_init failed: %d", r); 165 + DMERR("crypto_ahash_init failed: %d", r); 109 166 return r; 110 167 } 111 168 112 - if (likely(v->version >= 1)) { 113 - r = crypto_shash_update(desc, v->salt, v->salt_size); 114 - 115 - if (unlikely(r < 0)) { 116 - DMERR("crypto_shash_update failed: %d", r); 117 - return r; 118 - } 119 - } 120 - 121 - return 0; 122 - } 123 - 124 - static int verity_hash_update(struct dm_verity *v, struct shash_desc *desc, 125 - const u8 *data, size_t len) 126 - { 127 - int r = crypto_shash_update(desc, data, len); 128 - 129 - if (unlikely(r < 0)) 130 - DMERR("crypto_shash_update failed: %d", r); 169 + if (likely(v->version >= 1)) 170 + r = verity_hash_update(v, req, v->salt, v->salt_size, res); 131 171 132 172 return r; 133 173 } 134 174 135 - static int verity_hash_final(struct dm_verity *v, struct shash_desc *desc, 136 - u8 *digest) 175 + static int verity_hash_final(struct dm_verity *v, struct ahash_request *req, 176 + u8 *digest, struct verity_result *res) 137 177 { 138 178 int r; 139 179 140 180 if (unlikely(!v->version)) { 141 - r = crypto_shash_update(desc, v->salt, v->salt_size); 181 + r = verity_hash_update(v, req, v->salt, v->salt_size, res); 142 182 143 183 if (r < 0) { 144 - DMERR("crypto_shash_update failed: %d", r); 145 - return r; 184 + DMERR("verity_hash_final failed updating salt: %d", r); 185 + goto out; 146 186 } 147 187 } 148 188 149 - r = crypto_shash_final(desc, digest); 150 - 151 - if (unlikely(r < 0)) 152 - DMERR("crypto_shash_final failed: %d", r); 153 - 189 + ahash_request_set_crypt(req, NULL, digest, 0); 190 + r = verity_complete_op(res, crypto_ahash_final(req)); 191 + out: 154 192 return r; 155 193 } 156 194 157 - int verity_hash(struct dm_verity *v, struct shash_desc *desc, 195 + int verity_hash(struct dm_verity *v, struct ahash_request *req, 158 196 const u8 *data, size_t len, u8 *digest) 159 197 { 160 198 int r; 199 + struct verity_result res; 161 200 162 - r = verity_hash_init(v, desc); 201 + r = verity_hash_init(v, req, &res); 163 202 if (unlikely(r < 0)) 164 - return r; 203 + goto out; 165 204 166 - r = verity_hash_update(v, desc, data, len); 205 + r = verity_hash_update(v, req, data, len, &res); 167 206 if (unlikely(r < 0)) 168 - return r; 207 + goto out; 169 208 170 - return verity_hash_final(v, desc, digest); 209 + r = verity_hash_final(v, req, digest, &res); 210 + 211 + out: 212 + return r; 171 213 } 172 214 173 215 static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level, ··· 317 275 goto release_ret_r; 318 276 } 319 277 320 - r = verity_hash(v, verity_io_hash_desc(v, io), 278 + r = verity_hash(v, verity_io_hash_req(v, io), 321 279 data, 1 << v->hash_dev_block_bits, 322 280 verity_io_real_digest(v, io)); 323 281 if (unlikely(r < 0)) ··· 386 344 } 387 345 388 346 /* 347 + * Calculates the digest for the given bio 348 + */ 349 + int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io, 350 + struct bvec_iter *iter, struct verity_result *res) 351 + { 352 + unsigned int todo = 1 << v->data_dev_block_bits; 353 + struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size); 354 + struct scatterlist sg; 355 + struct ahash_request *req = verity_io_hash_req(v, io); 356 + 357 + do { 358 + int r; 359 + unsigned int len; 360 + struct bio_vec bv = bio_iter_iovec(bio, *iter); 361 + 362 + sg_init_table(&sg, 1); 363 + 364 + len = bv.bv_len; 365 + 366 + if (likely(len >= todo)) 367 + len = todo; 368 + /* 369 + * Operating on a single page at a time looks suboptimal 370 + * until you consider the typical block size is 4,096B. 371 + * Going through this loops twice should be very rare. 372 + */ 373 + sg_set_page(&sg, bv.bv_page, len, bv.bv_offset); 374 + ahash_request_set_crypt(req, &sg, NULL, len); 375 + r = verity_complete_op(res, crypto_ahash_update(req)); 376 + 377 + if (unlikely(r < 0)) { 378 + DMERR("verity_for_io_block crypto op failed: %d", r); 379 + return r; 380 + } 381 + 382 + bio_advance_iter(bio, iter, len); 383 + todo -= len; 384 + } while (todo); 385 + 386 + return 0; 387 + } 388 + 389 + /* 389 390 * Calls function process for 1 << v->data_dev_block_bits bytes in the bio_vec 390 391 * starting from iter. 391 392 */ ··· 466 381 return 0; 467 382 } 468 383 469 - static int verity_bv_hash_update(struct dm_verity *v, struct dm_verity_io *io, 470 - u8 *data, size_t len) 471 - { 472 - return verity_hash_update(v, verity_io_hash_desc(v, io), data, len); 473 - } 474 - 475 384 static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io, 476 385 u8 *data, size_t len) 477 386 { ··· 482 403 struct dm_verity *v = io->v; 483 404 struct bvec_iter start; 484 405 unsigned b; 406 + struct verity_result res; 485 407 486 408 for (b = 0; b < io->n_blocks; b++) { 487 409 int r; 488 - struct shash_desc *desc = verity_io_hash_desc(v, io); 410 + struct ahash_request *req = verity_io_hash_req(v, io); 489 411 490 412 r = verity_hash_for_block(v, io, io->block + b, 491 413 verity_io_want_digest(v, io), ··· 507 427 continue; 508 428 } 509 429 510 - r = verity_hash_init(v, desc); 430 + r = verity_hash_init(v, req, &res); 511 431 if (unlikely(r < 0)) 512 432 return r; 513 433 514 434 start = io->iter; 515 - r = verity_for_bv_block(v, io, &io->iter, verity_bv_hash_update); 435 + r = verity_for_io_block(v, io, &io->iter, &res); 516 436 if (unlikely(r < 0)) 517 437 return r; 518 438 519 - r = verity_hash_final(v, desc, verity_io_real_digest(v, io)); 439 + r = verity_hash_final(v, req, verity_io_real_digest(v, io), 440 + &res); 520 441 if (unlikely(r < 0)) 521 442 return r; 522 443 ··· 786 705 kfree(v->zero_digest); 787 706 788 707 if (v->tfm) 789 - crypto_free_shash(v->tfm); 708 + crypto_free_ahash(v->tfm); 790 709 791 710 kfree(v->alg_name); 792 711 ··· 804 723 static int verity_alloc_zero_digest(struct dm_verity *v) 805 724 { 806 725 int r = -ENOMEM; 807 - struct shash_desc *desc; 726 + struct ahash_request *req; 808 727 u8 *zero_data; 809 728 810 729 v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL); ··· 812 731 if (!v->zero_digest) 813 732 return r; 814 733 815 - desc = kmalloc(v->shash_descsize, GFP_KERNEL); 734 + req = kmalloc(v->ahash_reqsize, GFP_KERNEL); 816 735 817 - if (!desc) 736 + if (!req) 818 737 return r; /* verity_dtr will free zero_digest */ 819 738 820 739 zero_data = kzalloc(1 << v->data_dev_block_bits, GFP_KERNEL); ··· 822 741 if (!zero_data) 823 742 goto out; 824 743 825 - r = verity_hash(v, desc, zero_data, 1 << v->data_dev_block_bits, 744 + r = verity_hash(v, req, zero_data, 1 << v->data_dev_block_bits, 826 745 v->zero_digest); 827 746 828 747 out: 829 - kfree(desc); 748 + kfree(req); 830 749 kfree(zero_data); 831 750 832 751 return r; ··· 1004 923 goto bad; 1005 924 } 1006 925 1007 - v->tfm = crypto_alloc_shash(v->alg_name, 0, 0); 926 + v->tfm = crypto_alloc_ahash(v->alg_name, 0, 0); 1008 927 if (IS_ERR(v->tfm)) { 1009 928 ti->error = "Cannot initialize hash function"; 1010 929 r = PTR_ERR(v->tfm); 1011 930 v->tfm = NULL; 1012 931 goto bad; 1013 932 } 1014 - v->digest_size = crypto_shash_digestsize(v->tfm); 933 + v->digest_size = crypto_ahash_digestsize(v->tfm); 1015 934 if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) { 1016 935 ti->error = "Digest size too big"; 1017 936 r = -EINVAL; 1018 937 goto bad; 1019 938 } 1020 - v->shash_descsize = 1021 - sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm); 939 + v->ahash_reqsize = sizeof(struct ahash_request) + 940 + crypto_ahash_reqsize(v->tfm); 1022 941 1023 942 v->root_digest = kmalloc(v->digest_size, GFP_KERNEL); 1024 943 if (!v->root_digest) { ··· 1118 1037 } 1119 1038 1120 1039 ti->per_io_data_size = sizeof(struct dm_verity_io) + 1121 - v->shash_descsize + v->digest_size * 2; 1040 + v->ahash_reqsize + v->digest_size * 2; 1122 1041 1123 1042 r = verity_fec_ctr(v); 1124 1043 if (r)
+14 -9
drivers/md/dm-verity.h
··· 37 37 struct dm_target *ti; 38 38 struct dm_bufio_client *bufio; 39 39 char *alg_name; 40 - struct crypto_shash *tfm; 40 + struct crypto_ahash *tfm; 41 41 u8 *root_digest; /* digest of the root block */ 42 42 u8 *salt; /* salt: its size is salt_size */ 43 43 u8 *zero_digest; /* digest for a zero block */ ··· 52 52 unsigned char levels; /* the number of tree levels */ 53 53 unsigned char version; 54 54 unsigned digest_size; /* digest size for the current hash algorithm */ 55 - unsigned shash_descsize;/* the size of temporary space for crypto */ 55 + unsigned int ahash_reqsize;/* the size of temporary space for crypto */ 56 56 int hash_failed; /* set to 1 if hash of any block failed */ 57 57 enum verity_mode mode; /* mode for handling verification errors */ 58 58 unsigned corrupted_errs;/* Number of errors for corrupted blocks */ ··· 81 81 /* 82 82 * Three variably-size fields follow this struct: 83 83 * 84 - * u8 hash_desc[v->shash_descsize]; 84 + * u8 hash_req[v->ahash_reqsize]; 85 85 * u8 real_digest[v->digest_size]; 86 86 * u8 want_digest[v->digest_size]; 87 87 * 88 - * To access them use: verity_io_hash_desc(), verity_io_real_digest() 88 + * To access them use: verity_io_hash_req(), verity_io_real_digest() 89 89 * and verity_io_want_digest(). 90 90 */ 91 91 }; 92 92 93 - static inline struct shash_desc *verity_io_hash_desc(struct dm_verity *v, 93 + struct verity_result { 94 + struct completion completion; 95 + int err; 96 + }; 97 + 98 + static inline struct ahash_request *verity_io_hash_req(struct dm_verity *v, 94 99 struct dm_verity_io *io) 95 100 { 96 - return (struct shash_desc *)(io + 1); 101 + return (struct ahash_request *)(io + 1); 97 102 } 98 103 99 104 static inline u8 *verity_io_real_digest(struct dm_verity *v, 100 105 struct dm_verity_io *io) 101 106 { 102 - return (u8 *)(io + 1) + v->shash_descsize; 107 + return (u8 *)(io + 1) + v->ahash_reqsize; 103 108 } 104 109 105 110 static inline u8 *verity_io_want_digest(struct dm_verity *v, 106 111 struct dm_verity_io *io) 107 112 { 108 - return (u8 *)(io + 1) + v->shash_descsize + v->digest_size; 113 + return (u8 *)(io + 1) + v->ahash_reqsize + v->digest_size; 109 114 } 110 115 111 116 static inline u8 *verity_io_digest_end(struct dm_verity *v, ··· 125 120 struct dm_verity_io *io, 126 121 u8 *data, size_t len)); 127 122 128 - extern int verity_hash(struct dm_verity *v, struct shash_desc *desc, 123 + extern int verity_hash(struct dm_verity *v, struct ahash_request *req, 129 124 const u8 *data, size_t len, u8 *digest); 130 125 131 126 extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,