From 8bfd35db0b07ed4433534e68c51192aebdf3a707 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 6 Mar 2026 10:35:09 -0800 Subject: [PATCH] Set BLOCK_BIT_ERROR on bio submit failure during forced unmount block_submit_bio will return -ENOLINK if called during a forced shutdown, the bio is never submitted, and thus no completion callback will fire to set BLOCK_BIT_ERROR. Any other task waiting for this specific bp will end up waiting forever. To fix, fall through to the existing block_end_io call on the error path instead of returning directly. That means moving the forcing_unmount check past the setup calls so block_end_io's bookkeeping stays balanced. block_end_io then sets BLOCK_BIT_ERROR and wakes up waiters just as it would on a failed async completion. Signed-off-by: Auke Kok --- kmod/src/block.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/kmod/src/block.c b/kmod/src/block.c index 463e1b01..adba8c39 100644 --- a/kmod/src/block.c +++ b/kmod/src/block.c @@ -467,9 +467,6 @@ static int block_submit_bio(struct super_block *sb, struct block_private *bp, sector_t sector; int ret = 0; - if (scoutfs_forcing_unmount(sb)) - return -ENOLINK; - sector = bp->bl.blkno << (SCOUTFS_BLOCK_LG_SHIFT - 9); WARN_ON_ONCE(bp->bl.blkno == U64_MAX); @@ -480,6 +477,17 @@ static int block_submit_bio(struct super_block *sb, struct block_private *bp, set_bit(BLOCK_BIT_IO_BUSY, &bp->bits); block_get(bp); + /* + * A second thread may already be waiting on this block's completion + * after this thread won the race to submit the block. We exit through + * the block_end_io error path which sets BLOCK_BIT_ERROR and assures + * that other callers in the waitq get woken up. + */ + if (scoutfs_forcing_unmount(sb)) { + ret = -ENOLINK; + goto end_io; + } + blk_start_plug(&plug); for (off = 0; off < SCOUTFS_BLOCK_LG_SIZE; off += PAGE_SIZE) { @@ -517,6 +525,7 @@ static int block_submit_bio(struct super_block *sb, struct block_private *bp, blk_finish_plug(&plug); +end_io: /* let racing end_io know we're done */ block_end_io(sb, opf, bp, ret);