I'm announcing the release of the 6.1.58 kernel.
All users of the 6.1 kernel series must upgrade.
The updated 6.1.y git tree can be found at: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-6.1.y and can be browsed at the normal kernel.org git web browser: https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git%3Ba=summa...
thanks,
greg k-h
------------
Makefile | 2 fs/nfs/direct.c | 134 ++++++++++++++--------------------------------- fs/nfs/write.c | 23 +++----- include/linux/nfs_page.h | 4 - lib/test_meminit.c | 2 5 files changed, 55 insertions(+), 110 deletions(-)
Greg Kroah-Hartman (7): Revert "NFS: More fixes for nfs_direct_write_reschedule_io()" Revert "NFS: Use the correct commit info in nfs_join_page_group()" Revert "NFS: More O_DIRECT accounting fixes for error paths" Revert "NFS: Fix O_DIRECT locking issues" Revert "NFS: Fix error handling for O_DIRECT write scheduling" lib/test_meminit: fix off-by-one error in test_pages() Linux 6.1.58
diff --git a/Makefile b/Makefile index b435b56594f0..ce1eec0b5010 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 1 -SUBLEVEL = 57 +SUBLEVEL = 58 EXTRAVERSION = NAME = Curry Ramen
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 5a976fa343df..3bb530d4bb5c 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -93,10 +93,12 @@ nfs_direct_handle_truncated(struct nfs_direct_req *dreq, dreq->max_count = dreq_len; if (dreq->count > dreq_len) dreq->count = dreq_len; - }
- if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && !dreq->error) - dreq->error = hdr->error; + if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) + dreq->error = hdr->error; + else /* Clear outstanding error if this is EOF */ + dreq->error = 0; + } }
static void @@ -118,18 +120,6 @@ nfs_direct_count_bytes(struct nfs_direct_req *dreq, 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_swap_rw - NFS address space operation for swap I/O * @iocb: target I/O control block @@ -500,9 +490,7 @@ static void nfs_direct_add_page_head(struct list_head *list, kref_get(&head->wb_kref); }
-static void nfs_direct_join_group(struct list_head *list, - struct nfs_commit_info *cinfo, - struct inode *inode) +static void nfs_direct_join_group(struct list_head *list, struct inode *inode) { struct nfs_page *req, *subreq;
@@ -524,7 +512,7 @@ static void nfs_direct_join_group(struct list_head *list, nfs_release_request(subreq); } } while ((subreq = subreq->wb_this_page) != req); - nfs_join_page_group(req, cinfo, inode); + nfs_join_page_group(req, inode); } }
@@ -542,15 +530,20 @@ nfs_direct_write_scan_commit_list(struct inode *inode, static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) { struct nfs_pageio_descriptor desc; - struct nfs_page *req; + struct nfs_page *req, *tmp; LIST_HEAD(reqs); struct nfs_commit_info cinfo; + LIST_HEAD(failed);
nfs_init_cinfo_from_dreq(&cinfo, dreq); nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo);
- nfs_direct_join_group(&reqs, &cinfo, dreq->inode); + nfs_direct_join_group(&reqs, dreq->inode);
+ 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); get_dreq(dreq);
@@ -558,40 +551,27 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) &nfs_direct_write_completion_ops); desc.pg_dreq = dreq;
- while (!list_empty(&reqs)) { - req = nfs_list_entry(reqs.next); + list_for_each_entry_safe(req, tmp, &reqs, wb_list) { /* Bump the transmission count */ req->wb_nio++; if (!nfs_pageio_add_request(&desc, req)) { - spin_lock(&dreq->lock); - 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; + nfs_list_move_request(req, &failed); + spin_lock(&cinfo.inode->i_lock); + dreq->flags = 0; + if (desc.pg_error < 0) dreq->error = desc.pg_error; - } else - dreq->flags = NFS_ODIRECT_RESCHED_WRITES; - spin_unlock(&dreq->lock); - break; + else + dreq->error = -EIO; + spin_unlock(&cinfo.inode->i_lock); } nfs_release_request(req); } nfs_pageio_complete(&desc);
- while (!list_empty(&reqs)) { - req = nfs_list_entry(reqs.next); + while (!list_empty(&failed)) { + req = nfs_list_entry(failed.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 { - spin_lock(&dreq->lock); - nfs_direct_truncate_request(dreq, req); - spin_unlock(&dreq->lock); - nfs_release_request(req); - } }
if (put_dreq(dreq)) @@ -611,6 +591,8 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) if (status < 0) { /* Errors in commit are fatal */ dreq->error = status; + dreq->max_count = 0; + dreq->count = 0; dreq->flags = NFS_ODIRECT_DONE; } else { status = dreq->error; @@ -621,12 +603,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); nfs_list_remove_request(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)) { + if (status >= 0 && !nfs_write_match_verf(verf, req)) { dreq->flags = NFS_ODIRECT_RESCHED_WRITES; /* * Despite the reboot, the write was successful, @@ -634,7 +611,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) */ req->wb_nio = 0; nfs_mark_request_commit(req, NULL, &cinfo, 0); - } else + } else /* Error or match */ nfs_release_request(req); nfs_unlock_and_release_request(req); } @@ -687,7 +664,6 @@ static void nfs_direct_write_clear_reqs(struct nfs_direct_req *dreq) 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,8 +713,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) }
nfs_direct_count_bytes(dreq, hdr); - if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags) && - !test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { + if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags)) { if (!dreq->flags) dreq->flags = NFS_ODIRECT_DO_COMMIT; flags = dreq->flags; @@ -782,23 +757,18 @@ static void nfs_write_sync_pgio_error(struct list_head *head, int error) static void nfs_direct_write_reschedule_io(struct nfs_pgio_header *hdr) { struct nfs_direct_req *dreq = hdr->dreq; - struct nfs_page *req; - struct nfs_commit_info cinfo;
trace_nfs_direct_write_reschedule_io(dreq);
- nfs_init_cinfo_from_dreq(&cinfo, dreq); spin_lock(&dreq->lock); - if (dreq->error == 0) + if (dreq->error == 0) { dreq->flags = NFS_ODIRECT_RESCHED_WRITES; - set_bit(NFS_IOHDR_REDO, &hdr->flags); - spin_unlock(&dreq->lock); - while (!list_empty(&hdr->pages)) { - req = nfs_list_entry(hdr->pages.next); - nfs_list_remove_request(req); - nfs_unlock_request(req); - nfs_mark_request_commit(req, NULL, &cinfo, 0); + /* fake unstable write to let common nfs resend pages */ + hdr->verf.committed = NFS_UNSTABLE; + hdr->good_bytes = hdr->args.offset + hdr->args.count - + hdr->io_start; } + spin_unlock(&dreq->lock); }
static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = { @@ -826,11 +796,9 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, { 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;
trace_nfs_direct_write_schedule_iovec(dreq);
@@ -871,39 +839,19 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, 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)) - continue; - - /* Exit on hard errors */ - if (desc.pg_error < 0 && desc.pg_error != -EAGAIN) { + if (!nfs_pageio_add_request(&desc, req)) { result = desc.pg_error; nfs_unlock_and_release_request(req); break; } - - /* If the error is soft, defer remaining requests */ - nfs_init_cinfo_from_dreq(&cinfo, dreq); - spin_lock(&dreq->lock); - dreq->flags = NFS_ODIRECT_RESCHED_WRITES; - spin_unlock(&dreq->lock); - nfs_unlock_request(req); - nfs_mark_request_commit(req, NULL, &cinfo, 0); - desc.pg_error = 0; - defer = true; + pgbase = 0; + bytes -= req_len; + requested_bytes += req_len; + pos += req_len; + dreq->bytes_left -= req_len; } nfs_direct_release_pages(pagevec, npages); kvfree(pagevec); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0a8aed0ac994..f41d24b54fd1 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -58,8 +58,7 @@ static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops; static const struct nfs_commit_completion_ops nfs_commit_completion_ops; static const struct nfs_rw_ops nfs_rw_write_ops; static void nfs_inode_remove_request(struct nfs_page *req); -static void nfs_clear_request_commit(struct nfs_commit_info *cinfo, - struct nfs_page *req); +static void nfs_clear_request_commit(struct nfs_page *req); static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo, struct inode *inode); static struct nfs_page * @@ -503,8 +502,8 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list, * the (former) group. All subrequests are removed from any write or commit * lists, unlinked from the group and destroyed. */ -void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo, - struct inode *inode) +void +nfs_join_page_group(struct nfs_page *head, struct inode *inode) { struct nfs_page *subreq; struct nfs_page *destroy_list = NULL; @@ -534,7 +533,7 @@ void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo, * Commit list removal accounting is done after locks are dropped */ subreq = head; do { - nfs_clear_request_commit(cinfo, subreq); + nfs_clear_request_commit(subreq); subreq = subreq->wb_this_page; } while (subreq != head);
@@ -568,10 +567,8 @@ nfs_lock_and_join_requests(struct page *page) { struct inode *inode = page_file_mapping(page)->host; struct nfs_page *head; - struct nfs_commit_info cinfo; int ret;
- nfs_init_cinfo_from_inode(&cinfo, inode); /* * A reference is taken only on the head request which acts as a * reference to the whole page group - the group will not be destroyed @@ -588,7 +585,7 @@ nfs_lock_and_join_requests(struct page *page) return ERR_PTR(ret); }
- nfs_join_page_group(head, &cinfo, inode); + nfs_join_page_group(head, inode);
return head; } @@ -959,16 +956,18 @@ nfs_clear_page_commit(struct page *page) }
/* Called holding the request lock on @req */ -static void nfs_clear_request_commit(struct nfs_commit_info *cinfo, - struct nfs_page *req) +static void +nfs_clear_request_commit(struct nfs_page *req) { if (test_bit(PG_CLEAN, &req->wb_flags)) { struct nfs_open_context *ctx = nfs_req_openctx(req); struct inode *inode = d_inode(ctx->dentry); + struct nfs_commit_info cinfo;
+ nfs_init_cinfo_from_inode(&cinfo, inode); mutex_lock(&NFS_I(inode)->commit_mutex); - if (!pnfs_clear_request_commit(req, cinfo)) { - nfs_request_remove_commit_list(req, cinfo); + if (!pnfs_clear_request_commit(req, &cinfo)) { + nfs_request_remove_commit_list(req, &cinfo); } mutex_unlock(&NFS_I(inode)->commit_mutex); nfs_clear_page_commit(req->wb_page); diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index e39a8cf8b179..ba7e2e4b0926 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -145,9 +145,7 @@ extern void nfs_unlock_request(struct nfs_page *req); extern void nfs_unlock_and_release_request(struct nfs_page *); extern struct nfs_page *nfs_page_group_lock_head(struct nfs_page *req); extern int nfs_page_group_lock_subrequests(struct nfs_page *head); -extern void nfs_join_page_group(struct nfs_page *head, - struct nfs_commit_info *cinfo, - struct inode *inode); +extern void nfs_join_page_group(struct nfs_page *head, struct inode *inode); extern int nfs_page_group_lock(struct nfs_page *); extern void nfs_page_group_unlock(struct nfs_page *); extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); diff --git a/lib/test_meminit.c b/lib/test_meminit.c index 0ae35223d773..85d8dd8e01dc 100644 --- a/lib/test_meminit.c +++ b/lib/test_meminit.c @@ -93,7 +93,7 @@ static int __init test_pages(int *total_failures) int failures = 0, num_tests = 0; int i;
- for (i = 0; i <= MAX_ORDER; i++) + for (i = 0; i < MAX_ORDER; i++) num_tests += do_alloc_pages_order(i, &failures);
REPORT_FAILURES_IN_FN();
On Mon, 16 Oct 2023, Greg Kroah-Hartman wrote:
I'm announcing the release of the 6.1.58 kernel.
All users of the 6.1 kernel series must upgrade.
The updated 6.1.y git tree can be found at: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-6.1.y and can be browsed at the normal kernel.org git web browser: https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git%3Ba=summa...
thanks,
greg k-h
Makefile | 2 fs/nfs/direct.c | 134 ++++++++++++++--------------------------------- fs/nfs/write.c | 23 +++----- include/linux/nfs_page.h | 4 - lib/test_meminit.c | 2 5 files changed, 55 insertions(+), 110 deletions(-)
Greg Kroah-Hartman (7): Revert "NFS: More fixes for nfs_direct_write_reschedule_io()" Revert "NFS: Use the correct commit info in nfs_join_page_group()" Revert "NFS: More O_DIRECT accounting fixes for error paths" Revert "NFS: Fix O_DIRECT locking issues" Revert "NFS: Fix error handling for O_DIRECT write scheduling"
FYI the problem with these NFS patch is now described in comment #4 of https://bugzilla.kernel.org/show_bug.cgi?id=217999 which I include below. They can be reapplied if the "Fix error handling..." patch is fixed up as described.
NeilBrown
FYI the cause of this corruption is that the backport of NFS: Fix error handling for O_DIRECT write scheduling
had an error. The backported patch f16fd0b11f0f4d41846b5102b1656ea1fc9ac7a0 moves "pos += req_len" in nfs_direct_write_schedule_iovec() from after req->wb_index = pos >> PAGE_SHIFT; to before that statement. This ->wb_index is wrong. Possibly a better way to look at this is the use of "pos" is moved to *after* it is updated.
The upstream patch 954998b60caa8f2a3bf3abe490de6f08d283687a doesn't move the use of pos because Commit 70e9db69f927 ("NFS: Clean up O_DIRECT request allocation")
removes the use.
v6.1.56 can be fixed with
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 5a976fa343df..69134e11e7d0 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -864,6 +864,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, result = PTR_ERR(req); break; } + req->wb_index = pos >> PAGE_SHIFT; + req->wb_offset = pos & ~PAGE_MASK;
if (desc.pg_error < 0) { nfs_free_request(req); @@ -883,8 +885,6 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, }
nfs_lock_request(req); - req->wb_index = pos >> PAGE_SHIFT; - req->wb_offset = pos & ~PAGE_MASK; if (nfs_pageio_add_request(&desc, req)) continue;
On Fri, Oct 20, 2023 at 06:22:47PM +1100, NeilBrown wrote:
On Mon, 16 Oct 2023, Greg Kroah-Hartman wrote:
I'm announcing the release of the 6.1.58 kernel.
All users of the 6.1 kernel series must upgrade.
The updated 6.1.y git tree can be found at: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-6.1.y and can be browsed at the normal kernel.org git web browser: https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git%3Ba=summa...
thanks,
greg k-h
Makefile | 2 fs/nfs/direct.c | 134 ++++++++++++++--------------------------------- fs/nfs/write.c | 23 +++----- include/linux/nfs_page.h | 4 - lib/test_meminit.c | 2 5 files changed, 55 insertions(+), 110 deletions(-)
Greg Kroah-Hartman (7): Revert "NFS: More fixes for nfs_direct_write_reschedule_io()" Revert "NFS: Use the correct commit info in nfs_join_page_group()" Revert "NFS: More O_DIRECT accounting fixes for error paths" Revert "NFS: Fix O_DIRECT locking issues" Revert "NFS: Fix error handling for O_DIRECT write scheduling"
FYI the problem with these NFS patch is now described in comment #4 of https://bugzilla.kernel.org/show_bug.cgi?id=217999 which I include below. They can be reapplied if the "Fix error handling..." patch is fixed up as described.
NeilBrown
FYI the cause of this corruption is that the backport of NFS: Fix error handling for O_DIRECT write scheduling
had an error. The backported patch f16fd0b11f0f4d41846b5102b1656ea1fc9ac7a0 moves "pos += req_len" in nfs_direct_write_schedule_iovec() from after req->wb_index = pos >> PAGE_SHIFT; to before that statement. This ->wb_index is wrong. Possibly a better way to look at this is the use of "pos" is moved to *after* it is updated.
The upstream patch 954998b60caa8f2a3bf3abe490de6f08d283687a doesn't move the use of pos because Commit 70e9db69f927 ("NFS: Clean up O_DIRECT request allocation")
removes the use.
v6.1.56 can be fixed with
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 5a976fa343df..69134e11e7d0 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -864,6 +864,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, result = PTR_ERR(req); break; }
req->wb_index = pos >> PAGE_SHIFT;
req->wb_offset = pos & ~PAGE_MASK;
if (desc.pg_error < 0) { nfs_free_request(req); @@ -883,8 +885,6 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, } nfs_lock_request(req);
req->wb_index = pos >> PAGE_SHIFT;
req->wb_offset = pos & ~PAGE_MASK; if (nfs_pageio_add_request(&desc, req)) continue;
Nice, thanks for digging into this. I think I'll leave this be for now, until someone submits a fully backported, and tested, series that they are willing to say actually works :)
thanks,
greg k-h
linux-stable-mirror@lists.linaro.org