summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilad Ben-Yossef <gilad@benyossef.com>2017-02-19 07:46:07 -0500
committerMike Snitzer <snitzer@redhat.com>2017-04-24 15:37:04 -0400
commitd1ac3ff008fb9a48f91fc15920b4c8db24c0f03e (patch)
tree564a6181d22925a9dfc25eb7c69af735a0f6c399
parenta1b89132dc4f61071bdeaab92ea958e0953380a1 (diff)
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>
-rw-r--r--drivers/md/dm-verity-fec.c4
-rw-r--r--drivers/md/dm-verity-target.c201
-rw-r--r--drivers/md/dm-verity.h23
3 files changed, 157 insertions, 71 deletions
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 0f0eb8a3d922..dab98fee0754 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -188,7 +188,7 @@ error:
188static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io, 188static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
189 u8 *want_digest, u8 *data) 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 data, 1 << v->data_dev_block_bits, 192 data, 1 << v->data_dev_block_bits,
193 verity_io_real_digest(v, io)))) 193 verity_io_real_digest(v, io))))
194 return 0; 194 return 0;
@@ -397,7 +397,7 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
397 } 397 }
398 398
399 /* Always re-validate the corrected block against the expected hash */ 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 1 << v->data_dev_block_bits, 401 1 << v->data_dev_block_bits,
402 verity_io_real_digest(v, io)); 402 verity_io_real_digest(v, io));
403 if (unlikely(r < 0)) 403 if (unlikely(r < 0))
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 7335d8a3fc47..97de961a3bfc 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -93,81 +93,123 @@ static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
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 */
98static int verity_hash_init(struct dm_verity *v, struct shash_desc *desc) 98static void verity_op_done(struct crypto_async_request *base, int err)
99{ 99{
100 int r; 100 struct verity_result *res = (struct verity_result *)base->data;
101 101
102 desc->tfm = v->tfm; 102 if (err == -EINPROGRESS)
103 desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; 103 return;
104 104
105 r = crypto_shash_init(desc); 105 res->err = err;
106 complete(&res->completion);
107}
106 108
107 if (unlikely(r < 0)) { 109/*
108 DMERR("crypto_shash_init failed: %d", r); 110 * Wait for async crypto API callback
109 return r; 111 */
110 } 112static inline int verity_complete_op(struct verity_result *res, int ret)
113{
114 switch (ret) {
115 case 0:
116 break;
111 117
112 if (likely(v->version >= 1)) { 118 case -EINPROGRESS:
113 r = crypto_shash_update(desc, v->salt, v->salt_size); 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;
114 125
115 if (unlikely(r < 0)) { 126 default:
116 DMERR("crypto_shash_update failed: %d", r); 127 DMERR("verity_wait_hash: crypto op submission failed: %d", ret);
117 return r;
118 }
119 } 128 }
120 129
121 return 0; 130 if (unlikely(ret < 0))
131 DMERR("verity_wait_hash: crypto op failed: %d", ret);
132
133 return ret;
122} 134}
123 135
124static int verity_hash_update(struct dm_verity *v, struct shash_desc *desc, 136static int verity_hash_update(struct dm_verity *v, struct ahash_request *req,
125 const u8 *data, size_t len) 137 const u8 *data, size_t len,
138 struct verity_result *res)
126{ 139{
127 int r = crypto_shash_update(desc, data, len); 140 struct scatterlist sg;
128 141
129 if (unlikely(r < 0)) 142 sg_init_one(&sg, data, len);
130 DMERR("crypto_shash_update failed: %d", r); 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 */
151static int verity_hash_init(struct dm_verity *v, struct ahash_request *req,
152 struct verity_result *res)
153{
154 int r;
155
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);
161
162 r = verity_complete_op(res, crypto_ahash_init(req));
163
164 if (unlikely(r < 0)) {
165 DMERR("crypto_ahash_init failed: %d", r);
166 return r;
167 }
168
169 if (likely(v->version >= 1))
170 r = verity_hash_update(v, req, v->salt, v->salt_size, res);
131 171
132 return r; 172 return r;
133} 173}
134 174
135static int verity_hash_final(struct dm_verity *v, struct shash_desc *desc, 175static int verity_hash_final(struct dm_verity *v, struct ahash_request *req,
136 u8 *digest) 176 u8 *digest, struct verity_result *res)
137{ 177{
138 int r; 178 int r;
139 179
140 if (unlikely(!v->version)) { 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 if (r < 0) { 183 if (r < 0) {
144 DMERR("crypto_shash_update failed: %d", r); 184 DMERR("verity_hash_final failed updating salt: %d", r);
145 return r; 185 goto out;
146 } 186 }
147 } 187 }
148 188
149 r = crypto_shash_final(desc, digest); 189 ahash_request_set_crypt(req, NULL, digest, 0);
150 190 r = verity_complete_op(res, crypto_ahash_final(req));
151 if (unlikely(r < 0)) 191out:
152 DMERR("crypto_shash_final failed: %d", r);
153
154 return r; 192 return r;
155} 193}
156 194
157int verity_hash(struct dm_verity *v, struct shash_desc *desc, 195int verity_hash(struct dm_verity *v, struct ahash_request *req,
158 const u8 *data, size_t len, u8 *digest) 196 const u8 *data, size_t len, u8 *digest)
159{ 197{
160 int r; 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 if (unlikely(r < 0)) 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 if (unlikely(r < 0)) 206 if (unlikely(r < 0))
168 return r; 207 goto out;
208
209 r = verity_hash_final(v, req, digest, &res);
169 210
170 return verity_hash_final(v, desc, digest); 211out:
212 return r;
171} 213}
172 214
173static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level, 215static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
@@ -275,7 +317,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
275 goto release_ret_r; 317 goto release_ret_r;
276 } 318 }
277 319
278 r = verity_hash(v, verity_io_hash_desc(v, io), 320 r = verity_hash(v, verity_io_hash_req(v, io),
279 data, 1 << v->hash_dev_block_bits, 321 data, 1 << v->hash_dev_block_bits,
280 verity_io_real_digest(v, io)); 322 verity_io_real_digest(v, io));
281 if (unlikely(r < 0)) 323 if (unlikely(r < 0))
@@ -344,6 +386,49 @@ out:
344} 386}
345 387
346/* 388/*
389 * Calculates the digest for the given bio
390 */
391int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
392 struct bvec_iter *iter, struct verity_result *res)
393{
394 unsigned int todo = 1 << v->data_dev_block_bits;
395 struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
396 struct scatterlist sg;
397 struct ahash_request *req = verity_io_hash_req(v, io);
398
399 do {
400 int r;
401 unsigned int len;
402 struct bio_vec bv = bio_iter_iovec(bio, *iter);
403
404 sg_init_table(&sg, 1);
405
406 len = bv.bv_len;
407
408 if (likely(len >= todo))
409 len = todo;
410 /*
411 * Operating on a single page at a time looks suboptimal
412 * until you consider the typical block size is 4,096B.
413 * Going through this loops twice should be very rare.
414 */
415 sg_set_page(&sg, bv.bv_page, len, bv.bv_offset);
416 ahash_request_set_crypt(req, &sg, NULL, len);
417 r = verity_complete_op(res, crypto_ahash_update(req));
418
419 if (unlikely(r < 0)) {
420 DMERR("verity_for_io_block crypto op failed: %d", r);
421 return r;
422 }
423
424 bio_advance_iter(bio, iter, len);
425 todo -= len;
426 } while (todo);
427
428 return 0;
429}
430
431/*
347 * Calls function process for 1 << v->data_dev_block_bits bytes in the bio_vec 432 * Calls function process for 1 << v->data_dev_block_bits bytes in the bio_vec
348 * starting from iter. 433 * starting from iter.
349 */ 434 */
@@ -381,12 +466,6 @@ int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
381 return 0; 466 return 0;
382} 467}
383 468
384static int verity_bv_hash_update(struct dm_verity *v, struct dm_verity_io *io,
385 u8 *data, size_t len)
386{
387 return verity_hash_update(v, verity_io_hash_desc(v, io), data, len);
388}
389
390static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io, 469static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io,
391 u8 *data, size_t len) 470 u8 *data, size_t len)
392{ 471{
@@ -403,10 +482,11 @@ static int verity_verify_io(struct dm_verity_io *io)
403 struct dm_verity *v = io->v; 482 struct dm_verity *v = io->v;
404 struct bvec_iter start; 483 struct bvec_iter start;
405 unsigned b; 484 unsigned b;
485 struct verity_result res;
406 486
407 for (b = 0; b < io->n_blocks; b++) { 487 for (b = 0; b < io->n_blocks; b++) {
408 int r; 488 int r;
409 struct shash_desc *desc = verity_io_hash_desc(v, io); 489 struct ahash_request *req = verity_io_hash_req(v, io);
410 490
411 r = verity_hash_for_block(v, io, io->block + b, 491 r = verity_hash_for_block(v, io, io->block + b,
412 verity_io_want_digest(v, io), 492 verity_io_want_digest(v, io),
@@ -427,16 +507,17 @@ static int verity_verify_io(struct dm_verity_io *io)
427 continue; 507 continue;
428 } 508 }
429 509
430 r = verity_hash_init(v, desc); 510 r = verity_hash_init(v, req, &res);
431 if (unlikely(r < 0)) 511 if (unlikely(r < 0))
432 return r; 512 return r;
433 513
434 start = io->iter; 514 start = io->iter;
435 r = verity_for_bv_block(v, io, &io->iter, verity_bv_hash_update); 515 r = verity_for_io_block(v, io, &io->iter, &res);
436 if (unlikely(r < 0)) 516 if (unlikely(r < 0))
437 return r; 517 return r;
438 518
439 r = verity_hash_final(v, desc, verity_io_real_digest(v, io)); 519 r = verity_hash_final(v, req, verity_io_real_digest(v, io),
520 &res);
440 if (unlikely(r < 0)) 521 if (unlikely(r < 0))
441 return r; 522 return r;
442 523
@@ -705,7 +786,7 @@ static void verity_dtr(struct dm_target *ti)
705 kfree(v->zero_digest); 786 kfree(v->zero_digest);
706 787
707 if (v->tfm) 788 if (v->tfm)
708 crypto_free_shash(v->tfm); 789 crypto_free_ahash(v->tfm);
709 790
710 kfree(v->alg_name); 791 kfree(v->alg_name);
711 792
@@ -723,7 +804,7 @@ static void verity_dtr(struct dm_target *ti)
723static int verity_alloc_zero_digest(struct dm_verity *v) 804static int verity_alloc_zero_digest(struct dm_verity *v)
724{ 805{
725 int r = -ENOMEM; 806 int r = -ENOMEM;
726 struct shash_desc *desc; 807 struct ahash_request *req;
727 u8 *zero_data; 808 u8 *zero_data;
728 809
729 v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL); 810 v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL);
@@ -731,9 +812,9 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
731 if (!v->zero_digest) 812 if (!v->zero_digest)
732 return r; 813 return r;
733 814
734 desc = kmalloc(v->shash_descsize, GFP_KERNEL); 815 req = kmalloc(v->ahash_reqsize, GFP_KERNEL);
735 816
736 if (!desc) 817 if (!req)
737 return r; /* verity_dtr will free zero_digest */ 818 return r; /* verity_dtr will free zero_digest */
738 819
739 zero_data = kzalloc(1 << v->data_dev_block_bits, GFP_KERNEL); 820 zero_data = kzalloc(1 << v->data_dev_block_bits, GFP_KERNEL);
@@ -741,11 +822,11 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
741 if (!zero_data) 822 if (!zero_data)
742 goto out; 823 goto out;
743 824
744 r = verity_hash(v, desc, zero_data, 1 << v->data_dev_block_bits, 825 r = verity_hash(v, req, zero_data, 1 << v->data_dev_block_bits,
745 v->zero_digest); 826 v->zero_digest);
746 827
747out: 828out:
748 kfree(desc); 829 kfree(req);
749 kfree(zero_data); 830 kfree(zero_data);
750 831
751 return r; 832 return r;
@@ -923,21 +1004,21 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
923 goto bad; 1004 goto bad;
924 } 1005 }
925 1006
926 v->tfm = crypto_alloc_shash(v->alg_name, 0, 0); 1007 v->tfm = crypto_alloc_ahash(v->alg_name, 0, 0);
927 if (IS_ERR(v->tfm)) { 1008 if (IS_ERR(v->tfm)) {
928 ti->error = "Cannot initialize hash function"; 1009 ti->error = "Cannot initialize hash function";
929 r = PTR_ERR(v->tfm); 1010 r = PTR_ERR(v->tfm);
930 v->tfm = NULL; 1011 v->tfm = NULL;
931 goto bad; 1012 goto bad;
932 } 1013 }
933 v->digest_size = crypto_shash_digestsize(v->tfm); 1014 v->digest_size = crypto_ahash_digestsize(v->tfm);
934 if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) { 1015 if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
935 ti->error = "Digest size too big"; 1016 ti->error = "Digest size too big";
936 r = -EINVAL; 1017 r = -EINVAL;
937 goto bad; 1018 goto bad;
938 } 1019 }
939 v->shash_descsize = 1020 v->ahash_reqsize = sizeof(struct ahash_request) +
940 sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm); 1021 crypto_ahash_reqsize(v->tfm);
941 1022
942 v->root_digest = kmalloc(v->digest_size, GFP_KERNEL); 1023 v->root_digest = kmalloc(v->digest_size, GFP_KERNEL);
943 if (!v->root_digest) { 1024 if (!v->root_digest) {
@@ -1037,7 +1118,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
1037 } 1118 }
1038 1119
1039 ti->per_io_data_size = sizeof(struct dm_verity_io) + 1120 ti->per_io_data_size = sizeof(struct dm_verity_io) +
1040 v->shash_descsize + v->digest_size * 2; 1121 v->ahash_reqsize + v->digest_size * 2;
1041 1122
1042 r = verity_fec_ctr(v); 1123 r = verity_fec_ctr(v);
1043 if (r) 1124 if (r)
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index fb419f422d73..a59e0ada6fd3 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -37,7 +37,7 @@ struct dm_verity {
37 struct dm_target *ti; 37 struct dm_target *ti;
38 struct dm_bufio_client *bufio; 38 struct dm_bufio_client *bufio;
39 char *alg_name; 39 char *alg_name;
40 struct crypto_shash *tfm; 40 struct crypto_ahash *tfm;
41 u8 *root_digest; /* digest of the root block */ 41 u8 *root_digest; /* digest of the root block */
42 u8 *salt; /* salt: its size is salt_size */ 42 u8 *salt; /* salt: its size is salt_size */
43 u8 *zero_digest; /* digest for a zero block */ 43 u8 *zero_digest; /* digest for a zero block */
@@ -52,7 +52,7 @@ struct dm_verity {
52 unsigned char levels; /* the number of tree levels */ 52 unsigned char levels; /* the number of tree levels */
53 unsigned char version; 53 unsigned char version;
54 unsigned digest_size; /* digest size for the current hash algorithm */ 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 int hash_failed; /* set to 1 if hash of any block failed */ 56 int hash_failed; /* set to 1 if hash of any block failed */
57 enum verity_mode mode; /* mode for handling verification errors */ 57 enum verity_mode mode; /* mode for handling verification errors */
58 unsigned corrupted_errs;/* Number of errors for corrupted blocks */ 58 unsigned corrupted_errs;/* Number of errors for corrupted blocks */
@@ -81,31 +81,36 @@ struct dm_verity_io {
81 /* 81 /*
82 * Three variably-size fields follow this struct: 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 * u8 real_digest[v->digest_size]; 85 * u8 real_digest[v->digest_size];
86 * u8 want_digest[v->digest_size]; 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 * and verity_io_want_digest(). 89 * and verity_io_want_digest().
90 */ 90 */
91}; 91};
92 92
93static inline struct shash_desc *verity_io_hash_desc(struct dm_verity *v, 93struct verity_result {
94 struct completion completion;
95 int err;
96};
97
98static inline struct ahash_request *verity_io_hash_req(struct dm_verity *v,
94 struct dm_verity_io *io) 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
99static inline u8 *verity_io_real_digest(struct dm_verity *v, 104static inline u8 *verity_io_real_digest(struct dm_verity *v,
100 struct dm_verity_io *io) 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
105static inline u8 *verity_io_want_digest(struct dm_verity *v, 110static inline u8 *verity_io_want_digest(struct dm_verity *v,
106 struct dm_verity_io *io) 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
111static inline u8 *verity_io_digest_end(struct dm_verity *v, 116static inline u8 *verity_io_digest_end(struct dm_verity *v,
@@ -120,7 +125,7 @@ extern int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
120 struct dm_verity_io *io, 125 struct dm_verity_io *io,
121 u8 *data, size_t len)); 126 u8 *data, size_t len));
122 127
123extern int verity_hash(struct dm_verity *v, struct shash_desc *desc, 128extern int verity_hash(struct dm_verity *v, struct ahash_request *req,
124 const u8 *data, size_t len, u8 *digest); 129 const u8 *data, size_t len, u8 *digest);
125 130
126extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io, 131extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,