Skip to content

Commit c375b22

Browse files
htejunMike Snitzer
authored andcommitted
dm-verity: Convert from tasklet to BH workqueue
The only generic interface to execute asynchronously in the BH context is tasklet; however, it's marked deprecated and has some design flaws. To replace tasklets, BH workqueue support was recently added. A BH workqueue behaves similarly to regular workqueues except that the queued work items are executed in the BH context. This commit converts dm-verity from tasklet to BH workqueue. It backfills tasklet code that was removed with commit 0a9bab3 ("dm-crypt, dm-verity: disable tasklets") and tweaks to use BH workqueue (and does some renaming). This is a minimal conversion which doesn't rename the related names including the "try_verify_in_tasklet" option. If this patch is applied, a follow-up patch would be necessary. I couldn't decide whether the option name would need to be updated too. Signed-off-by: Tejun Heo <[email protected]> [snitzer: rename 'use_tasklet' to 'use_bh_wq' and 'in_tasklet' to 'in_bh'] Signed-off-by: Mike Snitzer <[email protected]>
1 parent fb6ad4a commit c375b22

File tree

2 files changed

+45
-24
lines changed

2 files changed

+45
-24
lines changed

drivers/md/dm-verity-target.c

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static unsigned int dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE
4646

4747
module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, 0644);
4848

49-
static DEFINE_STATIC_KEY_FALSE(use_tasklet_enabled);
49+
static DEFINE_STATIC_KEY_FALSE(use_bh_wq_enabled);
5050

5151
struct dm_verity_prefetch_work {
5252
struct work_struct work;
@@ -299,7 +299,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
299299

300300
verity_hash_at_level(v, block, level, &hash_block, &offset);
301301

302-
if (static_branch_unlikely(&use_tasklet_enabled) && io->in_tasklet) {
302+
if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
303303
data = dm_bufio_get(v->bufio, hash_block, &buf);
304304
if (data == NULL) {
305305
/*
@@ -327,15 +327,14 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
327327

328328
r = verity_hash(v, verity_io_hash_req(v, io),
329329
data, 1 << v->hash_dev_block_bits,
330-
verity_io_real_digest(v, io), !io->in_tasklet);
330+
verity_io_real_digest(v, io), !io->in_bh);
331331
if (unlikely(r < 0))
332332
goto release_ret_r;
333333

334334
if (likely(memcmp(verity_io_real_digest(v, io), want_digest,
335335
v->digest_size) == 0))
336336
aux->hash_verified = 1;
337-
else if (static_branch_unlikely(&use_tasklet_enabled) &&
338-
io->in_tasklet) {
337+
else if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
339338
/*
340339
* Error handling code (FEC included) cannot be run in a
341340
* tasklet since it may sleep, so fallback to work-queue.
@@ -576,7 +575,7 @@ static int verity_verify_io(struct dm_verity_io *io)
576575
struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
577576
unsigned int b;
578577

579-
if (static_branch_unlikely(&use_tasklet_enabled) && io->in_tasklet) {
578+
if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
580579
/*
581580
* Copy the iterator in case we need to restart
582581
* verification in a work-queue.
@@ -616,7 +615,7 @@ static int verity_verify_io(struct dm_verity_io *io)
616615
continue;
617616
}
618617

619-
r = verity_hash_init(v, req, &wait, !io->in_tasklet);
618+
r = verity_hash_init(v, req, &wait, !io->in_bh);
620619
if (unlikely(r < 0))
621620
return r;
622621

@@ -635,8 +634,7 @@ static int verity_verify_io(struct dm_verity_io *io)
635634
if (v->validated_blocks)
636635
set_bit(cur_block, v->validated_blocks);
637636
continue;
638-
} else if (static_branch_unlikely(&use_tasklet_enabled) &&
639-
io->in_tasklet) {
637+
} else if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
640638
/*
641639
* Error handling code (FEC included) cannot be run in a
642640
* tasklet since it may sleep, so fallback to work-queue.
@@ -690,7 +688,7 @@ static void verity_finish_io(struct dm_verity_io *io, blk_status_t status)
690688
bio->bi_end_io = io->orig_bi_end_io;
691689
bio->bi_status = status;
692690

693-
if (!static_branch_unlikely(&use_tasklet_enabled) || !io->in_tasklet)
691+
if (!static_branch_unlikely(&use_bh_wq_enabled) || !io->in_bh)
694692
verity_fec_finish_io(io);
695693

696694
bio_endio(bio);
@@ -700,11 +698,28 @@ static void verity_work(struct work_struct *w)
700698
{
701699
struct dm_verity_io *io = container_of(w, struct dm_verity_io, work);
702700

703-
io->in_tasklet = false;
701+
io->in_bh = false;
704702

705703
verity_finish_io(io, errno_to_blk_status(verity_verify_io(io)));
706704
}
707705

706+
static void verity_bh_work(struct work_struct *w)
707+
{
708+
struct dm_verity_io *io = container_of(w, struct dm_verity_io, bh_work);
709+
int err;
710+
711+
io->in_bh = true;
712+
err = verity_verify_io(io);
713+
if (err == -EAGAIN || err == -ENOMEM) {
714+
/* fallback to retrying with work-queue */
715+
INIT_WORK(&io->work, verity_work);
716+
queue_work(io->v->verify_wq, &io->work);
717+
return;
718+
}
719+
720+
verity_finish_io(io, errno_to_blk_status(err));
721+
}
722+
708723
static void verity_end_io(struct bio *bio)
709724
{
710725
struct dm_verity_io *io = bio->bi_private;
@@ -717,8 +732,13 @@ static void verity_end_io(struct bio *bio)
717732
return;
718733
}
719734

720-
INIT_WORK(&io->work, verity_work);
721-
queue_work(io->v->verify_wq, &io->work);
735+
if (static_branch_unlikely(&use_bh_wq_enabled) && io->v->use_bh_wq) {
736+
INIT_WORK(&io->bh_work, verity_bh_work);
737+
queue_work(system_bh_wq, &io->bh_work);
738+
} else {
739+
INIT_WORK(&io->work, verity_work);
740+
queue_work(io->v->verify_wq, &io->work);
741+
}
722742
}
723743

724744
/*
@@ -885,7 +905,7 @@ static void verity_status(struct dm_target *ti, status_type_t type,
885905
args++;
886906
if (v->validated_blocks)
887907
args++;
888-
if (v->use_tasklet)
908+
if (v->use_bh_wq)
889909
args++;
890910
if (v->signature_key_desc)
891911
args += DM_VERITY_ROOT_HASH_VERIFICATION_OPTS;
@@ -912,7 +932,7 @@ static void verity_status(struct dm_target *ti, status_type_t type,
912932
DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
913933
if (v->validated_blocks)
914934
DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE);
915-
if (v->use_tasklet)
935+
if (v->use_bh_wq)
916936
DMEMIT(" " DM_VERITY_OPT_TASKLET_VERIFY);
917937
sz = verity_fec_status_table(v, sz, result, maxlen);
918938
if (v->signature_key_desc)
@@ -1031,8 +1051,8 @@ static void verity_dtr(struct dm_target *ti)
10311051

10321052
kfree(v->signature_key_desc);
10331053

1034-
if (v->use_tasklet)
1035-
static_branch_dec(&use_tasklet_enabled);
1054+
if (v->use_bh_wq)
1055+
static_branch_dec(&use_bh_wq_enabled);
10361056

10371057
kfree(v);
10381058

@@ -1166,8 +1186,8 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
11661186
continue;
11671187

11681188
} else if (!strcasecmp(arg_name, DM_VERITY_OPT_TASKLET_VERIFY)) {
1169-
v->use_tasklet = true;
1170-
static_branch_inc(&use_tasklet_enabled);
1189+
v->use_bh_wq = true;
1190+
static_branch_inc(&use_bh_wq_enabled);
11711191
continue;
11721192

11731193
} else if (verity_is_fec_opt_arg(arg_name)) {
@@ -1338,7 +1358,7 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
13381358
}
13391359

13401360
v->tfm = crypto_alloc_ahash(v->alg_name, 0,
1341-
v->use_tasklet ? CRYPTO_ALG_ASYNC : 0);
1361+
v->use_bh_wq ? CRYPTO_ALG_ASYNC : 0);
13421362
if (IS_ERR(v->tfm)) {
13431363
ti->error = "Cannot initialize hash function";
13441364
r = PTR_ERR(v->tfm);
@@ -1463,7 +1483,7 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
14631483
v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
14641484
1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
14651485
dm_bufio_alloc_callback, NULL,
1466-
v->use_tasklet ? DM_BUFIO_CLIENT_NO_SLEEP : 0);
1486+
v->use_bh_wq ? DM_BUFIO_CLIENT_NO_SLEEP : 0);
14671487
if (IS_ERR(v->bufio)) {
14681488
ti->error = "Cannot initialize dm-bufio";
14691489
r = PTR_ERR(v->bufio);
@@ -1482,7 +1502,7 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
14821502
* reducing wait times when reading from a dm-verity device.
14831503
*
14841504
* Also as required for the "try_verify_in_tasklet" feature: WQ_HIGHPRI
1485-
* allows verify_wq to preempt softirq since verification in tasklet
1505+
* allows verify_wq to preempt softirq since verification in BH workqueue
14861506
* will fall-back to using it for error handling (or if the bufio cache
14871507
* doesn't have required hashes).
14881508
*/

drivers/md/dm-verity.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct dm_verity {
5454
unsigned char levels; /* the number of tree levels */
5555
unsigned char version;
5656
bool hash_failed:1; /* set if hash of any block failed */
57-
bool use_tasklet:1; /* try to verify in tasklet before work-queue */
57+
bool use_bh_wq:1; /* try to verify in BH wq before normal work-queue */
5858
unsigned int digest_size; /* digest size for the current hash algorithm */
5959
unsigned int ahash_reqsize;/* the size of temporary space for crypto */
6060
enum verity_mode mode; /* mode for handling verification errors */
@@ -84,9 +84,10 @@ struct dm_verity_io {
8484

8585
sector_t block;
8686
unsigned int n_blocks;
87-
bool in_tasklet;
87+
bool in_bh;
8888

8989
struct work_struct work;
90+
struct work_struct bh_work;
9091

9192
char *recheck_buffer;
9293

0 commit comments

Comments
 (0)