diff --git a/patches.suse/NFS-Fix-error-handling-for-O_DIRECT-write-scheduling.patch b/patches.suse/NFS-Fix-error-handling-for-O_DIRECT-write-scheduling.patch new file mode 100644 index 0000000..f026c3e --- /dev/null +++ b/patches.suse/NFS-Fix-error-handling-for-O_DIRECT-write-scheduling.patch @@ -0,0 +1,147 @@ +From: Trond Myklebust +Date: Mon, 4 Sep 2023 12:34:37 -0400 +Subject: [PATCH] NFS: Fix error handling for O_DIRECT write scheduling +Git-commit: 954998b60caa8f2a3bf3abe490de6f08d283687a +Patch-mainline: v6.6 +References: git-fixes + +If we fail to schedule a request for transmission, there are 2 +Possibilities: +1) Either we hit a fatal error, and we just want to drop the remaining + requests on the floor. +2) We were asked to try again, in which case we should allow the + outstanding RPC calls to complete, so that we can recoalesce requests + and try again. + +Fixes: d600ad1f2bdb ("NFS41: pop some layoutget errors to application") +Signed-off-by: Trond Myklebust +Signed-off-by: Anna Schumaker +Acked-by: NeilBrown + +--- + fs/nfs/direct.c | 67 +++++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 47 insertions(+), 20 deletions(-) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -655,10 +655,9 @@ nfs_direct_write_scan_commit_list(struct + static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) + { + struct nfs_pageio_descriptor desc; +- struct nfs_page *req, *tmp; ++ struct nfs_page *req; + LIST_HEAD(reqs); + struct nfs_commit_info cinfo; +- LIST_HEAD(failed); + int i; + + nfs_init_cinfo_from_dreq(&cinfo, dreq); +@@ -680,32 +679,38 @@ static void nfs_direct_write_reschedule( + + req = nfs_list_entry(reqs.next); + nfs_direct_setup_mirroring(dreq, &desc, req); +- if (desc.pg_error < 0) { +- list_splice_init(&reqs, &failed); ++ if (desc.pg_error < 0) + goto out_failed; +- } + +- list_for_each_entry_safe(req, tmp, &reqs, wb_list) { ++ while (!list_empty(&reqs)) { ++ req = nfs_list_entry(reqs.next); + if (!nfs_pageio_add_request(&desc, req)) { +- nfs_list_remove_request(req); +- nfs_list_add_request(req, &failed); + spin_lock(&cinfo.inode->i_lock); +- dreq->flags = 0; +- if (desc.pg_error < 0) ++ if (dreq->error < 0) { ++ desc.pg_error = dreq->error; ++ } else if (desc.pg_error != -EAGAIN) { ++ dreq->flags = 0; ++ if (!desc.pg_error) ++ desc.pg_error = -EIO; + dreq->error = desc.pg_error; +- else +- dreq->error = -EIO; ++ } else ++ dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + spin_unlock(&cinfo.inode->i_lock); ++ break; + } + nfs_release_request(req); + } + nfs_pageio_complete(&desc); + + out_failed: +- while (!list_empty(&failed)) { +- req = nfs_list_entry(failed.next); ++ while (!list_empty(&reqs)) { ++ req = nfs_list_entry(reqs.next); + nfs_list_remove_request(req); + nfs_unlock_and_release_request(req); ++ if (desc.pg_error == -EAGAIN) ++ nfs_mark_request_commit(req, NULL, &cinfo, 0); ++ else ++ nfs_release_request(req); + } + + if (put_dreq(dreq)) +@@ -893,9 +898,11 @@ static ssize_t nfs_direct_write_schedule + { + struct nfs_pageio_descriptor desc; + struct inode *inode = dreq->inode; ++ struct nfs_commit_info cinfo; + ssize_t result = 0; + size_t requested_bytes = 0; + size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE); ++ bool defer = false; + + nfs_pageio_init_write(&desc, inode, ioflags, false, + &nfs_direct_write_completion_ops); +@@ -936,19 +943,39 @@ static ssize_t nfs_direct_write_schedule + break; + } + ++ pgbase = 0; ++ bytes -= req_len; ++ requested_bytes += req_len; ++ pos += req_len; ++ dreq->bytes_left -= req_len; ++ ++ if (defer) { ++ nfs_mark_request_commit(req, NULL, &cinfo, 0); ++ continue; ++ } ++ + nfs_lock_request(req); + req->wb_index = pos >> PAGE_SHIFT; + req->wb_offset = pos & ~PAGE_MASK; +- if (!nfs_pageio_add_request(&desc, req)) { ++ if (nfs_pageio_add_request(&desc, req)) ++ continue; ++ ++ /* Exit on hard errors */ ++ if (desc.pg_error < 0 && desc.pg_error != -EAGAIN) { + result = desc.pg_error; + nfs_unlock_and_release_request(req); + break; + } +- pgbase = 0; +- bytes -= req_len; +- requested_bytes += req_len; +- pos += req_len; +- dreq->bytes_left -= req_len; ++ ++ /* If the error is soft, defer remaining requests */ ++ nfs_init_cinfo_from_dreq(&cinfo, dreq); ++ spin_lock(&cinfo.inode->i_lock); ++ dreq->flags = NFS_ODIRECT_RESCHED_WRITES; ++ spin_unlock(&cinfo.inode->i_lock); ++ nfs_unlock_request(req); ++ nfs_mark_request_commit(req, NULL, &cinfo, 0); ++ desc.pg_error = 0; ++ defer = true; + } + nfs_direct_release_pages(pagevec, npages); + kvfree(pagevec); diff --git a/series.conf b/series.conf index c52f3fa..4ceaa5e 100644 --- a/series.conf +++ b/series.conf @@ -64836,6 +64836,7 @@ patches.suse/nfsd-fix-change_info-in-NFSv4-RENAME-replies.patch patches.suse/scsi-qla2xxx-Use-raw_smp_processor_id-instead-of-smp.patch patches.suse/scsi-qla2xxx-Fix-NULL-vs-IS_ERR-bug-for-debugfs_crea.patch + patches.suse/NFS-Fix-error-handling-for-O_DIRECT-write-scheduling.patch patches.suse/NFS-pNFS-Report-EINVAL-errors-from-connect-to-the-se.patch patches.suse/ipv4-fix-null-deref-in-ipv4_link_failure.patch patches.suse/team-fix-null-ptr-deref-when-team-device-type-is-cha.patch