Skip to content

Commit ba0f428

Browse files
Eric BiggersMikulas Patocka
authored andcommitted
dm-verity: use SHA-256 library for SHA-256
When the hash algorithm is SHA-256 and the verity version is not 0, use the SHA-256 library instead of crypto_shash. This is a prerequisite for making dm-verity interleave the computation of SHA-256 hashes for increased performance. That optimization is available in the SHA-256 library but not in crypto_shash. Even without interleaved hashing, switching to the library also slightly improves performance by itself because it avoids the overhead of crypto_shash, including indirect calls and other API overhead. (Benchmark on x86_64, AMD Zen 5: hashing 4K blocks gets 2.1% faster.) SHA-256 is by far the most common hash algorithm used with dm-verity. It makes sense to optimize for the common case and fall back to the generic crypto layer for uncommon cases, as suggested by Linus: https://lore.kernel.org/r/CAHk-=wgp-fOSsZsYrbyzqCAfEvrt5jQs1jL-97Wc4seMNTUyng@mail.gmail.com Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
1 parent 3ee6c4b commit ba0f428

3 files changed

Lines changed: 64 additions & 18 deletions

File tree

drivers/md/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ config DM_VERITY
547547
depends on BLK_DEV_DM
548548
select CRYPTO
549549
select CRYPTO_HASH
550+
select CRYPTO_LIB_SHA256
550551
select DM_BUFIO
551552
help
552553
This device-mapper target creates a read-only device that

drivers/md/dm-verity-target.c

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,33 @@ static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
117117
int verity_hash(struct dm_verity *v, struct dm_verity_io *io,
118118
const u8 *data, size_t len, u8 *digest)
119119
{
120-
struct shash_desc *desc = &io->hash_desc;
120+
struct shash_desc *desc;
121121
int r;
122122

123+
if (likely(v->use_sha256_lib)) {
124+
struct sha256_ctx *ctx = &io->hash_ctx.sha256;
125+
126+
/*
127+
* Fast path using SHA-256 library. This is enabled only for
128+
* verity version 1, where the salt is at the beginning.
129+
*/
130+
*ctx = *v->initial_hashstate.sha256;
131+
sha256_update(ctx, data, len);
132+
sha256_final(ctx, digest);
133+
return 0;
134+
}
135+
136+
desc = &io->hash_ctx.shash;
123137
desc->tfm = v->shash_tfm;
124-
if (unlikely(v->initial_hashstate == NULL)) {
138+
if (unlikely(v->initial_hashstate.shash == NULL)) {
125139
/* Version 0: salt at end */
126140
r = crypto_shash_init(desc) ?:
127141
crypto_shash_update(desc, data, len) ?:
128142
crypto_shash_update(desc, v->salt, v->salt_size) ?:
129143
crypto_shash_final(desc, digest);
130144
} else {
131145
/* Version 1: salt at beginning */
132-
r = crypto_shash_import(desc, v->initial_hashstate) ?:
146+
r = crypto_shash_import(desc, v->initial_hashstate.shash) ?:
133147
crypto_shash_finup(desc, data, len, digest);
134148
}
135149
if (unlikely(r))
@@ -1004,7 +1018,7 @@ static void verity_dtr(struct dm_target *ti)
10041018

10051019
kvfree(v->validated_blocks);
10061020
kfree(v->salt);
1007-
kfree(v->initial_hashstate);
1021+
kfree(v->initial_hashstate.shash);
10081022
kfree(v->root_digest);
10091023
kfree(v->zero_digest);
10101024
verity_free_sig(v);
@@ -1069,8 +1083,7 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
10691083
if (!v->zero_digest)
10701084
return r;
10711085

1072-
io = kmalloc(sizeof(*io) + crypto_shash_descsize(v->shash_tfm),
1073-
GFP_KERNEL);
1086+
io = kmalloc(v->ti->per_io_data_size, GFP_KERNEL);
10741087

10751088
if (!io)
10761089
return r; /* verity_dtr will free zero_digest */
@@ -1256,6 +1269,20 @@ static int verity_setup_hash_alg(struct dm_verity *v, const char *alg_name)
12561269
ti->error = "Digest size too big";
12571270
return -EINVAL;
12581271
}
1272+
if (likely(v->version && strcmp(alg_name, "sha256") == 0)) {
1273+
/*
1274+
* Fast path: use the library API for reduced overhead and
1275+
* interleaved hashing support.
1276+
*/
1277+
v->use_sha256_lib = true;
1278+
ti->per_io_data_size =
1279+
offsetofend(struct dm_verity_io, hash_ctx.sha256);
1280+
} else {
1281+
/* Fallback case: use the generic crypto API. */
1282+
ti->per_io_data_size =
1283+
offsetofend(struct dm_verity_io, hash_ctx.shash) +
1284+
crypto_shash_descsize(shash);
1285+
}
12591286
return 0;
12601287
}
12611288

@@ -1276,24 +1303,35 @@ static int verity_setup_salt_and_hashstate(struct dm_verity *v, const char *arg)
12761303
return -EINVAL;
12771304
}
12781305
}
1279-
if (v->version) { /* Version 1: salt at beginning */
1306+
if (likely(v->use_sha256_lib)) {
1307+
/* Implies version 1: salt at beginning */
1308+
v->initial_hashstate.sha256 =
1309+
kmalloc(sizeof(struct sha256_ctx), GFP_KERNEL);
1310+
if (!v->initial_hashstate.sha256) {
1311+
ti->error = "Cannot allocate initial hash state";
1312+
return -ENOMEM;
1313+
}
1314+
sha256_init(v->initial_hashstate.sha256);
1315+
sha256_update(v->initial_hashstate.sha256,
1316+
v->salt, v->salt_size);
1317+
} else if (v->version) { /* Version 1: salt at beginning */
12801318
SHASH_DESC_ON_STACK(desc, v->shash_tfm);
12811319
int r;
12821320

12831321
/*
12841322
* Compute the pre-salted hash state that can be passed to
12851323
* crypto_shash_import() for each block later.
12861324
*/
1287-
v->initial_hashstate = kmalloc(
1325+
v->initial_hashstate.shash = kmalloc(
12881326
crypto_shash_statesize(v->shash_tfm), GFP_KERNEL);
1289-
if (!v->initial_hashstate) {
1327+
if (!v->initial_hashstate.shash) {
12901328
ti->error = "Cannot allocate initial hash state";
12911329
return -ENOMEM;
12921330
}
12931331
desc->tfm = v->shash_tfm;
12941332
r = crypto_shash_init(desc) ?:
12951333
crypto_shash_update(desc, v->salt, v->salt_size) ?:
1296-
crypto_shash_export(desc, v->initial_hashstate);
1334+
crypto_shash_export(desc, v->initial_hashstate.shash);
12971335
if (r) {
12981336
ti->error = "Cannot set up initial hash state";
12991337
return r;
@@ -1555,9 +1593,6 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
15551593
goto bad;
15561594
}
15571595

1558-
ti->per_io_data_size = sizeof(struct dm_verity_io) +
1559-
crypto_shash_descsize(v->shash_tfm);
1560-
15611596
r = verity_fec_ctr(v);
15621597
if (r)
15631598
goto bad;

drivers/md/dm-verity.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/device-mapper.h>
1717
#include <linux/interrupt.h>
1818
#include <crypto/hash.h>
19+
#include <crypto/sha2.h>
1920

2021
#define DM_VERITY_MAX_LEVELS 63
2122

@@ -42,7 +43,10 @@ struct dm_verity {
4243
struct crypto_shash *shash_tfm;
4344
u8 *root_digest; /* digest of the root block */
4445
u8 *salt; /* salt: its size is salt_size */
45-
u8 *initial_hashstate; /* salted initial state, if version >= 1 */
46+
union {
47+
struct sha256_ctx *sha256; /* for use_sha256_lib=1 */
48+
u8 *shash; /* for use_sha256_lib=0 */
49+
} initial_hashstate; /* salted initial state, if version >= 1 */
4650
u8 *zero_digest; /* digest for a zero block */
4751
#ifdef CONFIG_SECURITY
4852
u8 *root_digest_sig; /* signature of the root digest */
@@ -59,6 +63,7 @@ struct dm_verity {
5963
unsigned char version;
6064
bool hash_failed:1; /* set if hash of any block failed */
6165
bool use_bh_wq:1; /* try to verify in BH wq before normal work-queue */
66+
bool use_sha256_lib:1; /* use SHA-256 library instead of generic crypto API */
6267
unsigned int digest_size; /* digest size for the current hash algorithm */
6368
enum verity_mode mode; /* mode for handling verification errors */
6469
enum verity_mode error_mode;/* mode for handling I/O errors */
@@ -98,11 +103,16 @@ struct dm_verity_io {
98103
u8 want_digest[HASH_MAX_DIGESTSIZE];
99104

100105
/*
101-
* Temporary space for hashing. This is variable-length and must be at
102-
* the end of the struct. struct shash_desc is just the fixed part;
103-
* it's followed by a context of size crypto_shash_descsize(shash_tfm).
106+
* Temporary space for hashing. Either sha256 or shash is used,
107+
* depending on the value of use_sha256_lib. If shash is used,
108+
* then this field is variable-length, with total size
109+
* sizeof(struct shash_desc) + crypto_shash_descsize(shash_tfm).
110+
* For this reason, this field must be the end of the struct.
104111
*/
105-
struct shash_desc hash_desc;
112+
union {
113+
struct sha256_ctx sha256;
114+
struct shash_desc shash;
115+
} hash_ctx;
106116
};
107117

108118
static inline u8 *verity_io_real_digest(struct dm_verity *v,

0 commit comments

Comments
 (0)