diff --git a/patches.suse/NFS-More-O_DIRECT-accounting-fixes-for-error-paths.patch b/patches.suse/NFS-More-O_DIRECT-accounting-fixes-for-error-paths.patch new file mode 100644 index 0000000..7b5d2fc --- /dev/null +++ b/patches.suse/NFS-More-O_DIRECT-accounting-fixes-for-error-paths.patch @@ -0,0 +1,129 @@ +From: Trond Myklebust +Date: Mon, 4 Sep 2023 12:34:39 -0400 +Subject: [PATCH] NFS: More O_DIRECT accounting fixes for error paths +Git-commit: 8982f7aff39fb526aba4441fff2525fcedd5e1a3 +Patch-mainline: v6.6 +References: git-fixes + +If we hit a fatal error when retransmitting, we do need to record the +removal of the request from the count of written bytes. + +Fixes: 031d73ed768a ("NFS: Fix O_DIRECT accounting of number of bytes read/written") +Signed-off-by: Trond Myklebust +Signed-off-by: Anna Schumaker +Acked-by: NeilBrown + +--- + fs/nfs/direct.c | 47 +++++++++++++++++++++++++++++++---------------- + 1 file changed, 31 insertions(+), 16 deletions(-) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -135,12 +135,10 @@ nfs_direct_handle_truncated(struct nfs_d + dreq->max_count = dreq_len; + if (dreq->count > dreq_len) + dreq->count = dreq_len; +- +- if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) +- dreq->error = hdr->error; +- else /* Clear outstanding error if this is EOF */ +- dreq->error = 0; + } ++ ++ if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && !dreq->error) ++ dreq->error = hdr->error; + if (mirror->count > dreq_len) + mirror->count = dreq_len; + } +@@ -167,6 +165,18 @@ nfs_direct_count_bytes(struct nfs_direct + dreq->count = dreq_len; + } + ++static void nfs_direct_truncate_request(struct nfs_direct_req *dreq, ++ struct nfs_page *req) ++{ ++ loff_t offs = req_offset(req); ++ size_t req_start = (size_t)(offs - dreq->io_start); ++ ++ if (req_start < dreq->max_count) ++ dreq->max_count = req_start; ++ if (req_start < dreq->count) ++ dreq->count = req_start; ++} ++ + /** + * nfs_direct_IO - NFS address space operation for direct I/O + * @iocb: target I/O control block +@@ -562,10 +572,6 @@ static void nfs_direct_write_reschedule( + nfs_init_cinfo_from_dreq(&cinfo, dreq); + nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); + +- dreq->count = 0; +- dreq->max_count = 0; +- list_for_each_entry(req, &reqs, wb_list) +- dreq->max_count += req->wb_bytes; + nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo); + for (i = 0; i < dreq->mirror_count; i++) + dreq->mirrors[i].count = 0; +@@ -605,10 +611,14 @@ out_failed: + req = nfs_list_entry(reqs.next); + nfs_list_remove_request(req); + nfs_unlock_and_release_request(req); +- if (desc.pg_error == -EAGAIN) ++ if (desc.pg_error == -EAGAIN) { + nfs_mark_request_commit(req, NULL, &cinfo, 0); +- else ++ } else { ++ spin_lock(&dreq->lock); ++ nfs_direct_truncate_request(dreq, req); ++ spin_unlock(&dreq->lock); + nfs_release_request(req); ++ } + } + + if (put_dreq(dreq)) +@@ -626,8 +636,6 @@ static void nfs_direct_commit_complete(s + if (status < 0) { + /* Errors in commit are fatal */ + dreq->error = status; +- dreq->max_count = 0; +- dreq->count = 0; + dreq->flags = NFS_ODIRECT_DONE; + } else if (dreq->flags == NFS_ODIRECT_DONE) + status = dreq->error; +@@ -637,10 +645,15 @@ static void nfs_direct_commit_complete(s + while (!list_empty(&data->pages)) { + req = nfs_list_entry(data->pages.next); + nfs_list_remove_request(req); +- if (status >= 0 && !nfs_write_match_verf(verf, req)) { ++ if (status < 0) { ++ spin_lock(&dreq->lock); ++ nfs_direct_truncate_request(dreq, req); ++ spin_unlock(&dreq->lock); ++ nfs_release_request(req); ++ } else if (!nfs_write_match_verf(verf, req)) { + dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + nfs_mark_request_commit(req, NULL, &cinfo, 0); +- } else /* Error or match */ ++ } else + nfs_release_request(req); + nfs_unlock_and_release_request(req); + } +@@ -691,6 +704,7 @@ static void nfs_direct_write_clear_reqs( + while (!list_empty(&reqs)) { + req = nfs_list_entry(reqs.next); + nfs_list_remove_request(req); ++ nfs_direct_truncate_request(dreq, req); + nfs_release_request(req); + nfs_unlock_and_release_request(req); + } +@@ -737,7 +751,8 @@ static void nfs_direct_write_completion( + } + + nfs_direct_count_bytes(dreq, hdr); +- if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags)) { ++ if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags) && ++ !test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { + switch (dreq->flags) { + case 0: + dreq->flags = NFS_ODIRECT_DO_COMMIT; diff --git a/series.conf b/series.conf index 4ceaa5e..94cac11 100644 --- a/series.conf +++ b/series.conf @@ -64837,6 +64837,7 @@ 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-More-O_DIRECT-accounting-fixes-for-error-paths.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