NFSv4: Fix an Oops in pnfs_mark_request_commit() when doing O_DIRECT
[ Upstream commit 3731d44bba8e0116b052b1b374476c5f6dd9a456 ]
Fix an Oopsable condition in pnfs_mark_request_commit() when we're
putting a set of writes on the commit list to reschedule them after a
failed pNFS attempt.
Fixes: 9c455a8c1e
("NFS/pNFS: Clean up pNFS commit operations")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
ff4023d019
commit
5c7ef8a370
@@ -700,8 +700,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
|||||||
{
|
{
|
||||||
struct nfs_direct_req *dreq = hdr->dreq;
|
struct nfs_direct_req *dreq = hdr->dreq;
|
||||||
struct nfs_commit_info cinfo;
|
struct nfs_commit_info cinfo;
|
||||||
bool request_commit = false;
|
|
||||||
struct nfs_page *req = nfs_list_entry(hdr->pages.next);
|
struct nfs_page *req = nfs_list_entry(hdr->pages.next);
|
||||||
|
int flags = NFS_ODIRECT_DONE;
|
||||||
|
|
||||||
nfs_init_cinfo_from_dreq(&cinfo, dreq);
|
nfs_init_cinfo_from_dreq(&cinfo, dreq);
|
||||||
|
|
||||||
@@ -713,15 +713,9 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
|||||||
|
|
||||||
nfs_direct_count_bytes(dreq, hdr);
|
nfs_direct_count_bytes(dreq, hdr);
|
||||||
if (hdr->good_bytes != 0 && nfs_write_need_commit(hdr)) {
|
if (hdr->good_bytes != 0 && nfs_write_need_commit(hdr)) {
|
||||||
switch (dreq->flags) {
|
if (!dreq->flags)
|
||||||
case 0:
|
|
||||||
dreq->flags = NFS_ODIRECT_DO_COMMIT;
|
dreq->flags = NFS_ODIRECT_DO_COMMIT;
|
||||||
request_commit = true;
|
flags = dreq->flags;
|
||||||
break;
|
|
||||||
case NFS_ODIRECT_RESCHED_WRITES:
|
|
||||||
case NFS_ODIRECT_DO_COMMIT:
|
|
||||||
request_commit = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
spin_unlock(&dreq->lock);
|
spin_unlock(&dreq->lock);
|
||||||
|
|
||||||
@@ -729,12 +723,15 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
|||||||
|
|
||||||
req = nfs_list_entry(hdr->pages.next);
|
req = nfs_list_entry(hdr->pages.next);
|
||||||
nfs_list_remove_request(req);
|
nfs_list_remove_request(req);
|
||||||
if (request_commit) {
|
if (flags == NFS_ODIRECT_DO_COMMIT) {
|
||||||
kref_get(&req->wb_kref);
|
kref_get(&req->wb_kref);
|
||||||
memcpy(&req->wb_verf, &hdr->verf.verifier,
|
memcpy(&req->wb_verf, &hdr->verf.verifier,
|
||||||
sizeof(req->wb_verf));
|
sizeof(req->wb_verf));
|
||||||
nfs_mark_request_commit(req, hdr->lseg, &cinfo,
|
nfs_mark_request_commit(req, hdr->lseg, &cinfo,
|
||||||
hdr->ds_commit_idx);
|
hdr->ds_commit_idx);
|
||||||
|
} else if (flags == NFS_ODIRECT_RESCHED_WRITES) {
|
||||||
|
kref_get(&req->wb_kref);
|
||||||
|
nfs_mark_request_commit(req, NULL, &cinfo, 0);
|
||||||
}
|
}
|
||||||
nfs_unlock_and_release_request(req);
|
nfs_unlock_and_release_request(req);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user