Commit 2c61be0a authored by Trond Myklebust's avatar Trond Myklebust

NFS: Ensure that the WRITE and COMMIT RPC calls are always uninterruptible

We always want to ensure that WRITE and COMMIT completes, whether or not
the user presses ^C. Do this by making the call asynchronous, and allowing
the user to do an interruptible wait for rpc_task completion.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent a6305ddb
...@@ -781,7 +781,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req, ...@@ -781,7 +781,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
int how) int how)
{ {
struct inode *inode = req->wb_context->path.dentry->d_inode; struct inode *inode = req->wb_context->path.dentry->d_inode;
int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
int priority = flush_task_priority(how); int priority = flush_task_priority(how);
struct rpc_task *task; struct rpc_task *task;
struct rpc_message msg = { struct rpc_message msg = {
...@@ -796,9 +795,10 @@ static int nfs_write_rpcsetup(struct nfs_page *req, ...@@ -796,9 +795,10 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
.callback_ops = call_ops, .callback_ops = call_ops,
.callback_data = data, .callback_data = data,
.workqueue = nfsiod_workqueue, .workqueue = nfsiod_workqueue,
.flags = flags, .flags = RPC_TASK_ASYNC,
.priority = priority, .priority = priority,
}; };
int ret = 0;
/* Set up the RPC argument and reply structs /* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */ * NB: take care not to mess about with data->commit et al. */
...@@ -837,10 +837,18 @@ static int nfs_write_rpcsetup(struct nfs_page *req, ...@@ -837,10 +837,18 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
(unsigned long long)data->args.offset); (unsigned long long)data->args.offset);
task = rpc_run_task(&task_setup_data); task = rpc_run_task(&task_setup_data);
if (IS_ERR(task)) if (IS_ERR(task)) {
return PTR_ERR(task); ret = PTR_ERR(task);
goto out;
}
if (how & FLUSH_SYNC) {
ret = rpc_wait_for_completion_task(task);
if (ret == 0)
ret = task->tk_status;
}
rpc_put_task(task); rpc_put_task(task);
return 0; out:
return ret;
} }
/* If a nfs_flush_* function fails, it should remove reqs from @head and /* If a nfs_flush_* function fails, it should remove reqs from @head and
...@@ -1210,7 +1218,6 @@ static int nfs_commit_rpcsetup(struct list_head *head, ...@@ -1210,7 +1218,6 @@ static int nfs_commit_rpcsetup(struct list_head *head,
{ {
struct nfs_page *first = nfs_list_entry(head->next); struct nfs_page *first = nfs_list_entry(head->next);
struct inode *inode = first->wb_context->path.dentry->d_inode; struct inode *inode = first->wb_context->path.dentry->d_inode;
int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
int priority = flush_task_priority(how); int priority = flush_task_priority(how);
struct rpc_task *task; struct rpc_task *task;
struct rpc_message msg = { struct rpc_message msg = {
...@@ -1225,7 +1232,7 @@ static int nfs_commit_rpcsetup(struct list_head *head, ...@@ -1225,7 +1232,7 @@ static int nfs_commit_rpcsetup(struct list_head *head,
.callback_ops = &nfs_commit_ops, .callback_ops = &nfs_commit_ops,
.callback_data = data, .callback_data = data,
.workqueue = nfsiod_workqueue, .workqueue = nfsiod_workqueue,
.flags = flags, .flags = RPC_TASK_ASYNC,
.priority = priority, .priority = priority,
}; };
...@@ -1255,6 +1262,8 @@ static int nfs_commit_rpcsetup(struct list_head *head, ...@@ -1255,6 +1262,8 @@ static int nfs_commit_rpcsetup(struct list_head *head,
task = rpc_run_task(&task_setup_data); task = rpc_run_task(&task_setup_data);
if (IS_ERR(task)) if (IS_ERR(task))
return PTR_ERR(task); return PTR_ERR(task);
if (how & FLUSH_SYNC)
rpc_wait_for_completion_task(task);
rpc_put_task(task); rpc_put_task(task);
return 0; return 0;
} }
......
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