Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 9970
b: refs/heads/master
c: cee54fc
h: refs/heads/master
v: v3
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Oct 18, 2005
1 parent 5fc6f70 commit b6ae525
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 84 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5e5ce5be6f0161d2a069a4f8a1154fe639c5c02f
refs/heads/master: cee54fc944422c44e476736c045a9e8053cb0644
42 changes: 38 additions & 4 deletions trunk/fs/nfs/nfs4_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,35 @@ struct nfs4_client {
unsigned char cl_id_uniquifier;
};

/*
* struct rpc_sequence ensures that RPC calls are sent in the exact
* order that they appear on the list.
*/
struct rpc_sequence {
struct rpc_wait_queue wait; /* RPC call delay queue */
spinlock_t lock; /* Protects the list */
struct list_head list; /* Defines sequence of RPC calls */
};

#define NFS_SEQID_CONFIRMED 1
struct nfs_seqid_counter {
struct rpc_sequence *sequence;
int flags;
u32 counter;
};

struct nfs_seqid {
struct list_head list;
struct nfs_seqid_counter *sequence;
struct rpc_task *task;
};

static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status)
{
if (seqid_mutating_err(-status))
seqid->flags |= NFS_SEQID_CONFIRMED;
}

/*
* NFS4 state_owners and lock_owners are simply labels for ordered
* sequences of RPC calls. Their sole purpose is to provide once-only
Expand All @@ -106,12 +135,13 @@ struct nfs4_state_owner {
struct nfs4_client *so_client;
u32 so_id; /* 32-bit identifier, unique */
struct semaphore so_sema;
u32 so_seqid; /* protected by so_sema */
atomic_t so_count;

struct rpc_cred *so_cred; /* Associated cred */
struct list_head so_states;
struct list_head so_delegations;
struct nfs_seqid_counter so_seqid;
struct rpc_sequence so_sequence;
};

/*
Expand All @@ -132,7 +162,7 @@ struct nfs4_lock_state {
fl_owner_t ls_owner; /* POSIX lock owner */
#define NFS_LOCK_INITIALIZED 1
int ls_flags;
u32 ls_seqid;
struct nfs_seqid_counter ls_seqid;
u32 ls_id;
nfs4_stateid ls_stateid;
atomic_t ls_count;
Expand Down Expand Up @@ -224,12 +254,16 @@ extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state
extern void nfs4_put_open_state(struct nfs4_state *);
extern void nfs4_close_state(struct nfs4_state *, mode_t);
extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode);
extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp);
extern void nfs4_schedule_state_recovery(struct nfs4_client *);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls);
extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);

extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter);
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid);
extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid);
extern void nfs_free_seqid(struct nfs_seqid *seqid);

extern const nfs4_stateid zero_stateid;

/* nfs4xdr.c */
Expand Down
111 changes: 73 additions & 38 deletions trunk/fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
struct nfs_delegation *delegation = NFS_I(inode)->delegation;
struct nfs_openargs o_arg = {
.fh = NFS_FH(inode),
.seqid = sp->so_seqid,
.id = sp->so_id,
.open_flags = state->state,
.clientid = server->nfs4_state->cl_clientid,
Expand All @@ -245,8 +244,13 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
}
o_arg.u.delegation_type = delegation->type;
}
o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
if (o_arg.seqid == NULL)
return -ENOMEM;
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
nfs4_increment_seqid(status, sp);
/* Confirm the sequence as being established */
nfs_confirm_seqid(&sp->so_seqid, status);
nfs_increment_open_seqid(status, o_arg.seqid);
if (status == 0) {
memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
if (o_res.delegation_type != 0) {
Expand All @@ -256,6 +260,7 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
nfs_async_inode_return_delegation(inode, &o_res.stateid);
}
}
nfs_free_seqid(o_arg.seqid);
clear_bit(NFS_DELEGATED_STATE, &state->flags);
/* Ensure we update the inode attributes */
NFS_CACHEINV(inode);
Expand Down Expand Up @@ -307,16 +312,20 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state
goto out;
if (state->state == 0)
goto out;
arg.seqid = sp->so_seqid;
arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
status = -ENOMEM;
if (arg.seqid == NULL)
goto out;
arg.open_flags = state->state;
memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data));
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
nfs4_increment_seqid(status, sp);
nfs_increment_open_seqid(status, arg.seqid);
if (status >= 0) {
memcpy(state->stateid.data, res.stateid.data,
sizeof(state->stateid.data));
clear_bit(NFS_DELEGATED_STATE, &state->flags);
}
nfs_free_seqid(arg.seqid);
out:
up(&sp->so_sema);
dput(parent);
Expand Down Expand Up @@ -345,11 +354,11 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
return err;
}

static inline 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_seqid *seqid)
{
struct nfs_open_confirmargs arg = {
.fh = fh,
.seqid = sp->so_seqid,
.seqid = seqid,
.stateid = *stateid,
};
struct nfs_open_confirmres res;
Expand All @@ -362,7 +371,9 @@ static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nf
int status;

status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR);
nfs4_increment_seqid(status, sp);
/* Confirm the sequence as being established */
nfs_confirm_seqid(&sp->so_seqid, status);
nfs_increment_open_seqid(status, seqid);
if (status >= 0)
memcpy(stateid, &res.stateid, sizeof(*stateid));
return status;
Expand All @@ -380,21 +391,21 @@ static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, stru
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);
nfs_increment_open_seqid(status, o_arg->seqid);
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);
sp, &o_res->stateid, o_arg->seqid);
if (status != 0)
goto out;
}
nfs_confirm_seqid(&sp->so_seqid, 0);
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
out:
Expand Down Expand Up @@ -465,6 +476,10 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
set_bit(NFS_DELEGATED_STATE, &state->flags);
goto out;
}
o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
status = -ENOMEM;
if (o_arg.seqid == NULL)
goto out;
status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
if (status != 0)
goto out_nodeleg;
Expand All @@ -490,6 +505,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res);
}
out_nodeleg:
nfs_free_seqid(o_arg.seqid);
clear_bit(NFS_DELEGATED_STATE, &state->flags);
out:
dput(parent);
Expand Down Expand Up @@ -667,6 +683,9 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
/* Serialization for the sequence id */
down(&sp->so_sema);

o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
if (o_arg.seqid == NULL)
return -ENOMEM;
status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
if (status != 0)
goto out_err;
Expand All @@ -681,6 +700,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
update_open_stateid(state, &o_res.stateid, flags);
if (o_res.delegation_type != 0)
nfs_inode_set_delegation(inode, cred, &o_res);
nfs_free_seqid(o_arg.seqid);
up(&sp->so_sema);
nfs4_put_state_owner(sp);
up_read(&clp->cl_sem);
Expand All @@ -690,6 +710,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
if (sp != NULL) {
if (state != NULL)
nfs4_put_open_state(state);
nfs_free_seqid(o_arg.seqid);
up(&sp->so_sema);
nfs4_put_state_owner(sp);
}
Expand Down Expand Up @@ -718,7 +739,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry,
* It is actually a sign of a bug on the client or on the server.
*
* If we receive a BAD_SEQID error in the particular case of
* doing an OPEN, we assume that nfs4_increment_seqid() will
* doing an OPEN, we assume that nfs_increment_open_seqid() will
* have unhashed the old state_owner for us, and that we can
* therefore safely retry using a new one. We should still warn
* the user though...
Expand Down Expand Up @@ -799,7 +820,7 @@ static void nfs4_close_done(struct rpc_task *task)
/* 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);
nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid);
switch (task->tk_status) {
case 0:
memcpy(&state->stateid, &calldata->res.stateid,
Expand All @@ -818,6 +839,7 @@ static void nfs4_close_done(struct rpc_task *task)
}
state->state = calldata->arg.open_flags;
nfs4_put_open_state(state);
nfs_free_seqid(calldata->arg.seqid);
up(&sp->so_sema);
nfs4_put_state_owner(sp);
up_read(&server->nfs4_state->cl_sem);
Expand Down Expand Up @@ -865,7 +887,11 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode)
calldata->state = state;
calldata->arg.fh = NFS_FH(inode);
/* Serialization for the sequence id */
calldata->arg.seqid = state->owner->so_seqid;
calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
if (calldata->arg.seqid == NULL) {
kfree(calldata);
return -ENOMEM;
}
calldata->arg.open_flags = mode;
memcpy(&calldata->arg.stateid, &state->stateid,
sizeof(calldata->arg.stateid));
Expand Down Expand Up @@ -2729,15 +2755,19 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock
/* We might have lost the locks! */
if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0)
goto out;
luargs.seqid = lsp->ls_seqid;
memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid));
luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid);
status = -ENOMEM;
if (luargs.seqid == NULL)
goto out;
memcpy(luargs.stateid.data, lsp->ls_stateid.data, sizeof(luargs.stateid.data));
arg.u.locku = &luargs;
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
nfs4_increment_lock_seqid(status, lsp);
nfs_increment_lock_seqid(status, luargs.seqid);

if (status == 0)
memcpy(&lsp->ls_stateid, &res.u.stateid,
sizeof(lsp->ls_stateid));
memcpy(lsp->ls_stateid.data, res.u.stateid.data,
sizeof(lsp->ls_stateid.data));
nfs_free_seqid(luargs.seqid);
out:
up(&state->lock_sema);
if (status == 0)
Expand Down Expand Up @@ -2783,49 +2813,54 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r
.reclaim = reclaim,
.new_lock_owner = 0,
};
int status;
struct nfs_seqid *lock_seqid;
int status = -ENOMEM;

if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) {
lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid);
if (lock_seqid == NULL)
return -ENOMEM;
if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) {
struct nfs4_state_owner *owner = state->owner;
struct nfs_open_to_lock otl = {
.lock_owner = {
.clientid = server->nfs4_state->cl_clientid,
},
};

otl.lock_seqid = lsp->ls_seqid;
otl.lock_seqid = lock_seqid;
otl.lock_owner.id = lsp->ls_id;
memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid));
largs.u.open_lock = &otl;
largs.new_lock_owner = 1;
arg.u.lock = &largs;
down(&owner->so_sema);
otl.open_seqid = owner->so_seqid;
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
/* increment open_owner seqid on success, and
* seqid mutating errors */
nfs4_increment_seqid(status, owner);
up(&owner->so_sema);
if (status == 0) {
lsp->ls_flags |= NFS_LOCK_INITIALIZED;
lsp->ls_seqid++;
otl.open_seqid = nfs_alloc_seqid(&owner->so_seqid);
if (otl.open_seqid != NULL) {
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
/* increment seqid on success, and seqid mutating errors */
nfs_increment_open_seqid(status, otl.open_seqid);
nfs_free_seqid(otl.open_seqid);
}
up(&owner->so_sema);
if (status == 0)
nfs_confirm_seqid(&lsp->ls_seqid, 0);
} else {
struct nfs_exist_lock el = {
.seqid = lsp->ls_seqid,
};
struct nfs_exist_lock el;
memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid));
largs.u.exist_lock = ⪙
arg.u.lock = &largs;
el.seqid = lock_seqid;
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
/* increment seqid on success, and * seqid mutating errors*/
nfs4_increment_lock_seqid(status, lsp);
}
/* increment seqid on success, and seqid mutating errors*/
nfs_increment_lock_seqid(status, lock_seqid);
/* save the returned stateid. */
if (status == 0)
memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid));
else if (status == -NFS4ERR_DENIED)
if (status == 0) {
memcpy(lsp->ls_stateid.data, res.u.stateid.data, sizeof(lsp->ls_stateid.data));
lsp->ls_flags |= NFS_LOCK_INITIALIZED;
} else if (status == -NFS4ERR_DENIED)
status = -EAGAIN;
nfs_free_seqid(lock_seqid);
return status;
}

Expand Down
Loading

0 comments on commit b6ae525

Please sign in to comment.