The -ENOMEM from virtqueue_add_outbuf() under GFP_ATOMIC is typically transient. Queue the FORGET on queued_reqs and return 1 so the hiprio worker backs off and retries instead of dropping the forget.
This matches the existing -ENOSPC handling and avoids silent loss of nlookup decrements under memory pressure. Signed-off-by: Li Wang <[email protected]> --- fs/fuse/virtio_fs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index bcba1210c797..7e4c3fa6ab57 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -611,8 +611,8 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) } /* - * Returns 1 if queue is full and sender should wait a bit before sending - * next request, 0 otherwise. + * Returns 1 if the hiprio queue is full or transient allocation failed and + * the caller should wait before submitting the next FORGET, 0 otherwise. */ static int send_forget_request(struct virtio_fs_vq *fsvq, struct virtio_fs_forget *forget, @@ -638,13 +638,13 @@ static int send_forget_request(struct virtio_fs_vq *fsvq, ret = virtqueue_add_outbuf(vq, &sg, 1, forget, GFP_ATOMIC); if (ret < 0) { - if (ret == -ENOSPC) { + if (ret == -ENOSPC || ret == -ENOMEM) { pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later\n", ret); list_add_tail(&forget->list, &fsvq->queued_reqs); if (!in_flight) inc_in_flight_req(fsvq); - /* Queue is full */ + /* Queue full or GFP_ATOMIC allocation failure; retry later */ ret = 1; } else { pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n", -- 2.34.1

