X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfs%2Fnfs4proc.c;h=7d56ca4d63b72e96985297c47b004cce2166cfb0;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=7509bd2ae1818f29a75318319ca636bc381a16aa;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7509bd2ae..7d56ca4d6 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -477,7 +477,7 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st /* * Returns an nfs4_state + an referenced inode */ -static int _nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) +static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) { struct nfs4_state_owner *sp; struct nfs4_state *state = NULL; @@ -491,7 +491,7 @@ static int _nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct struct nfs_openargs o_arg = { .fh = NFS_FH(dir), .open_flags = flags, - .name = name, + .name = &dentry->d_name, .server = server, .bitmask = server->attr_bitmask, .claim = NFS4_OPEN_CLAIM_NULL, @@ -581,14 +581,14 @@ out_err: } -struct nfs4_state *nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred) +struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) { struct nfs4_exception exception = { }; struct nfs4_state *res; int status; do { - status = _nfs4_do_open(dir, name, flags, sattr, cred, &res); + status = _nfs4_do_open(dir, dentry, flags, sattr, cred, &res); if (status == 0) break; /* NOTE: BAD_SEQID means the server and client disagree about the @@ -635,6 +635,8 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, fattr->valid = 0; + if (state != NULL) + msg.rpc_cred = state->owner->so_cred; if (sattr->ia_valid & ATTR_SIZE) nfs4_copy_stateid(&arg.stateid, state, NULL); else @@ -658,6 +660,61 @@ int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, return err; } +struct nfs4_closedata { + struct inode *inode; + struct nfs4_state *state; + struct nfs_closeargs arg; + struct nfs_closeres res; +}; + +static void nfs4_close_done(struct rpc_task *task) +{ + struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; + struct nfs4_state *state = calldata->state; + struct nfs4_state_owner *sp = state->owner; + struct nfs_server *server = NFS_SERVER(calldata->inode); + + /* hmm. we are done with the inode, and in the process of freeing + * the state_owner. we keep this around to process errors + */ + nfs4_increment_seqid(task->tk_status, sp); + switch (task->tk_status) { + case 0: + state->state = calldata->arg.open_flags; + memcpy(&state->stateid, &calldata->res.stateid, + sizeof(state->stateid)); + break; + case -NFS4ERR_STALE_STATEID: + case -NFS4ERR_EXPIRED: + state->state = calldata->arg.open_flags; + nfs4_schedule_state_recovery(server->nfs4_state); + break; + default: + if (nfs4_async_handle_error(task, server) == -EAGAIN) { + rpc_restart_call(task); + return; + } + } + nfs4_put_open_state(state); + up(&sp->so_sema); + nfs4_put_state_owner(sp); + up_read(&server->nfs4_state->cl_sem); + kfree(calldata); +} + +static inline int nfs4_close_call(struct rpc_clnt *clnt, struct nfs4_closedata *calldata) +{ + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], + .rpc_argp = &calldata->arg, + .rpc_resp = &calldata->res, + .rpc_cred = calldata->state->owner->so_cred, + }; + if (calldata->arg.open_flags != 0) + msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; + return rpc_call_async(clnt, &msg, 0, nfs4_close_done, calldata); +} + /* * It is possible for data to be read/written from a mem-mapped file * after the sys_close call (which hits the vfs layer as a flush). @@ -669,102 +726,34 @@ int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, * * NOTE: Caller must be holding the sp->so_owner semaphore! */ -static int _nfs4_do_close(struct inode *inode, struct nfs4_state *state) +int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) { - struct nfs4_state_owner *sp = state->owner; - int status = 0; - struct nfs_closeargs arg = { - .fh = NFS_FH(inode), - }; - struct nfs_closeres res; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], - .rpc_argp = &arg, - .rpc_resp = &res, - }; + struct nfs4_closedata *calldata; + int status; - if (test_bit(NFS_DELEGATED_STATE, &state->flags)) + /* Tell caller we're done */ + if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { + state->state = mode; return 0; - memcpy(&arg.stateid, &state->stateid, sizeof(arg.stateid)); + } + calldata = (struct nfs4_closedata *)kmalloc(sizeof(*calldata), GFP_KERNEL); + if (calldata == NULL) + return -ENOMEM; + calldata->inode = inode; + calldata->state = state; + calldata->arg.fh = NFS_FH(inode); /* Serialization for the sequence id */ - arg.seqid = sp->so_seqid, - status = rpc_call_sync(NFS_SERVER(inode)->client, &msg, RPC_TASK_NOINTR); - - /* hmm. we are done with the inode, and in the process of freeing - * the state_owner. we keep this around to process errors + calldata->arg.seqid = state->owner->so_seqid; + calldata->arg.open_flags = mode; + memcpy(&calldata->arg.stateid, &state->stateid, + sizeof(calldata->arg.stateid)); + status = nfs4_close_call(NFS_SERVER(inode)->client, calldata); + /* + * Return -EINPROGRESS on success in order to indicate to the + * caller that an asynchronous RPC call has been launched, and + * that it will release the semaphores on completion. */ - nfs4_increment_seqid(status, sp); - if (!status) - memcpy(&state->stateid, &res.stateid, sizeof(state->stateid)); - - return status; -} - -int nfs4_do_close(struct inode *inode, struct nfs4_state *state) -{ - struct nfs_server *server = NFS_SERVER(state->inode); - struct nfs4_exception exception = { }; - int err; - do { - err = _nfs4_do_close(inode, state); - switch (err) { - case -NFS4ERR_STALE_STATEID: - case -NFS4ERR_EXPIRED: - nfs4_schedule_state_recovery(server->nfs4_state); - err = 0; - default: - state->state = 0; - } - err = nfs4_handle_exception(server, err, &exception); - } while (exception.retry); - return err; -} - -static int _nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) -{ - struct nfs4_state_owner *sp = state->owner; - int status = 0; - struct nfs_closeargs arg = { - .fh = NFS_FH(inode), - .seqid = sp->so_seqid, - .open_flags = mode, - }; - struct nfs_closeres res; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE], - .rpc_argp = &arg, - .rpc_resp = &res, - }; - - if (test_bit(NFS_DELEGATED_STATE, &state->flags)) - return 0; - memcpy(&arg.stateid, &state->stateid, sizeof(arg.stateid)); - status = rpc_call_sync(NFS_SERVER(inode)->client, &msg, RPC_TASK_NOINTR); - nfs4_increment_seqid(status, sp); - if (!status) - memcpy(&state->stateid, &res.stateid, sizeof(state->stateid)); - - return status; -} - -int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) -{ - struct nfs_server *server = NFS_SERVER(state->inode); - struct nfs4_exception exception = { }; - int err; - do { - err = _nfs4_do_downgrade(inode, state, mode); - switch (err) { - case -NFS4ERR_STALE_STATEID: - case -NFS4ERR_EXPIRED: - nfs4_schedule_state_recovery(server->nfs4_state); - err = 0; - default: - state->state = mode; - } - err = nfs4_handle_exception(server, err, &exception); - } while (exception.retry); - return err; + return (status == 0) ? -EINPROGRESS : status; } struct inode * @@ -785,7 +774,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) } cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); - state = nfs4_do_open(dir, &dentry->d_name, nd->intent.open.flags, &attr, cred); + state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); put_rpccred(cred); if (IS_ERR(state)) return (struct inode *)state; @@ -802,7 +791,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); state = nfs4_open_delegated(dentry->d_inode, openflags, cred); if (IS_ERR(state)) - state = nfs4_do_open(dir, &dentry->d_name, openflags, NULL, cred); + state = nfs4_do_open(dir, dentry, openflags, NULL, cred); put_rpccred(cred); if (state == ERR_PTR(-ENOENT) && dentry->d_inode == 0) return 1; @@ -1026,7 +1015,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, FMODE_WRITE, cred); if (IS_ERR(state)) state = nfs4_do_open(dentry->d_parent->d_inode, - &dentry->d_name, FMODE_WRITE, + dentry, FMODE_WRITE, NULL, cred); need_iput = 1; } @@ -1327,7 +1316,7 @@ static int nfs4_proc_commit(struct nfs_write_data *cdata) */ static struct inode * -nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, +nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags) { struct inode *inode; @@ -1335,7 +1324,7 @@ nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, struct rpc_cred *cred; cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); - state = nfs4_do_open(dir, name, flags, sattr, cred); + state = nfs4_do_open(dir, dentry, flags, sattr, cred); put_rpccred(cred); if (!IS_ERR(state)) { inode = state->inode;