Thank you for your contribution! Sashiko AI review found 1 potential issue(s) 
to consider:
- [High] Block I/O Forward Progress / Deadlock due to missing mempool backing 
for flush allocations
--

commit e290d67d3c09c47f258d895e86c79743d39db2c1
Author: Li Chen <[email protected]>

nvdimm: virtio_pmem: stop allocating child flush bio

This commit avoids allocating a child PREFLUSH bio during REQ_FUA
submission by queuing an ordered WQ_MEM_RECLAIM work item. It allows
provider flush callbacks to return NVDIMM_FLUSH_ASYNC after taking
ownership of parent bio completion.

> diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c
> index 4176046627beb..8e16b7780be1a 100644
> --- a/drivers/nvdimm/nd_virtio.c
> +++ b/drivers/nvdimm/nd_virtio.c

[ ... ]

> @@ -107,30 +113,46 @@ static int virtio_pmem_flush(struct nd_region 
> *nd_region)
>       return err;
>  };
>  
> +static void virtio_pmem_flush_work(struct work_struct *work)
> +{
> +     struct virtio_pmem_flush_work *flush;
> +     int err;
> +
> +     flush = container_of(work, struct virtio_pmem_flush_work, work);
> +     err = virtio_pmem_flush(flush->nd_region);

[ ... ]

>  int async_pmem_flush(struct nd_region *nd_region, struct bio *bio)
>  {
> -     /*
> -      * Create child bio for asynchronous flush and chain with
> -      * parent bio. Otherwise directly call nd_region flush.
> -      */
> -     if (bio && bio->bi_iter.bi_sector != -1) {
> -             struct bio *child = bio_alloc(bio->bi_bdev, 0,
> -                                           REQ_OP_WRITE | REQ_PREFLUSH,
> -                                           GFP_ATOMIC);
> +     struct virtio_device *vdev = nd_region->provider_data;
> +     struct virtio_pmem *vpmem = vdev->priv;
> +     struct virtio_pmem_flush_work *flush;
> +     int err;
>  
> -             if (!child)
> +     if (bio && bio->bi_iter.bi_sector != -1) {
> +             flush = kmalloc_obj(*flush, GFP_NOIO);

[Severity: High]
Can this cause a deadlock during memory reclaim?

Order-0 allocations with GFP_NOIO (which includes __GFP_DIRECT_RECLAIM)
can loop indefinitely in the page allocator's slowpath rather than failing.

Since this lacks mempool backing and is directly in the block I/O
submission path, couldn't the block submission thread block waiting
for memory, deadlocking if memory cannot be freed without this block I/O
completing?

> +             if (!flush)
>                       return -ENOMEM;
> -             bio_clone_blkg_association(child, bio);
> -             child->bi_iter.bi_sector = -1;
> -             bio_chain(child, bio);
> -             submit_bio(child);
> -             return 0;
> +
> +             INIT_WORK(&flush->work, virtio_pmem_flush_work);
> +             flush->nd_region = nd_region;
> +             flush->bio = bio;
> +             queue_work(vpmem->flush_wq, &flush->work);

[Severity: High]
Is it safe to queue work on a WQ_MEM_RECLAIM workqueue when the worker
function performs a non-mempool-backed GFP_NOIO allocation?

If the system is under severe memory pressure, the workqueue falls back
to its rescuer thread to ensure forward progress. The rescuer executes
virtio_pmem_flush_work() -> virtio_pmem_flush(), which allocates memory:

drivers/nvdimm/nd_virtio.c:virtio_pmem_flush() {
    ...
    req_data = kmalloc_obj(*req_data, GFP_NOIO);
    ...
}

Since GFP_NOIO includes __GFP_DIRECT_RECLAIM, the rescuer thread could
block indefinitely in direct reclaim trying to allocate req_data. Doesn't
this stall the rescuer thread and prevent pending flush completions from
making forward progress?

> +             return NVDIMM_FLUSH_ASYNC;
>       }

-- 
Sashiko AI review ยท 
https://sashiko.dev/#/patchset/[email protected]?part=4

Reply via email to