From bb26dc8d5a8522b59071608fab5ac77c8ad1c89b Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Mar 25 2024 08:32:01 +0000 Subject: Merge branch 'users/nfbrown/SLE12-SP5/for-next' into SLE12-SP5 Pull nfs fixes from Neil Brown --- diff --git a/patches.kabi/pNFS-Fix-the-pnfs-block-driver-s-calculation-of-layo.patch b/patches.kabi/pNFS-Fix-the-pnfs-block-driver-s-calculation-of-layo.patch new file mode 100644 index 0000000..83b9415 --- /dev/null +++ b/patches.kabi/pNFS-Fix-the-pnfs-block-driver-s-calculation-of-layo.patch @@ -0,0 +1,72 @@ +From: NeilBrown +Subject: kabi fix for pNFS: Fix the pnfs block driver's calculation of layoutget size +Patch-mainline: Never, kabi +References: git-fixes + +Rather than changing the signature of an exported function, create a new +function with the new functionality and use that. + +--- + fs/nfs/blocklayout/blocklayout.c | 2 +- + fs/nfs/direct.c | 10 ++++++++-- + fs/nfs/internal.h | 3 ++- + fs/nfs/pnfs.c | 2 +- + 4 files changed, 12 insertions(+), 5 deletions(-) + +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -849,7 +849,7 @@ bl_pg_init_write(struct nfs_pageio_descr + if (pgio->pg_dreq == NULL) + wb_size = pnfs_num_cont_bytes(pgio->pg_inode, req->wb_index); + else +- wb_size = nfs_dreq_bytes_left(pgio->pg_dreq, req_offset(req)); ++ wb_size = nfs_dreq_bytes_left_offset(pgio->pg_dreq, req_offset(req)); + + pnfs_generic_pg_init_write(pgio, req, wb_size); + } +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -267,12 +267,18 @@ static void nfs_direct_req_release(struc + kref_put(&dreq->kref, nfs_direct_req_free); + } + +-ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq, loff_t offset) ++ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq) ++{ ++ return dreq->bytes_left; ++} ++EXPORT_SYMBOL_GPL(nfs_dreq_bytes_left); ++ ++ssize_t nfs_dreq_bytes_left_offset(struct nfs_direct_req *dreq, loff_t offset) + { + loff_t start = offset - dreq->io_start; + return dreq->max_count - start; + } +-EXPORT_SYMBOL_GPL(nfs_dreq_bytes_left); ++EXPORT_SYMBOL_GPL(nfs_dreq_bytes_left_offset); + + /* + * Collects and returns the final error value/byte-count. +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -577,7 +577,8 @@ extern int nfs_sillyrename(struct inode + /* direct.c */ + void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, + struct nfs_direct_req *dreq); +-extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq, loff_t offset); ++extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); ++extern ssize_t nfs_dreq_bytes_left_offset(struct nfs_direct_req *dreq, loff_t offset); + + /* nfs4proc.c */ + extern struct nfs_client *nfs4_init_client(struct nfs_client *clp, +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -2173,7 +2173,7 @@ pnfs_generic_pg_init_read(struct nfs_pag + if (pgio->pg_dreq == NULL) + rd_size = i_size_read(pgio->pg_inode) - req_offset(req); + else +- rd_size = nfs_dreq_bytes_left(pgio->pg_dreq, ++ rd_size = nfs_dreq_bytes_left_offset(pgio->pg_dreq, + req_offset(req)); + + pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, diff --git a/patches.suse/NFS-Fix-O_DIRECT-commit-verifier-handling.patch b/patches.suse/NFS-Fix-O_DIRECT-commit-verifier-handling.patch new file mode 100644 index 0000000..b13e7d4 --- /dev/null +++ b/patches.suse/NFS-Fix-O_DIRECT-commit-verifier-handling.patch @@ -0,0 +1,240 @@ +From: Trond Myklebust +Date: Sat, 21 Mar 2020 09:27:46 -0400 +Subject: [PATCH] NFS: Fix O_DIRECT commit verifier handling +Git-commit: 1f28476dcb98797e838a0c1dd6eae2fda213dd81 +Patch-mainline: v5.7 +References: git-fixes + +Instead of trying to save the commit verifiers and checking them against +previous writes, adopt the same strategy as for buffered writes, of +just checking the verifiers at commit time. + +Signed-off-by: Trond Myklebust +Acked-by: NeilBrown + +--- + fs/nfs/direct.c | 135 +++++------------------------------------------------- + fs/nfs/internal.h | 8 +++ + fs/nfs/write.c | 3 - + 3 files changed, 22 insertions(+), 124 deletions(-) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -104,7 +104,6 @@ struct nfs_direct_req { + /* for read */ + #define NFS_ODIRECT_SHOULD_DIRTY (3) /* dirty user-space page after read */ + #define NFS_ODIRECT_DONE INT_MAX /* write verification failed */ +- struct nfs_writeverf verf; /* unstable write verifier */ + }; + + static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops; +@@ -168,106 +167,6 @@ nfs_direct_count_bytes(struct nfs_direct + dreq->count = dreq_len; + } + +-/* +- * nfs_direct_select_verf - select the right verifier +- * @dreq - direct request possibly spanning multiple servers +- * @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs +- * @commit_idx - commit bucket index for the DS +- * +- * returns the correct verifier to use given the role of the server +- */ +-static struct nfs_writeverf * +-nfs_direct_select_verf(struct nfs_direct_req *dreq, +- struct nfs_client *ds_clp, +- int commit_idx) +-{ +- struct nfs_writeverf *verfp = &dreq->verf; +- +-#ifdef CONFIG_NFS_V4_1 +- /* +- * pNFS is in use, use the DS verf except commit_through_mds is set +- * for layout segment where nbuckets is zero. +- */ +- if (ds_clp && dreq->ds_cinfo.nbuckets > 0) { +- if (commit_idx >= 0 && commit_idx < dreq->ds_cinfo.nbuckets) +- verfp = &dreq->ds_cinfo.buckets[commit_idx].direct_verf; +- else +- WARN_ON_ONCE(1); +- } +-#endif +- return verfp; +-} +- +- +-/* +- * nfs_direct_set_hdr_verf - set the write/commit verifier +- * @dreq - direct request possibly spanning multiple servers +- * @hdr - pageio header to validate against previously seen verfs +- * +- * Set the server's (MDS or DS) "seen" verifier +- */ +-static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, +- struct nfs_pgio_header *hdr) +-{ +- struct nfs_writeverf *verfp; +- +- verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, hdr->ds_commit_idx); +- WARN_ON_ONCE(verfp->committed >= 0); +- memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); +- WARN_ON_ONCE(verfp->committed < 0); +-} +- +-static int nfs_direct_cmp_verf(const struct nfs_writeverf *v1, +- const struct nfs_writeverf *v2) +-{ +- return nfs_write_verifier_cmp(&v1->verifier, &v2->verifier); +-} +- +-/* +- * nfs_direct_cmp_hdr_verf - compare verifier for pgio header +- * @dreq - direct request possibly spanning multiple servers +- * @hdr - pageio header to validate against previously seen verf +- * +- * set the server's "seen" verf if not initialized. +- * returns result of comparison between @hdr->verf and the "seen" +- * verf of the server used by @hdr (DS or MDS) +- */ +-static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, +- struct nfs_pgio_header *hdr) +-{ +- struct nfs_writeverf *verfp; +- +- verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, hdr->ds_commit_idx); +- if (verfp->committed < 0) { +- nfs_direct_set_hdr_verf(dreq, hdr); +- return 0; +- } +- return nfs_direct_cmp_verf(verfp, &hdr->verf); +-} +- +-/* +- * nfs_direct_cmp_commit_data_verf - compare verifier for commit data +- * @dreq - direct request possibly spanning multiple servers +- * @data - commit data to validate against previously seen verf +- * +- * returns result of comparison between @data->verf and the verf of +- * the server used by @data (DS or MDS) +- */ +-static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, +- struct nfs_commit_data *data) +-{ +- struct nfs_writeverf *verfp; +- +- verfp = nfs_direct_select_verf(dreq, data->ds_clp, +- data->ds_commit_index); +- +- /* verifier not set so always fail */ +- if (verfp->committed < 0 || data->res.verf->committed <= NFS_UNSTABLE) +- return 1; +- +- return nfs_direct_cmp_verf(verfp, data->res.verf); +-} +- + /** + * nfs_direct_IO - NFS address space operation for direct I/O + * @iocb: target I/O control block +@@ -334,7 +233,6 @@ static inline struct nfs_direct_req *nfs + kref_get(&dreq->kref); + init_completion(&dreq->completion); + INIT_LIST_HEAD(&dreq->mds_cinfo.list); +- dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ + INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); + dreq->mirror_count = 1; + spin_lock_init(&dreq->lock); +@@ -668,7 +566,6 @@ static void nfs_direct_write_reschedule( + dreq->max_count = 0; + list_for_each_entry(req, &reqs, wb_list) + dreq->max_count += req->wb_bytes; +- dreq->verf.committed = NFS_INVALID_STABLE_HOW; + nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo); + for (i = 0; i < dreq->mirror_count; i++) + dreq->mirrors[i].count = 0; +@@ -720,6 +617,7 @@ out_failed: + + static void nfs_direct_commit_complete(struct nfs_commit_data *data) + { ++ const struct nfs_writeverf *verf = data->res.verf; + struct nfs_direct_req *dreq = data->dreq; + struct nfs_commit_info cinfo; + struct nfs_page *req; +@@ -735,16 +633,14 @@ static void nfs_direct_commit_complete(s + status = dreq->error; + + nfs_init_cinfo_from_dreq(&cinfo, dreq); +- if (nfs_direct_cmp_commit_data_verf(dreq, data)) +- dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + + while (!list_empty(&data->pages)) { + req = nfs_list_entry(data->pages.next); + nfs_list_remove_request(req); +- if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) { +- /* Note the rewrite will go through mds */ ++ if (status >= 0 && !nfs_write_match_verf(verf, req)) { ++ dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + nfs_mark_request_commit(req, NULL, &cinfo, 0); +- } else ++ } else /* Error or match */ + nfs_release_request(req); + nfs_unlock_and_release_request(req); + } +@@ -840,20 +736,15 @@ static void nfs_direct_write_completion( + } + + nfs_direct_count_bytes(dreq, hdr); +- if (hdr->good_bytes != 0) { +- if (nfs_write_need_commit(hdr)) { +- if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) +- request_commit = true; +- else if (dreq->flags == 0) { +- nfs_direct_set_hdr_verf(dreq, hdr); +- request_commit = true; +- dreq->flags = NFS_ODIRECT_DO_COMMIT; +- } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { +- request_commit = true; +- if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr)) +- dreq->flags = +- NFS_ODIRECT_RESCHED_WRITES; +- } ++ if (hdr->good_bytes != 0 && nfs_write_need_commit(hdr)) { ++ switch (dreq->flags) { ++ case 0: ++ dreq->flags = NFS_ODIRECT_DO_COMMIT; ++ request_commit = true; ++ break; ++ case NFS_ODIRECT_RESCHED_WRITES: ++ case NFS_ODIRECT_DO_COMMIT: ++ request_commit = true; + } + } + spin_unlock(&dreq->lock); +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -559,6 +559,14 @@ nfs_write_verifier_cmp(const struct nfs_ + return memcmp(v1->data, v2->data, sizeof(v1->data)); + } + ++static inline bool ++nfs_write_match_verf(const struct nfs_writeverf *verf, ++ struct nfs_page *req) ++{ ++ return verf->committed > NFS_UNSTABLE && ++ !nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier); ++} ++ + /* unlink.c */ + extern struct rpc_task * + nfs_async_rename(struct inode *old_dir, struct inode *new_dir, +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -1864,8 +1864,7 @@ static void nfs_commit_release_pages(str + + /* Okay, COMMIT succeeded, apparently. Check the verifier + * returned by the server against all stored verfs. */ +- if (verf->committed > NFS_UNSTABLE && +- !nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier)) { ++ if (nfs_write_match_verf(verf, req)) { + /* We have a match */ + if (req->wb_page) + nfs_inode_remove_request(req); diff --git a/patches.suse/NFS-Fix-O_DIRECT-locking-issues.patch b/patches.suse/NFS-Fix-O_DIRECT-locking-issues.patch new file mode 100644 index 0000000..7a98c8a --- /dev/null +++ b/patches.suse/NFS-Fix-O_DIRECT-locking-issues.patch @@ -0,0 +1,50 @@ +From: Trond Myklebust +Date: Mon, 4 Sep 2023 12:34:38 -0400 +Subject: [PATCH] NFS: Fix O_DIRECT locking issues +Git-commit: 7c6339322ce0c6128acbe36aacc1eeb986dd7bf1 +Patch-mainline: v6.6 +References: git-fixes + +The dreq fields are protected by the dreq->lock. + +Fixes: 954998b60caa ("NFS: Fix error handling for O_DIRECT write scheduling") +Signed-off-by: Trond Myklebust +Signed-off-by: Anna Schumaker +Acked-by: NeilBrown + +--- + fs/nfs/direct.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -589,7 +589,7 @@ static void nfs_direct_write_reschedule( + while (!list_empty(&reqs)) { + req = nfs_list_entry(reqs.next); + if (!nfs_pageio_add_request(&desc, req)) { +- spin_lock(&cinfo.inode->i_lock); ++ spin_lock(&dreq->lock); + if (dreq->error < 0) { + desc.pg_error = dreq->error; + } else if (desc.pg_error != -EAGAIN) { +@@ -599,7 +599,7 @@ static void nfs_direct_write_reschedule( + dreq->error = desc.pg_error; + } else + dreq->flags = NFS_ODIRECT_RESCHED_WRITES; +- spin_unlock(&cinfo.inode->i_lock); ++ spin_unlock(&dreq->lock); + break; + } + nfs_release_request(req); +@@ -906,9 +906,9 @@ static ssize_t nfs_direct_write_schedule + + /* If the error is soft, defer remaining requests */ + nfs_init_cinfo_from_dreq(&cinfo, dreq); +- spin_lock(&cinfo.inode->i_lock); ++ spin_lock(&dreq->lock); + dreq->flags = NFS_ODIRECT_RESCHED_WRITES; +- spin_unlock(&cinfo.inode->i_lock); ++ spin_unlock(&dreq->lock); + nfs_unlock_request(req); + nfs_mark_request_commit(req, NULL, &cinfo, 0); + desc.pg_error = 0; diff --git a/patches.suse/NFS-Fix-a-request-reference-leak-in-nfs_direct_write.patch b/patches.suse/NFS-Fix-a-request-reference-leak-in-nfs_direct_write.patch new file mode 100644 index 0000000..ceb2f7c --- /dev/null +++ b/patches.suse/NFS-Fix-a-request-reference-leak-in-nfs_direct_write.patch @@ -0,0 +1,30 @@ +From: Trond Myklebust +Date: Mon, 30 Mar 2020 20:13:48 -0400 +Subject: [PATCH] NFS: Fix a request reference leak in + nfs_direct_write_clear_reqs() +Git-commit: f02cec9d33e0069c11e58f97529c1d697255889d +Patch-mainline: v5.7 +References: git-fixes + +nfs_direct_write_scan_commit_list() will lock the request and bump +the reference count, but we also need to account for the reference +that was taken when we initially added the request to the commit list. + +Fixes: fb5f7f20cdb9 ("NFS: commit errors should be fatal") +Signed-off-by: Trond Myklebust +Acked-by: NeilBrown + +--- + fs/nfs/direct.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -691,6 +691,7 @@ static void nfs_direct_write_clear_reqs( + while (!list_empty(&reqs)) { + req = nfs_list_entry(reqs.next); + nfs_list_remove_request(req); ++ nfs_release_request(req); + nfs_unlock_and_release_request(req); + } + } diff --git a/patches.suse/NFS-Fix-an-off-by-one-in-root_nfs_cat.patch b/patches.suse/NFS-Fix-an-off-by-one-in-root_nfs_cat.patch new file mode 100644 index 0000000..71e8c93 --- /dev/null +++ b/patches.suse/NFS-Fix-an-off-by-one-in-root_nfs_cat.patch @@ -0,0 +1,36 @@ +From: Christophe JAILLET +Date: Sun, 18 Feb 2024 22:16:53 +0100 +Subject: [PATCH] NFS: Fix an off by one in root_nfs_cat() +Git-commit: 698ad1a538da0b6bf969cfee630b4e3a026afb87 +Patch-mainline: v6.9-rc1 +References: git-fixes + +The intent is to check if 'dest' is truncated or not. So, >= should be +used instead of >, because strlcat() returns the length of 'dest' and 'src' +excluding the trailing NULL. + +Fixes: 56463e50d1fc ("NFS: Use super.c for NFSROOT mount option parsing") +Signed-off-by: Christophe JAILLET +Reviewed-by: Benjamin Coddington +Signed-off-by: Trond Myklebust +Acked-by: NeilBrown + +--- + fs/nfs/nfsroot.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/nfs/nfsroot.c ++++ b/fs/nfs/nfsroot.c +@@ -168,10 +168,10 @@ static int __init root_nfs_cat(char *des + size_t len = strlen(dest); + + if (len && dest[len - 1] != ',') +- if (strlcat(dest, ",", destlen) > destlen) ++ if (strlcat(dest, ",", destlen) >= destlen) + return -1; + +- if (strlcat(dest, src, destlen) > destlen) ++ if (strlcat(dest, src, destlen) >= destlen) + return -1; + return 0; + } diff --git a/patches.suse/NFS-Fix-direct-WRITE-throughput-regression.patch b/patches.suse/NFS-Fix-direct-WRITE-throughput-regression.patch new file mode 100644 index 0000000..8106ee5 --- /dev/null +++ b/patches.suse/NFS-Fix-direct-WRITE-throughput-regression.patch @@ -0,0 +1,44 @@ +From: Chuck Lever +Date: Fri, 29 May 2020 14:14:40 -0400 +Subject: [PATCH] NFS: Fix direct WRITE throughput regression +Git-commit: ba838a75e73f55a780f1ee896b8e3ecb032dba0f +Patch-mainline: v5.8 +References: git-fixes + +I measured a 50% throughput regression for large direct writes. + +The observed on-the-wire behavior is that the client sends every +NFS WRITE twice: once as an UNSTABLE WRITE plus a COMMIT, and once +as a FILE_SYNC WRITE. + +This is because the nfs_write_match_verf() check in +nfs_direct_commit_complete() fails for every WRITE. + +Buffered writes use nfs_write_completion(), which sets req->wb_verf +correctly. Direct writes use nfs_direct_write_completion(), which +does not set req->wb_verf at all. This leaves req->wb_verf set to +all zeroes for every direct WRITE, and thus +nfs_direct_commit_completion() always sets NFS_ODIRECT_RESCHED_WRITES. + +This fix appears to restore nearly all of the lost performance. + +Fixes: 1f28476dcb98 ("NFS: Fix O_DIRECT commit verifier handling") +Signed-off-by: Chuck Lever +Signed-off-by: Anna Schumaker +Acked-by: NeilBrown + +--- + fs/nfs/direct.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -771,6 +771,8 @@ static void nfs_direct_write_completion( + nfs_list_remove_request(req); + if (request_commit) { + kref_get(&req->wb_kref); ++ memcpy(&req->wb_verf, &hdr->verf.verifier, ++ sizeof(req->wb_verf)); + nfs_mark_request_commit(req, hdr->lseg, &cinfo, + hdr->ds_commit_idx); + } 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/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/patches.suse/NFS-commit-errors-should-be-fatal.patch b/patches.suse/NFS-commit-errors-should-be-fatal.patch new file mode 100644 index 0000000..bf87313 --- /dev/null +++ b/patches.suse/NFS-commit-errors-should-be-fatal.patch @@ -0,0 +1,87 @@ +From: Trond Myklebust +Date: Sat, 21 Mar 2020 09:36:13 -0400 +Subject: [PATCH] NFS: commit errors should be fatal +Git-commit: fb5f7f20cdb91f8ef985aef09fa2217c49c38396 +Patch-mainline: v5.7 +References: git-fixes + +Fix the O_DIRECT code to avoid retries if the COMMIT fails with a fatal +error. + +Signed-off-by: Trond Myklebust +Acked-by: NeilBrown + +--- + fs/nfs/direct.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -103,6 +103,7 @@ struct nfs_direct_req { + #define NFS_ODIRECT_RESCHED_WRITES (2) /* write verification failed */ + /* for read */ + #define NFS_ODIRECT_SHOULD_DIRTY (3) /* dirty user-space page after read */ ++#define NFS_ODIRECT_DONE INT_MAX /* write verification failed */ + struct nfs_writeverf verf; /* unstable write verifier */ + }; + +@@ -724,8 +725,17 @@ static void nfs_direct_commit_complete(s + struct nfs_page *req; + int status = data->task.tk_status; + ++ 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; ++ + nfs_init_cinfo_from_dreq(&cinfo, dreq); +- if (status < 0 || nfs_direct_cmp_commit_data_verf(dreq, data)) ++ if (nfs_direct_cmp_commit_data_verf(dreq, data)) + dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + + while (!list_empty(&data->pages)) { +@@ -749,7 +759,8 @@ static void nfs_direct_resched_write(str + struct nfs_direct_req *dreq = cinfo->dreq; + + spin_lock(&dreq->lock); +- dreq->flags = NFS_ODIRECT_RESCHED_WRITES; ++ if (dreq->flags != NFS_ODIRECT_DONE) ++ dreq->flags = NFS_ODIRECT_RESCHED_WRITES; + spin_unlock(&dreq->lock); + nfs_mark_request_commit(req, NULL, cinfo, 0); + } +@@ -772,6 +783,22 @@ static void nfs_direct_commit_schedule(s + nfs_direct_write_reschedule(dreq); + } + ++static void nfs_direct_write_clear_reqs(struct nfs_direct_req *dreq) ++{ ++ struct nfs_commit_info cinfo; ++ struct nfs_page *req; ++ LIST_HEAD(reqs); ++ ++ nfs_init_cinfo_from_dreq(&cinfo, dreq); ++ nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); ++ ++ while (!list_empty(&reqs)) { ++ req = nfs_list_entry(reqs.next); ++ nfs_list_remove_request(req); ++ nfs_unlock_and_release_request(req); ++ } ++} ++ + static void nfs_direct_write_schedule_work(struct work_struct *work) + { + struct nfs_direct_req *dreq = container_of(work, struct nfs_direct_req, work); +@@ -786,6 +813,7 @@ static void nfs_direct_write_schedule_wo + nfs_direct_write_reschedule(dreq); + break; + default: ++ nfs_direct_write_clear_reqs(dreq); + nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping); + nfs_direct_complete(dreq); + } diff --git a/patches.suse/SUNRPC-fix-a-memleak-in-gss_import_v2_context.patch b/patches.suse/SUNRPC-fix-a-memleak-in-gss_import_v2_context.patch new file mode 100644 index 0000000..784b98c --- /dev/null +++ b/patches.suse/SUNRPC-fix-a-memleak-in-gss_import_v2_context.patch @@ -0,0 +1,62 @@ +From: Zhipeng Lu +Date: Sun, 24 Dec 2023 16:20:33 +0800 +Subject: [PATCH] SUNRPC: fix a memleak in gss_import_v2_context +Git-commit: e67b652d8e8591d3b1e569dbcdfcee15993e91fa +Patch-mainline: v6.9-rc1 +References: git-fixes + +The ctx->mech_used.data allocated by kmemdup is not freed in neither +gss_import_v2_context nor it only caller gss_krb5_import_sec_context, +which frees ctx on error. + +Thus, this patch reform the last call of gss_import_v2_context to the +gss_krb5_import_ctx_v2, preventing the memleak while keepping the return +formation. + +Fixes: 47d848077629 ("gss_krb5: handle new context format from gssd") +Signed-off-by: Zhipeng Lu +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Acked-by: NeilBrown + +--- + net/sunrpc/auth_gss/gss_krb5_mech.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/net/sunrpc/auth_gss/gss_krb5_mech.c ++++ b/net/sunrpc/auth_gss/gss_krb5_mech.c +@@ -584,6 +584,7 @@ gss_import_v2_context(const void *p, con + gfp_t gfp_mask) + { + int keylen; ++ int ret; + + p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); + if (IS_ERR(p)) +@@ -638,16 +639,22 @@ gss_import_v2_context(const void *p, con + + switch (ctx->enctype) { + case ENCTYPE_DES3_CBC_RAW: +- return context_derive_keys_des3(ctx, gfp_mask); ++ ret = context_derive_keys_des3(ctx, gfp_mask); ++ break; + case ENCTYPE_ARCFOUR_HMAC: +- return context_derive_keys_rc4(ctx); ++ ret = context_derive_keys_rc4(ctx); ++ break; + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: +- return context_derive_keys_new(ctx, gfp_mask); ++ ret = context_derive_keys_new(ctx, gfp_mask); ++ break; + default: +- return -EINVAL; ++ ret = -EINVAL; + } + ++ if (ret) ++ kfree(ctx->mech_used.data); ++ return ret; + out_err: + return PTR_ERR(p); + } diff --git a/patches.suse/net-sunrpc-Fix-an-off-by-one-in-rpc_sockaddr2uaddr.patch b/patches.suse/net-sunrpc-Fix-an-off-by-one-in-rpc_sockaddr2uaddr.patch new file mode 100644 index 0000000..fddc8a9 --- /dev/null +++ b/patches.suse/net-sunrpc-Fix-an-off-by-one-in-rpc_sockaddr2uaddr.patch @@ -0,0 +1,36 @@ +From: Christophe JAILLET +Date: Tue, 24 Oct 2023 23:58:20 +0200 +Subject: [PATCH] net: sunrpc: Fix an off by one in rpc_sockaddr2uaddr() +Git-commit: d6f4de70f73a106986ee315d7d512539f2f3303a +Patch-mainline: v6.9-rc1 +References: git-fixes + +The intent is to check if the strings' are truncated or not. So, >= should +be used instead of >, because strlcat() and snprintf() return the length of +the output, excluding the trailing NULL. + +Fixes: a02d69261134 ("SUNRPC: Provide functions for managing universal addresses") +Signed-off-by: Christophe JAILLET +Reviewed-by: Benjamin Coddington +Signed-off-by: Trond Myklebust +Acked-by: NeilBrown + +--- + net/sunrpc/addr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/sunrpc/addr.c ++++ b/net/sunrpc/addr.c +@@ -283,10 +283,10 @@ char *rpc_sockaddr2uaddr(const struct so + } + + if (snprintf(portbuf, sizeof(portbuf), +- ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf)) ++ ".%u.%u", port >> 8, port & 0xff) >= (int)sizeof(portbuf)) + return NULL; + +- if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf)) ++ if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) >= sizeof(addrbuf)) + return NULL; + + return kstrdup(addrbuf, gfp_flags); diff --git a/patches.suse/nfs-only-issue-commit-in-DIO-codepath-if-we-have-unc.patch b/patches.suse/nfs-only-issue-commit-in-DIO-codepath-if-we-have-unc.patch new file mode 100644 index 0000000..e993b82 --- /dev/null +++ b/patches.suse/nfs-only-issue-commit-in-DIO-codepath-if-we-have-unc.patch @@ -0,0 +1,107 @@ +From: Jeff Layton +Date: Fri, 22 Jul 2022 14:12:20 -0400 +Subject: [PATCH] nfs: only issue commit in DIO codepath if we have uncommitted + data +Git-commit: 69d966510d9f5de81588b37d23a9ee8ccc477b23 +Patch-mainline: v6.0 +References: git-fixes + +Currently, we try to determine whether to issue a commit based on +nfs_write_need_commit which looks at the current verifier. In the case +where we got a short write and then tried to follow it up with one that +failed, the verifier can't be trusted. + +What we really want to know is whether the pgio request had any +successful writes that came back as UNSTABLE. Add a new flag to the pgio +request, and use that to indicate that we've had a successful unstable +write. Only issue a commit if that flag is set. + +Signed-off-by: Jeff Layton +Signed-off-by: Trond Myklebust +Acked-by: NeilBrown + +--- + fs/nfs/direct.c | 2 +- + fs/nfs/write.c | 48 ++++++++++++++++++++++++++++++------------------ + include/linux/nfs_xdr.h | 1 + + 3 files changed, 32 insertions(+), 19 deletions(-) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -737,7 +737,7 @@ static void nfs_direct_write_completion( + } + + nfs_direct_count_bytes(dreq, hdr); +- if (hdr->good_bytes != 0 && nfs_write_need_commit(hdr)) { ++ if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags)) { + switch (dreq->flags) { + case 0: + dreq->flags = NFS_ODIRECT_DO_COMMIT; +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -1582,25 +1582,37 @@ static int nfs_writeback_done(struct rpc + return status; + nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, hdr->res.count); + +- if (hdr->res.verf->committed < hdr->args.stable && +- task->tk_status >= 0) { +- /* We tried a write call, but the server did not +- * commit data to stable storage even though we +- * requested it. +- * Note: There is a known bug in Tru64 < 5.0 in which +- * the server reports NFS_DATA_SYNC, but performs +- * NFS_FILE_SYNC. We therefore implement this checking +- * as a dprintk() in order to avoid filling syslog. +- */ +- static unsigned long complain; ++ if (task->tk_status >= 0) { ++ enum nfs3_stable_how committed = hdr->res.verf->committed; + +- /* Note this will print the MDS for a DS write */ +- if (time_before(complain, jiffies)) { +- dprintk("NFS: faulty NFS server %s:" +- " (committed = %d) != (stable = %d)\n", +- NFS_SERVER(inode)->nfs_client->cl_hostname, +- hdr->res.verf->committed, hdr->args.stable); +- complain = jiffies + 300 * HZ; ++ if (committed == NFS_UNSTABLE) { ++ /* ++ * We have some uncommitted data on the server at ++ * this point, so ensure that we keep track of that ++ * fact irrespective of what later writes do. ++ */ ++ set_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags); ++ } ++ ++ if (committed < hdr->args.stable) { ++ /* We tried a write call, but the server did not ++ * commit data to stable storage even though we ++ * requested it. ++ * Note: There is a known bug in Tru64 < 5.0 in which ++ * the server reports NFS_DATA_SYNC, but performs ++ * NFS_FILE_SYNC. We therefore implement this checking ++ * as a dprintk() in order to avoid filling syslog. ++ */ ++ static unsigned long complain; ++ ++ /* Note this will print the MDS for a DS write */ ++ if (time_before(complain, jiffies)) { ++ dprintk("NFS: faulty NFS server %s:" ++ " (committed = %d) != (stable = %d)\n", ++ NFS_SERVER(inode)->nfs_client->cl_hostname, ++ committed, hdr->args.stable); ++ complain = jiffies + 300 * HZ; ++ } + } + } + +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -1422,6 +1422,7 @@ enum { + NFS_IOHDR_EOF, + NFS_IOHDR_REDO, + NFS_IOHDR_STAT, ++ NFS_IOHDR_UNSTABLE_WRITES, + }; + + struct nfs_io_completion; diff --git a/patches.suse/pNFS-Fix-the-pnfs-block-driver-s-calculation-of-layo.patch b/patches.suse/pNFS-Fix-the-pnfs-block-driver-s-calculation-of-layo.patch new file mode 100644 index 0000000..4f869ed --- /dev/null +++ b/patches.suse/pNFS-Fix-the-pnfs-block-driver-s-calculation-of-layo.patch @@ -0,0 +1,81 @@ +From: Trond Myklebust +Date: Fri, 17 Nov 2023 06:25:13 -0500 +Subject: [PATCH] pNFS: Fix the pnfs block driver's calculation of layoutget + size +Git-commit: 8a6291bf3b0eae1bf26621e6419a91682f2d6227 +Patch-mainline: v6.8 +References: git-fixes + +Instead of relying on the value of the 'bytes_left' field, we should +calculate the layout size based on the offset of the request that is +being written out. + +Reported-by: Benjamin Coddington +Signed-off-by: Trond Myklebust +Fixes: 954998b60caa ("NFS: Fix error handling for O_DIRECT write scheduling") +Reviewed-by: Benjamin Coddington +Tested-by: Benjamin Coddington +Reviewed-by: Christoph Hellwig +Signed-off-by: Anna Schumaker +Acked-by: NeilBrown + +--- + fs/nfs/blocklayout/blocklayout.c | 5 ++--- + fs/nfs/direct.c | 5 +++-- + fs/nfs/internal.h | 2 +- + fs/nfs/pnfs.c | 3 ++- + 4 files changed, 8 insertions(+), 7 deletions(-) + +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -847,10 +847,9 @@ bl_pg_init_write(struct nfs_pageio_descr + } + + if (pgio->pg_dreq == NULL) +- wb_size = pnfs_num_cont_bytes(pgio->pg_inode, +- req->wb_index); ++ wb_size = pnfs_num_cont_bytes(pgio->pg_inode, req->wb_index); + else +- wb_size = nfs_dreq_bytes_left(pgio->pg_dreq); ++ wb_size = nfs_dreq_bytes_left(pgio->pg_dreq, req_offset(req)); + + pnfs_generic_pg_init_write(pgio, req, wb_size); + } +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -267,9 +267,10 @@ static void nfs_direct_req_release(struc + kref_put(&dreq->kref, nfs_direct_req_free); + } + +-ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq) ++ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq, loff_t offset) + { +- return dreq->bytes_left; ++ loff_t start = offset - dreq->io_start; ++ return dreq->max_count - start; + } + EXPORT_SYMBOL_GPL(nfs_dreq_bytes_left); + +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -577,7 +577,7 @@ extern int nfs_sillyrename(struct inode + /* direct.c */ + void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, + struct nfs_direct_req *dreq); +-extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); ++extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq, loff_t offset); + + /* nfs4proc.c */ + extern struct nfs_client *nfs4_init_client(struct nfs_client *clp, +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -2173,7 +2173,8 @@ pnfs_generic_pg_init_read(struct nfs_pag + if (pgio->pg_dreq == NULL) + rd_size = i_size_read(pgio->pg_inode) - req_offset(req); + else +- rd_size = nfs_dreq_bytes_left(pgio->pg_dreq); ++ rd_size = nfs_dreq_bytes_left(pgio->pg_dreq, ++ req_offset(req)); + + pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, + req->wb_context, diff --git a/series.conf b/series.conf index 6aa7b44..5579939 100644 --- a/series.conf +++ b/series.conf @@ -56541,6 +56541,9 @@ patches.suse/net-dsa-bcm_sf2-Ensure-correct-sub-node-is-parsed.patch patches.suse/NFSv4-pnfs-Return-valid-stateids-in-nfs_layout_find_.patch patches.suse/NFS-direct.c-Fix-memory-leak-of-dreq-when-nfs_get_lo.patch + patches.suse/NFS-commit-errors-should-be-fatal.patch + patches.suse/NFS-Fix-O_DIRECT-commit-verifier-handling.patch + patches.suse/NFS-Fix-a-request-reference-leak-in-nfs_direct_write.patch patches.suse/NFS-Fix-memory-leaks-in-nfs_pageio_stop_mirroring.patch patches.suse/0001-mm-memory_hotplug.c-only-respect-mem-parameter-durin.patch patches.suse/include-linux-swapops-h-correct-guards-for-non_swap_entry.patch @@ -57443,6 +57446,7 @@ patches.suse/nfsd-Fix-svc_xprt-refcnt-leak-when-setup-callback-cl.patch patches.suse/crypto-cavium-nitrox-Fix-nitrox_get_first_device-whe.patch patches.suse/net-sunrpc-Fix-off-by-one-issues-in-rpc_ntop6.patch + patches.suse/NFS-Fix-direct-WRITE-throughput-regression.patch patches.suse/drm-sun4i-hdmi-ddc-clk-Fix-size-of-m-divider.patch patches.suse/ALSA-usb-audio-Fix-inconsistent-card-PM-state-after-.patch patches.suse/ALSA-usb-audio-Add-vendor-product-and-profile-name-f.patch @@ -63718,6 +63722,7 @@ patches.suse/fs-add-mode_strip_sgid-helper.patch patches.suse/fs-Add-missing-umask-strip-in-vfs_tmpfile.patch patches.suse/fs-move-S_ISGID-stripping-into-the-vfs_-helpers.patch + patches.suse/nfs-only-issue-commit-in-DIO-codepath-if-we-have-unc.patch patches.suse/NFSv4.1-RECLAIM_COMPLETE-must-handle-EACCES.patch patches.suse/SUNRPC-Reinitialise-the-backchannel-request-buffers-.patch patches.suse/Makefile-link-with-z-noexecstack-no-warn-rwx-segment.patch @@ -64832,6 +64837,9 @@ 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-Fix-O_DIRECT-locking-issues.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 @@ -64960,6 +64968,7 @@ patches.suse/ACPI-extlog-fix-NULL-pointer-dereference-check.patch patches.suse/pstore-ram_core-fix-possible-overflow-in-persistent_ram_init_ecc.patch patches.suse/NFSv4.1-pnfs-Ensure-we-handle-the-error-NFS4ERR_RETU.patch + patches.suse/pNFS-Fix-the-pnfs-block-driver-s-calculation-of-layo.patch patches.suse/KVM-s390-fix-setting-of-fpc-register.patch patches.suse/md-bypass-block-throttle-for-superblock-update-d6e0.patch patches.suse/Revert-md-raid5-Wait-for-MD_SB_CHANGE_PENDING-in-rai.patch @@ -65012,9 +65021,12 @@ patches.suse/Documentation-hw-vuln-Add-documentation-for-RFDS.patch patches.suse/x86-rfds-Mitigate-Register-File-Data-Sampling-RFDS.patch patches.suse/KVM-x86-Export-RFDS_NO-and-RFDS_CLEAR-to-guests.patch + patches.suse/SUNRPC-fix-a-memleak-in-gss_import_v2_context.patch patches.suse/SUNRPC-fix-some-memleaks-in-gssx_dec_option_array.patch patches.suse/NFSD-Reset-cb_seq_status-after-NFS4ERR_DELAY.patch patches.suse/NFSD-Retransmit-callbacks-after-client-reconnects.patch + patches.suse/net-sunrpc-Fix-an-off-by-one-in-rpc_sockaddr2uaddr.patch + patches.suse/NFS-Fix-an-off-by-one-in-root_nfs_cat.patch # dhowells/linux-fs keys-uefi patches.suse/0001-KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch @@ -66101,6 +66113,7 @@ patches.kabi/preserve-KABI-for-struct-sfp_socket_ops.patch patches.kabi/kabi-restore-return-type-of-dst_ops-gc-callback.patch patches.kabi/team-Hide-new-member-header-ops.patch + patches.kabi/pNFS-Fix-the-pnfs-block-driver-s-calculation-of-layo.patch ######################################################## # You'd better have a good reason for adding a patch