ext4: fix deadlock allocating bio_post_read_ctx from mempool
Eric Biggers
maintainerPATCH 1/1 ext4: fix deadlock allocating bio_post_read_ctx from mempool
From: Eric Biggers <[email protected]>
Without any form of coordination, any case where multiple allocations from the same mempool are needed at a time to make forward progress can deadlock under memory pressure.
This is the case for struct bio_post_read_ctx, as one can be allocated to decrypt a Merkle tree page during fsverity_verify_bio(), which itself is running from a post-read callback for a data bio which has its own struct bio_post_read_ctx.
Fix this by freeing the first bio_post_read_ctx before calling fsverity_verify_bio(). This works because verity (if enabled) is always the last post-read step.
This deadlock can be reproduced by trying to read from an encrypted verity file after reducing NUM_PREALLOC_POST_READ_CTXS to 1 and patching mempool_alloc() to pretend that pool->alloc() always fails.
Note that since NUM_PREALLOC_POST_READ_CTXS is actually 128, to actually hit this bug in practice would require reading from lots of encrypted verity files at the same time. But it's theoretically possible, as N available objects isn't enough to guarantee forward progress when > N/2 threads each need 2 objects at a time.
--- fs/ext4/readpage.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
fs/ext4/readpage.c +15 -2
@@ -57,6 +57,7 @@ enum bio_post_read_step {STEP_INITIAL =0 ,STEP_DECRYPT ,STEP_VERITY , + STEP_MAX, }; struct bio_post_read_ctx {
@@ -106,10 +107,22 @@ static void verity_work(struct work_struct *work) {struct bio_post_read_ctx *ctx = container_of(work, struct bio_post_read_ctx, work); +struct bio *bio = ctx->bio; -fsverity_verify_bio (ctx->bio); +/* +* fsverity_verify_bio() may call readpages() again, and although verity +* will be disabled for that, decryption may still be needed, causing +* another bio_post_read_ctx to be allocated. So to guarantee that +* mempool_alloc() never deadlocks we must free the current ctx first. +* This is safe because verity is the last post-read step. +*/ +BUILD_BUG_ON (STEP_VERITY +1 !=STEP_MAX ); +mempool_free (ctx, bio_post_read_ctx_pool); + bio->bi_private =NULL ; -bio_post_read_processing (ctx); +fsverity_verify_bio (bio); + +__read_end_io (bio); }static void bio_post_read_processing (struct bio_post_read_ctx *ctx)
Signature · 1 line
2.24.1
Quoted 19 lines · Eric Biggers
From: Eric Biggers <[email protected]>
Without any form of coordination, any case where multiple allocations from the same mempool are needed at a time to make forward progress can deadlock under memory pressure.
This is the case for struct
bio_post_read_ctx, as one can be allocated to decrypt a Merkle tree page duringfsverity_verify_bio(), which itself is running from a post-read callback for a data bio which has its own structbio_post_read_ctx.Fix this by freeing the first
bio_post_read_ctxbefore callingfsverity_verify_bio(). This works because verity (if enabled) is always the last post-read step.This deadlock can be reproduced by trying to read from an encrypted verity file after reducing
NUM_PREALLOC_POST_READ_CTXSto 1 and patchingmempool_alloc()to pretend thatpool->alloc()always fails.
Quoted 8 lines
Note that since
NUM_PREALLOC_POST_READ_CTXSis actually 128, to actually hit this bug in practice would require reading from lots of encrypted verity files at the same time. But it's theoretically possible, as N available objects isn't enough to guarantee forward progress when > N/2 threads each need 2 objects at a time.Fixes 22cfe4b48ccb ("ext4: add fs-verity read support")Signed-off-by Eric Biggers <[email protected]>
Thanks, applied.
- Ted