Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] The MD layer and RAID10 driver sleep in multiple paths while handling a `REQ_NOWAIT` bio, violating the non-blocking semantics of the block layer.
- [High] The driver unconditionally uses `GFP_NOIO` for mempool and bio allocations, which can sleep when memory is low, violating `REQ_NOWAIT` non-blocking semantics.
--
--- Patch [1]: [PATCH] md/raid10: free r10_bio on write NOWAIT exits ---
commit 2e30580bb5bb2ae342c9d924bf8c217f5b6c832f
Author: Guangshuo Li <[email protected]>
md/raid10: free r10_bio on write NOWAIT exits
This commit fixes a memory leak in raid10_write_request() where the r10_bio
structure was not returned to the mempool on two REQ_NOWAIT early exit
paths. It ensures free_r10bio() is called before returning false for these
NOWAIT cases.
> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
> index 0a3cfdd3f5df8..d480344c5b8f3 100644
> --- a/drivers/md/raid10.c
> +++ b/drivers/md/raid10.c
> @@ -1364,6 +1364,7 @@ static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
> DEFINE_WAIT(w);
> /* Bail out if REQ_NOWAIT is set for the bio */
> if (bio->bi_opf & REQ_NOWAIT) {
> + free_r10bio(r10_bio);
> bio_wouldblock_error(bio);
> return false;
> }
[ ... ]
> @@ -1397,6 +1398,7 @@ static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
> md_wakeup_thread(mddev->thread);
> if (bio->bi_opf & REQ_NOWAIT) {
> allow_barrier(conf);
> + free_r10bio(r10_bio);
> bio_wouldblock_error(bio);
> return false;
> }
[Severity: High]
This isn't a bug introduced by this patch, but are there other blocking
operations in the NOWAIT path that could still violate the non-blocking
semantics?
If a REQ_NOWAIT bio does not hit these early exits, it proceeds down to
wait_blocked_dev() later in raid10_write_request(), which does not check
for REQ_NOWAIT:
raid10_find_phys(conf, r10_bio);
wait_blocked_dev(mddev, r10_bio);
If a member device is blocked, wait_blocked_dev() drops the barrier and
sleeps in md_wait_for_blocked_rdev() (which has a 5-second timeout) and
then sleeps again in wait_barrier(conf, false).
Additionally, if the bio crosses a chunk boundary, it reacquires the
barrier without checking for REQ_NOWAIT:
if (r10_bio->sectors < bio_sectors(bio)) {
allow_barrier(conf);
bio = bio_submit_split_bioset(bio, r10_bio->sectors,
&conf->bio_split);
wait_barrier(conf, false);
Could these unconditional sleeps cause the thread submitting the async I/O
to stall, potentially exhausting io_uring worker threads?
[Severity: High]
This is also a pre-existing issue, but does the driver unconditionally use
GFP_NOIO for allocations when handling a REQ_NOWAIT bio?
Before raid10_write_request() is even called, __make_request() allocates
the primary r10_bio using GFP_NOIO:
r10_bio = mempool_alloc(&conf->r10bio_pool, GFP_NOIO);
Later, raid10_write_one_disk() clones the bio unconditionally using
GFP_NOIO:
mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO, &mddev->bio_set);
If the mempool is depleted and memory pressure requires direct reclaim,
won't these GFP_NOIO allocations sleep and stall the IO submission thread?
--
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.