Commit fb5f7f20 authored by Trond Myklebust's avatar Trond Myklebust

NFS: commit errors should be fatal

Fix the O_DIRECT code to avoid retries if the COMMIT fails with a fatal
error.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 18f41296
...@@ -94,6 +94,7 @@ struct nfs_direct_req { ...@@ -94,6 +94,7 @@ struct nfs_direct_req {
#define NFS_ODIRECT_RESCHED_WRITES (2) /* write verification failed */ #define NFS_ODIRECT_RESCHED_WRITES (2) /* write verification failed */
/* for read */ /* for read */
#define NFS_ODIRECT_SHOULD_DIRTY (3) /* dirty user-space page after 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 */ struct nfs_writeverf verf; /* unstable write verifier */
}; };
...@@ -678,8 +679,17 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) ...@@ -678,8 +679,17 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
struct nfs_page *req; struct nfs_page *req;
int status = data->task.tk_status; 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); 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; dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
while (!list_empty(&data->pages)) { while (!list_empty(&data->pages)) {
...@@ -708,7 +718,8 @@ static void nfs_direct_resched_write(struct nfs_commit_info *cinfo, ...@@ -708,7 +718,8 @@ static void nfs_direct_resched_write(struct nfs_commit_info *cinfo,
struct nfs_direct_req *dreq = cinfo->dreq; struct nfs_direct_req *dreq = cinfo->dreq;
spin_lock(&dreq->lock); 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); spin_unlock(&dreq->lock);
nfs_mark_request_commit(req, NULL, cinfo, 0); nfs_mark_request_commit(req, NULL, cinfo, 0);
} }
...@@ -731,6 +742,22 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) ...@@ -731,6 +742,22 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
nfs_direct_write_reschedule(dreq); 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) static void nfs_direct_write_schedule_work(struct work_struct *work)
{ {
struct nfs_direct_req *dreq = container_of(work, struct nfs_direct_req, work); struct nfs_direct_req *dreq = container_of(work, struct nfs_direct_req, work);
...@@ -745,6 +772,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) ...@@ -745,6 +772,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
nfs_direct_write_reschedule(dreq); nfs_direct_write_reschedule(dreq);
break; break;
default: default:
nfs_direct_write_clear_reqs(dreq);
nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping); nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping);
nfs_direct_complete(dreq); nfs_direct_complete(dreq);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment