mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
nfs: keep PG_UPTODATE clear after read errors in page groups
When a read request is split into multiple subrequests, earlier
completions may advance PG_UPTODATE state for the page group once
their bytes fall within hdr->good_bytes. If a later subrequest in
the same group then completes with NFS_IOHDR_ERROR, the read path
needs to clear any accumulated PG_UPTODATE state and keep later
completions from rebuilding it.
Otherwise, a subsequent successful subrequest can re-enter
nfs_page_group_set_uptodate(), restore the page-group sync state,
and leave stale PG_UPTODATE behind for nfs_page_group_destroy()
to trip over in nfs_free_request().
Add a sticky page-group read-failed flag. Once any subrequest in
the group is known to be bad, mark the group failed, clear any
accumulated PG_UPTODATE state, and refuse further PG_UPTODATE
synchronization for the rest of the completion walk.
Fixes: 67d0338edd ("nfs: page group syncing in read path")
Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
This commit is contained in:
committed by
Anna Schumaker
parent
77b160b2d8
commit
3ff72e1cdf
@@ -132,10 +132,32 @@ static void nfs_readpage_release(struct nfs_page *req, int error)
|
||||
|
||||
static void nfs_page_group_set_uptodate(struct nfs_page *req)
|
||||
{
|
||||
if (nfs_page_group_sync_on_bit(req, PG_UPTODATE))
|
||||
bool uptodate = false;
|
||||
|
||||
nfs_page_group_lock(req);
|
||||
if (!test_bit(PG_READ_FAILED, &req->wb_head->wb_flags) &&
|
||||
nfs_page_group_sync_on_bit_locked(req, PG_UPTODATE))
|
||||
uptodate = true;
|
||||
nfs_page_group_unlock(req);
|
||||
|
||||
if (uptodate)
|
||||
folio_mark_uptodate(nfs_page_to_folio(req));
|
||||
}
|
||||
|
||||
static void nfs_page_group_mark_read_failed(struct nfs_page *req)
|
||||
{
|
||||
struct nfs_page *tmp;
|
||||
|
||||
nfs_page_group_lock(req);
|
||||
set_bit(PG_READ_FAILED, &req->wb_head->wb_flags);
|
||||
tmp = req;
|
||||
do {
|
||||
clear_bit(PG_UPTODATE, &tmp->wb_flags);
|
||||
tmp = tmp->wb_this_page;
|
||||
} while (tmp != req);
|
||||
nfs_page_group_unlock(req);
|
||||
}
|
||||
|
||||
static void nfs_read_completion(struct nfs_pgio_header *hdr)
|
||||
{
|
||||
unsigned long bytes = 0;
|
||||
@@ -172,6 +194,7 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr)
|
||||
if (bytes <= hdr->good_bytes)
|
||||
nfs_page_group_set_uptodate(req);
|
||||
else {
|
||||
nfs_page_group_mark_read_failed(req);
|
||||
error = hdr->error;
|
||||
xchg(&nfs_req_openctx(req)->error, error);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ enum {
|
||||
PG_TEARDOWN, /* page group sync for destroy */
|
||||
PG_UNLOCKPAGE, /* page group sync bit in read path */
|
||||
PG_UPTODATE, /* page group sync bit in read path */
|
||||
PG_READ_FAILED, /* page group saw a read error */
|
||||
PG_WB_END, /* page group sync bit in write path */
|
||||
PG_REMOVE, /* page group sync bit in write path */
|
||||
PG_CONTENDED1, /* Is someone waiting for a lock? */
|
||||
|
||||
Reference in New Issue
Block a user