Commit 4800a811 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Cleanups for the network partition reclaim code

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 16ba67b1
......@@ -190,6 +190,23 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf
nfsi->change_attr = cinfo->after;
}
static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
{
struct inode *inode = state->inode;
open_flags &= (FMODE_READ|FMODE_WRITE);
/* Protect against nfs4_find_state() */
spin_lock(&inode->i_lock);
state->state |= open_flags;
/* NB! List reordering - see the reclaim code for why. */
if ((open_flags & FMODE_WRITE) && 0 == state->nwriters++)
list_move(&state->open_states, &state->owner->so_states);
if (open_flags & FMODE_READ)
state->nreaders++;
memcpy(&state->stateid, stateid, sizeof(state->stateid));
spin_unlock(&inode->i_lock);
}
/*
* OPEN_RECLAIM:
* reclaim state on the server after a reboot.
......@@ -334,7 +351,7 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
return err;
}
static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid)
static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid)
{
struct nfs_open_confirmargs arg = {
.fh = fh,
......@@ -357,6 +374,39 @@ static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *f
return status;
}
static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, struct nfs_openargs *o_arg, struct nfs_openres *o_res)
{
struct nfs_server *server = NFS_SERVER(dir);
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
.rpc_argp = o_arg,
.rpc_resp = o_res,
.rpc_cred = sp->so_cred,
};
int status;
/* Update sequence id. The caller must serialize! */
o_arg->seqid = sp->so_seqid;
o_arg->id = sp->so_id;
o_arg->clientid = sp->so_client->cl_clientid;
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
nfs4_increment_seqid(status, sp);
if (status != 0)
goto out;
update_changeattr(dir, &o_res->cinfo);
if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
status = _nfs4_proc_open_confirm(server->client, &o_res->fh,
sp, &o_res->stateid);
if (status != 0)
goto out;
}
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
out:
return status;
}
static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags)
{
struct nfs_access_entry cache;
......@@ -434,16 +484,8 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
unlock_kernel();
if (err != 0)
goto out_err;
spin_lock(&inode->i_lock);
memcpy(state->stateid.data, delegation->stateid.data,
sizeof(state->stateid.data));
state->state |= open_flags;
if (open_flags & FMODE_READ)
state->nreaders++;
if (open_flags & FMODE_WRITE)
state->nwriters++;
set_bit(NFS_DELEGATED_STATE, &state->flags);
spin_unlock(&inode->i_lock);
update_open_stateid(state, &delegation->stateid, open_flags);
out_ok:
up(&sp->so_sema);
nfs4_put_state_owner(sp);
......@@ -506,12 +548,6 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
.f_attr = &f_attr,
.server = server,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
.rpc_argp = &o_arg,
.rpc_resp = &o_res,
.rpc_cred = cred,
};
/* Protect against reboot recovery conflicts */
down_read(&clp->cl_sem);
......@@ -528,26 +564,10 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
o_arg.u.attrs = sattr;
/* Serialization for the sequence id */
down(&sp->so_sema);
o_arg.seqid = sp->so_seqid;
o_arg.id = sp->so_id;
o_arg.clientid = clp->cl_clientid,
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
nfs4_increment_seqid(status, sp);
if (status)
status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
if (status != 0)
goto out_err;
update_changeattr(dir, &o_res.cinfo);
if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) {
status = _nfs4_proc_open_confirm(server->client, &o_res.fh,
sp, &o_res.stateid);
if (status != 0)
goto out_err;
}
if (!(f_attr.valid & NFS_ATTR_FATTR)) {
status = server->rpc_ops->getattr(server, &o_res.fh, &f_attr);
if (status < 0)
goto out_err;
}
status = -ENOMEM;
inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr);
......@@ -556,14 +576,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
state = nfs4_get_open_state(inode, sp);
if (!state)
goto out_err;
memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
spin_lock(&inode->i_lock);
if (flags & FMODE_READ)
state->nreaders++;
if (flags & FMODE_WRITE)
state->nwriters++;
state->state |= flags & (FMODE_READ|FMODE_WRITE);
spin_unlock(&inode->i_lock);
update_open_stateid(state, &o_res.stateid, flags);
if (o_res.delegation_type != 0)
nfs_inode_set_delegation(inode, cred, &o_res);
up(&sp->so_sema);
......
......@@ -447,7 +447,9 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
if (state == NULL && new != NULL) {
state = new;
/* Caller *must* be holding owner->so_sem */
list_add(&state->open_states, &owner->so_states);
/* Note: The reclaim code dictates that we add stateless
* and read-only stateids to the end of the list */
list_add_tail(&state->open_states, &owner->so_states);
state->owner = owner;
atomic_inc(&owner->so_count);
list_add(&state->inode_states, &nfsi->open_states);
......@@ -503,8 +505,12 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode)
state->nreaders--;
if (mode & FMODE_WRITE)
state->nwriters--;
if (state->nwriters == 0 && state->nreaders == 0)
list_del_init(&state->inode_states);
if (state->nwriters == 0) {
if (state->nreaders == 0)
list_del_init(&state->inode_states);
/* See reclaim code */
list_move_tail(&state->open_states, &owner->so_states);
}
spin_unlock(&inode->i_lock);
newstate = 0;
if (state->state != 0) {
......@@ -798,6 +804,14 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
struct nfs4_lock_state *lock;
int status = 0;
/* Note: we rely on the sp->so_states list being ordered
* so that we always reclaim open(O_RDWR) and/or open(O_WRITE)
* states first.
* This is needed to ensure that the server won't give us any
* read delegations that we have to return if, say, we are
* recovering after a network partition or a reboot from a
* server that doesn't support a grace period.
*/
list_for_each_entry(state, &sp->so_states, open_states) {
if (state->state == 0)
continue;
......
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