提交 003707c7 编写于 作者: T Trond Myklebust

NFSv4: Always use the delegation if we have one

Signed-off-by: NTrond Myklebust <Trond.Myklebust@netapp.com>
上级 0f9f95e0
...@@ -122,7 +122,10 @@ struct nfs4_lock_state { ...@@ -122,7 +122,10 @@ struct nfs4_lock_state {
/* bits for nfs4_state->flags */ /* bits for nfs4_state->flags */
enum { enum {
LK_STATE_IN_USE, LK_STATE_IN_USE,
NFS_DELEGATED_STATE, NFS_DELEGATED_STATE, /* Current stateid is delegation */
NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */
NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */
NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
}; };
struct nfs4_state { struct nfs4_state {
...@@ -136,11 +139,12 @@ struct nfs4_state { ...@@ -136,11 +139,12 @@ struct nfs4_state {
unsigned long flags; /* Do we hold any locks? */ unsigned long flags; /* Do we hold any locks? */
spinlock_t state_lock; /* Protects the lock_states list */ spinlock_t state_lock; /* Protects the lock_states list */
nfs4_stateid stateid; nfs4_stateid stateid; /* Current stateid: may be delegation */
nfs4_stateid open_stateid; /* OPEN stateid */
unsigned int n_rdonly; unsigned int n_rdonly; /* Number of read-only references */
unsigned int n_wronly; unsigned int n_wronly; /* Number of write-only references */
unsigned int n_rdwr; unsigned int n_rdwr; /* Number of read/write references */
int state; /* State on the server (R,W, or RW) */ int state; /* State on the server (R,W, or RW) */
atomic_t count; atomic_t count;
}; };
......
...@@ -319,7 +319,7 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) ...@@ -319,7 +319,7 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
return ret; return ret;
} }
static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags)
{ {
switch (open_flags) { switch (open_flags) {
case FMODE_WRITE: case FMODE_WRITE:
...@@ -331,9 +331,36 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_ ...@@ -331,9 +331,36 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_
case FMODE_READ|FMODE_WRITE: case FMODE_READ|FMODE_WRITE:
state->n_rdwr++; state->n_rdwr++;
} }
nfs4_state_set_mode_locked(state, state->state | open_flags);
}
static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
{
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data));
memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data));
switch (open_flags) {
case FMODE_READ:
set_bit(NFS_O_RDONLY_STATE, &state->flags);
break;
case FMODE_WRITE:
set_bit(NFS_O_WRONLY_STATE, &state->flags);
break;
case FMODE_READ|FMODE_WRITE:
set_bit(NFS_O_RDWR_STATE, &state->flags);
}
} }
static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
{
spin_lock(&state->owner->so_lock);
spin_lock(&state->inode->i_lock);
nfs_set_open_stateid_locked(state, stateid, open_flags);
spin_unlock(&state->inode->i_lock);
spin_unlock(&state->owner->so_lock);
}
static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags)
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
...@@ -341,9 +368,13 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, ...@@ -341,9 +368,13 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid,
/* Protect against nfs4_find_state_byowner() */ /* Protect against nfs4_find_state_byowner() */
spin_lock(&state->owner->so_lock); spin_lock(&state->owner->so_lock);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
memcpy(&state->stateid, stateid, sizeof(state->stateid)); if (deleg_stateid != NULL) {
memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
set_bit(NFS_DELEGATED_STATE, &state->flags);
}
if (open_stateid != NULL)
nfs_set_open_stateid_locked(state, open_stateid, open_flags);
update_open_stateflags(state, open_flags); update_open_stateflags(state, open_flags);
nfs4_state_set_mode_locked(state, state->state | open_flags);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
spin_unlock(&state->owner->so_lock); spin_unlock(&state->owner->so_lock);
} }
...@@ -352,6 +383,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data ...@@ -352,6 +383,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
{ {
struct inode *inode; struct inode *inode;
struct nfs4_state *state = NULL; struct nfs4_state *state = NULL;
struct nfs_delegation *delegation;
nfs4_stateid *deleg_stateid = NULL;
if (!(data->f_attr.valid & NFS_ATTR_FATTR)) if (!(data->f_attr.valid & NFS_ATTR_FATTR))
goto out; goto out;
...@@ -361,13 +394,14 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data ...@@ -361,13 +394,14 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
state = nfs4_get_open_state(inode, data->owner); state = nfs4_get_open_state(inode, data->owner);
if (state == NULL) if (state == NULL)
goto put_inode; goto put_inode;
update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags);
if (data->o_res.delegation_type != 0) { if (data->o_res.delegation_type != 0) {
struct nfs_inode *nfsi = NFS_I(inode);
int delegation_flags = 0; int delegation_flags = 0;
if (nfsi->delegation) rcu_read_lock();
delegation_flags = nfsi->delegation->flags; delegation = rcu_dereference(NFS_I(inode)->delegation);
if (delegation)
delegation_flags = delegation->flags;
rcu_read_unlock();
if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM))
nfs_inode_set_delegation(state->inode, nfs_inode_set_delegation(state->inode,
data->owner->so_cred, data->owner->so_cred,
...@@ -377,6 +411,12 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data ...@@ -377,6 +411,12 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
data->owner->so_cred, data->owner->so_cred,
&data->o_res); &data->o_res);
} }
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
if (delegation != NULL)
deleg_stateid = &delegation->stateid;
update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags);
rcu_read_unlock();
put_inode: put_inode:
iput(inode); iput(inode);
out: out:
...@@ -911,8 +951,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred ...@@ -911,8 +951,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
unlock_kernel(); unlock_kernel();
if (err != 0) if (err != 0)
goto out_put_open_state; goto out_put_open_state;
set_bit(NFS_DELEGATED_STATE, &state->flags); update_open_stateid(state, NULL, &delegation->stateid, open_flags);
update_open_stateid(state, &delegation->stateid, open_flags);
out_ok: out_ok:
nfs4_put_state_owner(sp); nfs4_put_state_owner(sp);
up_read(&nfsi->rwsem); up_read(&nfsi->rwsem);
...@@ -1149,8 +1188,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) ...@@ -1149,8 +1188,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid);
switch (task->tk_status) { switch (task->tk_status) {
case 0: case 0:
memcpy(&state->stateid, &calldata->res.stateid, nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags);
sizeof(state->stateid));
renew_lease(server, calldata->timestamp); renew_lease(server, calldata->timestamp);
break; break;
case -NFS4ERR_STALE_STATEID: case -NFS4ERR_STALE_STATEID:
...@@ -1175,26 +1213,32 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) ...@@ -1175,26 +1213,32 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
.rpc_resp = &calldata->res, .rpc_resp = &calldata->res,
.rpc_cred = state->owner->so_cred, .rpc_cred = state->owner->so_cred,
}; };
int mode = 0, old_mode; int clear_rd, clear_wr, clear_rdwr;
int mode;
if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
return; return;
/* Recalculate the new open mode in case someone reopened the file
* while we were waiting in line to be scheduled. mode = FMODE_READ|FMODE_WRITE;
*/ clear_rd = clear_wr = clear_rdwr = 0;
spin_lock(&state->owner->so_lock); spin_lock(&state->owner->so_lock);
spin_lock(&calldata->inode->i_lock); spin_lock(&calldata->inode->i_lock);
mode = old_mode = state->state; /* Calculate the change in open mode */
if (state->n_rdwr == 0) { if (state->n_rdwr == 0) {
if (state->n_rdonly == 0) if (state->n_rdonly == 0) {
mode &= ~FMODE_READ; mode &= ~FMODE_READ;
if (state->n_wronly == 0) clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags);
clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
}
if (state->n_wronly == 0) {
mode &= ~FMODE_WRITE; mode &= ~FMODE_WRITE;
clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags);
clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
}
} }
nfs4_state_set_mode_locked(state, mode);
spin_unlock(&calldata->inode->i_lock); spin_unlock(&calldata->inode->i_lock);
spin_unlock(&state->owner->so_lock); spin_unlock(&state->owner->so_lock);
if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { if (!clear_rd && !clear_wr && !clear_rdwr) {
/* Note: exit _without_ calling nfs4_close_done */ /* Note: exit _without_ calling nfs4_close_done */
task->tk_action = NULL; task->tk_action = NULL;
return; return;
...@@ -1238,7 +1282,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state) ...@@ -1238,7 +1282,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state)
calldata->inode = state->inode; calldata->inode = state->inode;
calldata->state = state; calldata->state = state;
calldata->arg.fh = NFS_FH(state->inode); calldata->arg.fh = NFS_FH(state->inode);
calldata->arg.stateid = &state->stateid; calldata->arg.stateid = &state->open_stateid;
/* Serialization for the sequence id */ /* Serialization for the sequence id */
calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
if (calldata->arg.seqid == NULL) if (calldata->arg.seqid == NULL)
......
...@@ -412,7 +412,8 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) ...@@ -412,7 +412,8 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct nfs4_state_owner *owner = state->owner; struct nfs4_state_owner *owner = state->owner;
int oldstate, newstate = 0; int call_close = 0;
int newstate;
atomic_inc(&owner->so_count); atomic_inc(&owner->so_count);
/* Protect against nfs4_find_state() */ /* Protect against nfs4_find_state() */
...@@ -428,21 +429,26 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) ...@@ -428,21 +429,26 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
case FMODE_READ|FMODE_WRITE: case FMODE_READ|FMODE_WRITE:
state->n_rdwr--; state->n_rdwr--;
} }
oldstate = newstate = state->state; newstate = FMODE_READ|FMODE_WRITE;
if (state->n_rdwr == 0) { if (state->n_rdwr == 0) {
if (state->n_rdonly == 0) if (state->n_rdonly == 0) {
newstate &= ~FMODE_READ; newstate &= ~FMODE_READ;
if (state->n_wronly == 0) call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
}
if (state->n_wronly == 0) {
newstate &= ~FMODE_WRITE; newstate &= ~FMODE_WRITE;
call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
}
if (newstate == 0)
clear_bit(NFS_DELEGATED_STATE, &state->flags);
} }
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { nfs4_state_set_mode_locked(state, newstate);
nfs4_state_set_mode_locked(state, newstate);
oldstate = newstate;
}
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
spin_unlock(&owner->so_lock); spin_unlock(&owner->so_lock);
if (oldstate == newstate) { if (!call_close) {
nfs4_put_open_state(state); nfs4_put_open_state(state);
nfs4_put_state_owner(owner); nfs4_put_state_owner(owner);
} else } else
...@@ -838,6 +844,10 @@ static void nfs4_state_mark_reclaim(struct nfs_client *clp) ...@@ -838,6 +844,10 @@ static void nfs4_state_mark_reclaim(struct nfs_client *clp)
sp->so_seqid.flags = 0; sp->so_seqid.flags = 0;
spin_lock(&sp->so_lock); spin_lock(&sp->so_lock);
list_for_each_entry(state, &sp->so_states, open_states) { list_for_each_entry(state, &sp->so_states, open_states) {
clear_bit(NFS_DELEGATED_STATE, &state->flags);
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
clear_bit(NFS_O_RDWR_STATE, &state->flags);
list_for_each_entry(lock, &state->lock_states, ls_locks) { list_for_each_entry(lock, &state->lock_states, ls_locks) {
lock->ls_seqid.counter = 0; lock->ls_seqid.counter = 0;
lock->ls_seqid.flags = 0; lock->ls_seqid.flags = 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册