mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
dmesg reports virtqueue failure and device reset: virtio_pmem virtio2: failed to send command to virtio pmem device, no free slots in the virtqueue virtio_pmem virtio2: virtio pmem device needs a reset virtio_pmem_flush() can wait for a free virtqueue descriptor (-ENOSPC). It can also wait for host completion. If the request virtqueue breaks, those waiters may never make progress. One example is notify failure from virtqueue_kick(). Track a device-level broken state and converge the failure to -EIO. New requests fail fast, -ENOSPC waiters are unlinked and woken, and the currently submitted request is woken so its host_acked waiter can return without waiting forever for host completion. Completed requests are forced to report an error after the queue is marked broken. Also serialize async parent-bio flush work against the broken state with pmem_lock. That way remove and freeze either drain work queued before virtio_pmem_mark_broken(), or later callers see nvdimm_flush() complete the parent bio synchronously with -EIO instead of queuing work after the drain point. Do not detach unused buffers from an active virtqueue. Runtime broken-queue handling only stops new submissions and wakes local waiters. Removal resets the device first. It then drains request tokens. After that, the device no longer owns the buffers when the virtqueue reference is dropped. Closes: https://lore.kernel.org/r/202512250116.ewtzlD0g-lkp@intel.com/ Signed-off-by: Li Chen <me@linux.beauty> Link: https://lore.kernel.org/r/202512250116.ewtzlD0g-lkp@intel.com/ Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260630092338.2094628-12-me@linux.beauty>
78 lines
1.9 KiB
C
78 lines
1.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* virtio_pmem.h: virtio pmem Driver
|
|
*
|
|
* Discovers persistent memory range information
|
|
* from host and provides a virtio based flushing
|
|
* interface.
|
|
**/
|
|
|
|
#ifndef _LINUX_VIRTIO_PMEM_H
|
|
#define _LINUX_VIRTIO_PMEM_H
|
|
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/module.h>
|
|
#include <uapi/linux/virtio_pmem.h>
|
|
#include <linux/kref.h>
|
|
#include <linux/libnvdimm.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
struct virtio_pmem_request {
|
|
struct kref kref;
|
|
|
|
/* Wait queue to process deferred work after ack from host */
|
|
wait_queue_head_t host_acked;
|
|
bool done;
|
|
|
|
/* Wait queue to process deferred work after virt queue buffer avail */
|
|
wait_queue_head_t wq_buf;
|
|
bool wq_buf_avail;
|
|
struct list_head list;
|
|
|
|
struct virtio_pmem_req req;
|
|
__dma_from_device_group_begin(resp);
|
|
struct virtio_pmem_resp resp;
|
|
__dma_from_device_group_end(resp);
|
|
};
|
|
|
|
struct virtio_pmem {
|
|
struct virtio_device *vdev;
|
|
|
|
/* Virtio pmem request queue */
|
|
struct virtqueue *req_vq;
|
|
|
|
/* Serialize flush requests to the device. */
|
|
struct mutex flush_lock;
|
|
|
|
/* Complete asynchronous FUA flushes outside the submit path. */
|
|
struct workqueue_struct *flush_wq;
|
|
|
|
/* nvdimm bus registers virtio pmem device */
|
|
struct nvdimm_bus *nvdimm_bus;
|
|
struct nvdimm_bus_descriptor nd_desc;
|
|
|
|
/* List to store deferred work if virtqueue is full */
|
|
struct list_head req_list;
|
|
|
|
/* Request currently owned by the virtqueue. */
|
|
struct virtio_pmem_request *req_inflight;
|
|
|
|
/* Fail fast and wake waiters if the request virtqueue is broken. */
|
|
bool broken;
|
|
|
|
/* Synchronize virtqueue data */
|
|
spinlock_t pmem_lock;
|
|
|
|
/* Memory region information */
|
|
__u64 start;
|
|
__u64 size;
|
|
};
|
|
|
|
void virtio_pmem_host_ack(struct virtqueue *vq);
|
|
void virtio_pmem_mark_broken(struct virtio_pmem *vpmem);
|
|
void virtio_pmem_drain(struct virtio_pmem *vpmem);
|
|
int async_pmem_flush(struct nd_region *nd_region, struct bio *bio);
|
|
#endif
|