#include "nfs4_fs.h"
#include "delegation.h"
-#include "iostat.h"
#define NFSDBG_FACILITY NFSDBG_PROC
if (!(data->f_attr.valid & NFS_ATTR_FATTR))
goto out;
inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);
- if (IS_ERR(inode))
+ if (inode == NULL)
goto out;
state = nfs4_get_open_state(inode, data->owner);
if (state == NULL)
int status;
atomic_inc(&data->count);
- /*
- * If rpc_run_task() ends up calling ->rpc_release(), we
- * want to ensure that it takes the 'error' code path.
- */
- data->rpc_status = -ENOMEM;
task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data);
- if (IS_ERR(task))
+ if (IS_ERR(task)) {
+ nfs4_opendata_free(data);
return PTR_ERR(task);
+ }
status = nfs4_wait_for_completion_rpc_task(task);
if (status != 0) {
data->cancelled = 1;
int status;
atomic_inc(&data->count);
- /*
- * If rpc_run_task() ends up calling ->rpc_release(), we
- * want to ensure that it takes the 'error' code path.
- */
- data->rpc_status = -ENOMEM;
task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data);
- if (IS_ERR(task))
+ if (IS_ERR(task)) {
+ nfs4_opendata_free(data);
return PTR_ERR(task);
+ }
status = nfs4_wait_for_completion_rpc_task(task);
if (status != 0) {
data->cancelled = 1;
static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred)
{
struct nfs4_exception exception = { };
- struct nfs4_state *res = ERR_PTR(-EIO);
+ struct nfs4_state *res;
int err;
do {
return res;
}
-static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
- struct iattr *sattr, struct nfs4_state *state)
+static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
+ struct nfs_fh *fhandle, struct iattr *sattr,
+ struct nfs4_state *state)
{
- struct nfs_server *server = NFS_SERVER(inode);
struct nfs_setattrargs arg = {
- .fh = NFS_FH(inode),
+ .fh = fhandle,
.iap = sattr,
.server = server,
.bitmask = server->attr_bitmask,
nfs_fattr_init(fattr);
- if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
- /* Use that stateid */
- } else if (state != NULL) {
+ if (state != NULL) {
msg.rpc_cred = state->owner->so_cred;
nfs4_copy_stateid(&arg.stateid, state, current->files);
} else
return status;
}
-static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
- struct iattr *sattr, struct nfs4_state *state)
+static int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
+ struct nfs_fh *fhandle, struct iattr *sattr,
+ struct nfs4_state *state)
{
- struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
- _nfs4_do_setattr(inode, fattr, sattr, state),
+ _nfs4_do_setattr(server, fattr, fhandle, sattr,
+ state),
&exception);
} while (exception.retry);
return err;
return status;
}
-static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state)
+static void nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state)
{
struct file *filp;
struct nfs_open_context *ctx;
ctx = (struct nfs_open_context *)filp->private_data;
ctx->state = state;
- return 0;
- }
- nfs4_close_state(state, nd->intent.open.flags);
- return PTR_ERR(filp);
+ } else
+ nfs4_close_state(state, nd->intent.open.flags);
}
struct dentry *
if (ctx != NULL)
state = ctx->state;
- status = nfs4_do_setattr(inode, fattr, sattr, state);
+ status = nfs4_do_setattr(NFS_SERVER(inode), fattr,
+ NFS_FH(inode), sattr, state);
if (status == 0)
nfs_setattr_update_inode(inode, sattr);
if (ctx != NULL)
d_instantiate(dentry, igrab(state->inode));
if (flags & O_EXCL) {
struct nfs_fattr fattr;
- status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
+ status = nfs4_do_setattr(NFS_SERVER(dir), &fattr,
+ NFS_FH(state->inode), sattr, state);
if (status == 0)
nfs_setattr_update_inode(state->inode, sattr);
}
if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN))
- status = nfs4_intent_set_file(nd, dentry, state);
+ nfs4_intent_set_file(nd, dentry, state);
else
nfs4_close_state(state, flags);
out:
return err;
}
-static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
+static void nfs4_read_done(struct rpc_task *task, void *calldata)
{
- struct nfs_server *server = NFS_SERVER(data->inode);
+ struct nfs_read_data *data = calldata;
+ struct inode *inode = data->inode;
- if (nfs4_async_handle_error(task, server) == -EAGAIN) {
+ if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
rpc_restart_call(task);
- return -EAGAIN;
+ return;
}
if (task->tk_status > 0)
- renew_lease(server, data->timestamp);
- return 0;
+ renew_lease(NFS_SERVER(inode), data->timestamp);
+ /* Call back common NFS readpage processing */
+ nfs_readpage_result(task, calldata);
}
-static void nfs4_proc_read_setup(struct nfs_read_data *data)
+static const struct rpc_call_ops nfs4_read_ops = {
+ .rpc_call_done = nfs4_read_done,
+ .rpc_release = nfs_readdata_release,
+};
+
+static void
+nfs4_proc_read_setup(struct nfs_read_data *data)
{
+ struct rpc_task *task = &data->task;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ],
.rpc_argp = &data->args,
.rpc_resp = &data->res,
.rpc_cred = data->cred,
};
+ struct inode *inode = data->inode;
+ int flags;
data->timestamp = jiffies;
- rpc_call_setup(&data->task, &msg, 0);
+ /* N.B. Do we need to test? Never called for swapfile inode */
+ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
+
+ /* Finalize the task. */
+ rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_read_ops, data);
+ rpc_call_setup(task, &msg, 0);
}
-static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
+static void nfs4_write_done(struct rpc_task *task, void *calldata)
{
+ struct nfs_write_data *data = calldata;
struct inode *inode = data->inode;
if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
rpc_restart_call(task);
- return -EAGAIN;
+ return;
}
if (task->tk_status >= 0) {
renew_lease(NFS_SERVER(inode), data->timestamp);
nfs_post_op_update_inode(inode, data->res.fattr);
}
- return 0;
+ /* Call back common NFS writeback processing */
+ nfs_writeback_done(task, calldata);
}
-static void nfs4_proc_write_setup(struct nfs_write_data *data, int how)
+static const struct rpc_call_ops nfs4_write_ops = {
+ .rpc_call_done = nfs4_write_done,
+ .rpc_release = nfs_writedata_release,
+};
+
+static void
+nfs4_proc_write_setup(struct nfs_write_data *data, int how)
{
+ struct rpc_task *task = &data->task;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE],
.rpc_argp = &data->args,
struct inode *inode = data->inode;
struct nfs_server *server = NFS_SERVER(inode);
int stable;
+ int flags;
if (how & FLUSH_STABLE) {
if (!NFS_I(inode)->ncommit)
data->timestamp = jiffies;
+ /* Set the initial flags for the task. */
+ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
/* Finalize the task. */
- rpc_call_setup(&data->task, &msg, 0);
+ rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_write_ops, data);
+ rpc_call_setup(task, &msg, 0);
}
-static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
+static void nfs4_commit_done(struct rpc_task *task, void *calldata)
{
+ struct nfs_write_data *data = calldata;
struct inode *inode = data->inode;
if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
rpc_restart_call(task);
- return -EAGAIN;
+ return;
}
if (task->tk_status >= 0)
nfs_post_op_update_inode(inode, data->res.fattr);
- return 0;
+ /* Call back common NFS writeback processing */
+ nfs_commit_done(task, calldata);
}
-static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how)
+static const struct rpc_call_ops nfs4_commit_ops = {
+ .rpc_call_done = nfs4_commit_done,
+ .rpc_release = nfs_commit_release,
+};
+
+static void
+nfs4_proc_commit_setup(struct nfs_write_data *data, int how)
{
+ struct rpc_task *task = &data->task;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT],
.rpc_argp = &data->args,
.rpc_resp = &data->res,
.rpc_cred = data->cred,
};
- struct nfs_server *server = NFS_SERVER(data->inode);
+ struct inode *inode = data->inode;
+ struct nfs_server *server = NFS_SERVER(inode);
+ int flags;
data->args.bitmask = server->attr_bitmask;
data->res.server = server;
- rpc_call_setup(&data->task, &msg, 0);
+ /* Set the initial flags for the task. */
+ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
+ /* Finalize the task. */
+ rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_commit_ops, data);
+ rpc_call_setup(task, &msg, 0);
}
/*
rpc_wake_up_task(task);
task->tk_status = 0;
return -EAGAIN;
- case -NFS4ERR_DELAY:
- nfs_inc_server_stats((struct nfs_server *) server,
- NFSIOS_DELAY);
case -NFS4ERR_GRACE:
+ case -NFS4ERR_DELAY:
rpc_delay(task, NFS4_POLL_RETRY_MAX);
task->tk_status = 0;
return -EAGAIN;
return status;
}
-static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred)
+int
+nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred)
{
struct nfs_fsinfo fsinfo;
struct rpc_message msg = {
return status;
}
-int nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred)
-{
- long timeout;
- int err;
- do {
- err = _nfs4_proc_setclientid_confirm(clp, cred);
- switch (err) {
- case 0:
- return err;
- case -NFS4ERR_RESOURCE:
- /* The IBM lawyers misread another document! */
- case -NFS4ERR_DELAY:
- err = nfs4_delay(clp->cl_rpcclient, &timeout);
- }
- } while (err == 0);
- return err;
-}
-
struct nfs4_delegreturndata {
struct nfs4_delegreturnargs args;
struct nfs4_delegreturnres res;
kfree(calldata);
}
-static const struct rpc_call_ops nfs4_delegreturn_ops = {
+const static struct rpc_call_ops nfs4_delegreturn_ops = {
.rpc_call_prepare = nfs4_delegreturn_prepare,
.rpc_call_done = nfs4_delegreturn_done,
.rpc_release = nfs4_delegreturn_release,
data->rpc_status = 0;
task = rpc_run_task(NFS_CLIENT(inode), RPC_TASK_ASYNC, &nfs4_delegreturn_ops, data);
- if (IS_ERR(task))
+ if (IS_ERR(task)) {
+ nfs4_delegreturn_release(data);
return PTR_ERR(task);
+ }
status = nfs4_wait_for_completion_rpc_task(task);
if (status == 0) {
status = data->rpc_status;
struct nfs_seqid *seqid)
{
struct nfs4_unlockdata *data;
+ struct rpc_task *task;
data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
if (data == NULL) {
/* Unlock _before_ we do the RPC call */
do_vfs_lock(fl->fl_file, fl);
- return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);
+ task = rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);
+ if (IS_ERR(task))
+ nfs4_locku_release_calldata(data);
+ return task;
}
static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
data->arg.reclaim = 1;
task = rpc_run_task(NFS_CLIENT(state->inode), RPC_TASK_ASYNC,
&nfs4_lock_ops, data);
- if (IS_ERR(task))
+ if (IS_ERR(task)) {
+ nfs4_lock_release(data);
return PTR_ERR(task);
+ }
ret = nfs4_wait_for_completion_rpc_task(task);
if (ret == 0) {
ret = data->rpc_status;
{
size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;
- if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
- return 0;
if (buf && buflen < len)
return -ERANGE;
if (buf)
.pathconf = nfs4_proc_pathconf,
.decode_dirent = nfs4_decode_dirent,
.read_setup = nfs4_proc_read_setup,
- .read_done = nfs4_read_done,
.write_setup = nfs4_proc_write_setup,
- .write_done = nfs4_write_done,
.commit_setup = nfs4_proc_commit_setup,
- .commit_done = nfs4_commit_done,
.file_open = nfs_open,
.file_release = nfs_release,
.lock = nfs4_proc_lock,