2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 00/25] nfsd4 state cleanup

This is just another batch of little cleanups and bugfixes to the nfsd4
state code.

What I'm actually thinking I'd like to do next is change the way
stateid's are composed to make it possible to look up the client first.
Once the client's looked up, lookup of the individual stateid, and most
of the following work, looks to me like it could be done under a
per-client lock. The set of clients doesn't change very much so we
could use locking that favors readers (maybe rcu) for that part. So
that could be a first step towards saner locking.

And then also still to do:
- close replays: we keep around a stateid to handle close
replays only in the case where it's the last stateid for an
openowner, but that's not sufficient.
- the data structures aren't really right for the things we need
to do: e.g. release_lockowner currently does a linear search
through all the lockowners!
- multiple client-to-lockowner locks for a given (owner, file)
aren't handled right.
- I need to look again at doing a better job of distinguishing
the bad, expired, and stale cases for stateid's.

I was hoping to have that ready for 3.2 but unfortunately keep running
across small bugs or cleanup opportunities like these along the way;
perhaps next week....

--b.

J. Bruce Fields (25):
nfsd4: centralize handling of replay owners
nfsd4: cleanup seqid op stateowner usage
nfsd4: extend state lock over seqid replay logic
nfsd4: eliminate impossible open replay case
nfsd4: drop most stateowner refcounting
nfsd4: eliminate unused lt_stateowner
nfsd4: share common seqid checks
nfsd4: simplify check_open logic
nfsd4: move double-confirm test to open_confirm
nfsd4: move CLOSE_STATE special case to caller
nfsd4: split stateowners into open and lockowners
nfsd4: split out some free_generic_stateid code
nfsd4: rearrange to avoid a forward reference
nfsd4: split up find_stateid
nfsd4: split preprocess_seqid, cleanup
nfsd4: pass around typemask instead of flags
nfsd4: rename init_stateid
nfsd4: remove redundant stateid initialization
nfsd4: move some of nfs4_stateid into a separate structure
nfsd4: add common dl_stid field to delegation
nfsd4: share common stid-hashing helper function
nfsd4: hash deleg stateid's like any other
nfsd4: fix test_stateid for delegation stateid's
nfsd4: use deleg changes to cleanup preprocess_stateid_op
nfsd4: better stateid hashing

fs/nfsd/nfs4callback.c | 2 +-
fs/nfsd/nfs4proc.c | 25 +-
fs/nfsd/nfs4state.c | 989 +++++++++++++++++++++++-------------------------
fs/nfsd/nfs4xdr.c | 52 ++--
fs/nfsd/state.h | 92 +++--
fs/nfsd/xdr4.h | 12 +-
6 files changed, 570 insertions(+), 602 deletions(-)

--
1.7.4.1



2011-09-26 22:36:44

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 00/25] nfsd4 state cleanup

On Mon, Sep 19, 2011 at 09:14:16AM -0400, bfields wrote:
> On Wed, Sep 14, 2011 at 07:44:56AM -0400, J. Bruce Fields wrote:
> > This is just another batch of little cleanups and bugfixes to the nfsd4
> > state code.
> >
> > What I'm actually thinking I'd like to do next is change the way
> > stateid's are composed to make it possible to look up the client first.
> > Once the client's looked up, lookup of the individual stateid, and most
> > of the following work, looks to me like it could be done under a
> > per-client lock. The set of clients doesn't change very much so we
> > could use locking that favors readers (maybe rcu) for that part. So
> > that could be a first step towards saner locking.
> >
> > And then also still to do:
> > - close replays: we keep around a stateid to handle close
> > replays only in the case where it's the last stateid for an
> > openowner, but that's not sufficient.
>
> A fix for this follows.

(Committed for 3.2).--b.

2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic

There are currently a couple races in the seqid replay code: a
retransmission could come while we're still encoding the original reply,
or a new seqid-mutating call could come as we're encoding a replay.

So, extend the state lock over the encoding (both encoding of a replayed
reply and caching of the original encoded reply).

I really hate doing this, and previously added the stateowner
reference-counting code to avoid it (which was insufficient)--but I
don't see a less complicated alternative at the moment.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4proc.c | 5 +++--
fs/nfsd/nfs4state.c | 12 ++++++++----
2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 50bae74..50063a8 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -408,8 +408,8 @@ out:
if (open->op_stateowner) {
nfs4_get_stateowner(open->op_stateowner);
cstate->replay_owner = open->op_stateowner;
- }
- nfs4_unlock_state();
+ } else
+ nfs4_unlock_state();
return status;
}

@@ -1227,6 +1227,7 @@ encode_op:
be32_to_cpu(status));

if (cstate->replay_owner) {
+ nfs4_unlock_state();
nfs4_put_stateowner(cstate->replay_owner);
cstate->replay_owner = NULL;
}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index bc1a9db..6cf729a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3501,7 +3501,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

nfsd4_create_clid_dir(sop->so_client);
out:
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
}

@@ -3568,7 +3569,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
status = nfs_ok;
out:
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
}

@@ -3609,7 +3611,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (list_empty(&so->so_stateids))
move_to_close_lru(so);
out:
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
}

@@ -4071,7 +4074,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
out:
if (status && lock->lk_is_new && lock_sop)
release_lockowner(lock_sop);
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
}

--
1.7.4.1


2011-09-28 01:40:06

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic

On Tue, Sep 27, 2011 at 12:55:56PM -0400, Bryan Schumaker wrote:
> Hi Bruce,
>
> I'm getting the following warning that I was able to bisect to this patch:

Hm. Was it doing a LOCKU at the time, I wonder? It looks like I missed
a case here.... I'll investigate.

--b.

>
> [ 142.149710] ------------[ cut here ]------------
> [ 142.150014] WARNING: at kernel/mutex-debug.c:78 debug_mutex_unlock+0xda/0xe0()
> [ 142.150258] Hardware name: Bochs
> [ 142.150407] Modules linked in: md5 nfsd exportfs nfs lockd fscache auth_rpcgss nfs_acl sunrpc ipv6 ext2 snd_hda_intel snd_hda_codec snd_hwdep psmouse i2c_piix4 evdev serio_raw pcspkr virtio_balloon snd_pcm snd_timer snd soundcore snd_page_alloc floppy i2c_core button processor ext4 mbcache jbd2 crc16 pata_acpi uhci_hcd ata_piix libata usbcore scsi_mod virtio_net virtio_pci virtio_blk virtio virtio_ring
> [ 142.152927] Pid: 742, comm: nfsd Not tainted 3.1.0-rc1-SLIM+ #9
> [ 142.152927] Call Trace:
> [ 142.152927] [<ffffffff8105fa4f>] warn_slowpath_common+0x7f/0xc0
> [ 142.152927] [<ffffffff8105faaa>] warn_slowpath_null+0x1a/0x20
> [ 142.152927] [<ffffffff810960ca>] debug_mutex_unlock+0xda/0xe0
> [ 142.152927] [<ffffffff813e4200>] __mutex_unlock_slowpath+0x80/0x140
> [ 142.152927] [<ffffffff813e42ce>] mutex_unlock+0xe/0x10
> [ 142.152927] [<ffffffffa03bd3f5>] nfs4_lock_state+0x35/0x40 [nfsd]
> [ 142.152927] [<ffffffffa03b0b71>] nfsd4_proc_compound+0x2a1/0x690 [nfsd]
> [ 142.152927] [<ffffffffa039f9fb>] nfsd_dispatch+0xeb/0x230 [nfsd]
> [ 142.152927] [<ffffffffa02b1055>] svc_process_common+0x345/0x690 [sunrpc]
> [ 142.152927] [<ffffffff81058d10>] ? try_to_wake_up+0x280/0x280
> [ 142.152927] [<ffffffffa02b16e2>] svc_process+0x102/0x150 [sunrpc]
> [ 142.152927] [<ffffffffa039f0bd>] nfsd+0xbd/0x160 [nfsd]
> [ 142.152927] [<ffffffffa039f000>] ? 0xffffffffa039efff
> [ 142.152927] [<ffffffff8108230c>] kthread+0x8c/0xa0
> [ 142.152927] [<ffffffff813e8694>] kernel_thread_helper+0x4/0x10
> [ 142.152927] [<ffffffff81082280>] ? kthread_worker_fn+0x190/0x190
> [ 142.152927] [<ffffffff813e8690>] ? gs_change+0x13/0x13
> [ 142.152927] ---[ end trace 1b4070dc432138aa ]---
>
> I can duplicate it with this python script, the warning shows up on the server after (during?) the f.close() line:
>
> #!/usr/bin/python
> import sys
> import fcntl
> import struct
> import datetime
>
> f = open(sys.argv[1], 'rw+')
> print "Attempting to lock file:", sys.argv[1]
> lockreq = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
> rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockreq)
> raw_input("Press enter when you are ready to continue... ")
> f.close()
>
> - Bryan
>
> On 09/14/2011 07:44 AM, J. Bruce Fields wrote:
> > There are currently a couple races in the seqid replay code: a
> > retransmission could come while we're still encoding the original reply,
> > or a new seqid-mutating call could come as we're encoding a replay.
> >
> > So, extend the state lock over the encoding (both encoding of a replayed
> > reply and caching of the original encoded reply).
> >
> > I really hate doing this, and previously added the stateowner
> > reference-counting code to avoid it (which was insufficient)--but I
> > don't see a less complicated alternative at the moment.
> >
> > Signed-off-by: J. Bruce Fields <[email protected]>
> > ---
> > fs/nfsd/nfs4proc.c | 5 +++--
> > fs/nfsd/nfs4state.c | 12 ++++++++----
> > 2 files changed, 11 insertions(+), 6 deletions(-)
> >
> > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> > index 50bae74..50063a8 100644
> > --- a/fs/nfsd/nfs4proc.c
> > +++ b/fs/nfsd/nfs4proc.c
> > @@ -408,8 +408,8 @@ out:
> > if (open->op_stateowner) {
> > nfs4_get_stateowner(open->op_stateowner);
> > cstate->replay_owner = open->op_stateowner;
> > - }
> > - nfs4_unlock_state();
> > + } else
> > + nfs4_unlock_state();
> > return status;
> > }
> >
> > @@ -1227,6 +1227,7 @@ encode_op:
> > be32_to_cpu(status));
> >
> > if (cstate->replay_owner) {
> > + nfs4_unlock_state();
> > nfs4_put_stateowner(cstate->replay_owner);
> > cstate->replay_owner = NULL;
> > }
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index bc1a9db..6cf729a 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -3501,7 +3501,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> >
> > nfsd4_create_clid_dir(sop->so_client);
> > out:
> > - nfs4_unlock_state();
> > + if (!cstate->replay_owner)
> > + nfs4_unlock_state();
> > return status;
> > }
> >
> > @@ -3568,7 +3569,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
> > memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
> > status = nfs_ok;
> > out:
> > - nfs4_unlock_state();
> > + if (!cstate->replay_owner)
> > + nfs4_unlock_state();
> > return status;
> > }
> >
> > @@ -3609,7 +3611,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > if (list_empty(&so->so_stateids))
> > move_to_close_lru(so);
> > out:
> > - nfs4_unlock_state();
> > + if (!cstate->replay_owner)
> > + nfs4_unlock_state();
> > return status;
> > }
> >
> > @@ -4071,7 +4074,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > out:
> > if (status && lock->lk_is_new && lock_sop)
> > release_lockowner(lock_sop);
> > - nfs4_unlock_state();
> > + if (!cstate->replay_owner)
> > + nfs4_unlock_state();
> > return status;
> > }
> >
>

2011-09-14 11:45:28

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 16/25] nfsd4: pass around typemask instead of flags

We're only using those flags to choose lock or open stateid's at this
point.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 18 ++++++++----------
fs/nfsd/state.h | 2 --
2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ad20bbf..4813463 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1080,16 +1080,14 @@ static struct nfs4_stateid *find_stateid(stateid_t *t)
return NULL;
}

-static struct nfs4_stateid *find_stateid_by_type(stateid_t *t, int flags)
+static struct nfs4_stateid *find_stateid_by_type(stateid_t *t, char typemask)
{
struct nfs4_stateid *s;

s = find_stateid(t);
if (!s)
return NULL;
- if (flags & LOCK_STATE && s->st_type == NFS4_LOCK_STID)
- return s;
- if (flags & OPEN_STATE && s->st_type == NFS4_OPEN_STID)
+ if (typemask & s->st_type)
return s;
return NULL;
}
@@ -3445,7 +3443,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
*/
static __be32
nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
- stateid_t *stateid, int flags,
+ stateid_t *stateid, char typemask,
struct nfs4_stateid **stpp)
{
__be32 status;
@@ -3457,7 +3455,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
status = nfs4_nospecial_stateid_checks(stateid);
if (status)
return status;
- *stpp = find_stateid_by_type(stateid, flags);
+ *stpp = find_stateid_by_type(stateid, typemask);
if (*stpp == NULL)
return nfserr_expired;
cstate->replay_owner = (*stpp)->st_stateowner;
@@ -3472,7 +3470,7 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs
struct nfs4_openowner *oo;

status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
- OPEN_STATE, stpp);
+ NFS4_OPEN_STID, stpp);
if (status)
return status;
oo = openowner((*stpp)->st_stateowner);
@@ -3501,7 +3499,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

status = nfs4_preprocess_seqid_op(cstate,
oc->oc_seqid, &oc->oc_req_stateid,
- OPEN_STATE, &stp);
+ NFS4_OPEN_STID, &stp);
if (status)
goto out;
oo = openowner(stp->st_stateowner);
@@ -3999,7 +3997,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs4_preprocess_seqid_op(cstate,
lock->lk_old_lock_seqid,
&lock->lk_old_lock_stateid,
- LOCK_STATE, &lock_stp);
+ NFS4_LOCK_STID, &lock_stp);
if (status)
goto out;
lock_sop = lockowner(lock_stp->st_stateowner);
@@ -4197,7 +4195,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfs4_lock_state();

status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
- &locku->lu_stateid, LOCK_STATE, &stp);
+ &locku->lu_stateid, NFS4_LOCK_STID, &stp);
if (status)
goto out;
filp = find_any_file(stp->st_file);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 9745cc7..ef949eb 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -463,8 +463,6 @@ struct nfs4_stateid {
};

/* flags for preprocess_seqid_op() */
-#define OPEN_STATE 0x00000004
-#define LOCK_STATE 0x00000008
#define RD_STATE 0x00000010
#define WR_STATE 0x00000020

--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 09/25] nfsd4: move double-confirm test to open_confirm

I don't see the point of having this check in nfs4_preprocess_seqid_op()
when it's only needed by the one caller.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 12 +++++-------
1 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8694e60..9c44630 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3434,11 +3434,6 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
if (status)
return status;

- if (sop->so_confirmed && flags & CONFIRM) {
- dprintk("NFSD: preprocess_seqid_op: expected"
- " unconfirmed stateowner!\n");
- return nfserr_bad_stateid;
- }
if (!sop->so_confirmed && !(flags & CONFIRM)) {
dprintk("NFSD: preprocess_seqid_op: stateowner not"
" confirmed yet!\n");
@@ -3473,9 +3468,11 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
oc->oc_seqid, &oc->oc_req_stateid,
CONFIRM | OPEN_STATE, &stp);
if (status)
- goto out;
-
+ goto out;
sop = stp->st_stateowner;
+ status = nfserr_bad_stateid;
+ if (sop->so_confirmed)
+ goto out;
sop->so_confirmed = 1;
update_stateid(&stp->st_stateid);
memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
@@ -3483,6 +3480,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stateid));

nfsd4_create_clid_dir(sop->so_client);
+ status = nfs_ok;
out:
if (!cstate->replay_owner)
nfs4_unlock_state();
--
1.7.4.1


2011-09-27 16:10:09

by Anna Schumaker

[permalink] [raw]
Subject: Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

On 09/19/2011 09:15 AM, J. Bruce Fields wrote:
> Including the full clientid in the on-the-wire stateid allows more
> reliable detection of bad vs. expired stateid's, simplifies code, and
> ensures we won't reuse the opaque part of the stateid (as we currently
> do when the same openowner closes and reopens the same file).
>
> Signed-off-by: J. Bruce Fields <[email protected]>
> ---
> fs/nfsd/nfs4state.c | 58 +++++++++++---------------------------------------
> fs/nfsd/state.h | 18 ++++-----------
> 2 files changed, 18 insertions(+), 58 deletions(-)
>
[ ... ]
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index e807abb..d6aec4f 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -353,11 +349,9 @@ struct nfs4_replay {
> */
>
> struct nfs4_stateowner {

The comment describing this struct should probably be updated since so_idhash and a few other variables no longer exist.

- Bryan

> - struct list_head so_idhash; /* hash by so_id */
> struct list_head so_strhash; /* hash by op_name */
> struct list_head so_stateids;
> int so_is_open_owner; /* 1=openowner,0=lockowner */
> - u32 so_id;
> struct nfs4_client * so_client;
> /* after increment in ENCODE_SEQID_OP_TAIL, represents the next
> * sequence id expected from the client: */
> @@ -415,8 +409,6 @@ struct nfs4_file {
> struct file_lock *fi_lease;
> atomic_t fi_delegees;
> struct inode *fi_inode;
> - u32 fi_id; /* used with stateowner->so_id
> - * for stateid_hashtbl hash */
> bool fi_had_conflict;
> };
>


2011-09-26 22:39:45

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 4/4] nfsd4: look up stateid's per clientid

Use a separate stateid idr per client, and lookup a stateid by first
finding the client, then looking up the stateid relative to that client.

Also some minor refactoring.

This allows us to improve error returns: we can return expired when the
clientid is not found and bad_stateid when the clientid is found but not
the stateid, as opposed to returning expired for both cases.

I hope this will also help to replace the state lock mostly by a
per-client lock, but that hasn't been done yet.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 112 ++++++++++++++++++++++----------------------------
fs/nfsd/nfs4xdr.c | 3 +-
fs/nfsd/state.h | 4 +-
3 files changed, 54 insertions(+), 65 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index daf75fa..931155f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -32,7 +32,6 @@
*
*/

-#include <linux/idr.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/slab.h>
@@ -149,8 +148,6 @@ static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
#define FILE_HASH_BITS 8
#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)

-struct idr stateids;
-
static unsigned int file_hashval(struct inode *ino)
{
/* XXX: why are we hashing on inode pointer, anyway? */
@@ -209,13 +206,14 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
static inline int get_new_stid(struct nfs4_stid *stid)
{
static int min_stateid = 0;
+ struct idr *stateids = &stid->sc_client->cl_stateids;
int new_stid;
int error;

- if (!idr_pre_get(&stateids, GFP_KERNEL))
+ if (!idr_pre_get(stateids, GFP_KERNEL))
return -ENOMEM;

- error = idr_get_new_above(&stateids, stid, min_stateid, &new_stid);
+ error = idr_get_new_above(stateids, stid, min_stateid, &new_stid);
/*
* All this code is currently serialized; the preallocation
* above should still be ours:
@@ -324,7 +322,9 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp)

static void unhash_stid(struct nfs4_stid *s)
{
- idr_remove(&stateids, s->sc_stateid.si_opaque.so_id);
+ struct idr *stateids = &s->sc_client->cl_stateids;
+
+ idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
}

/* Called under the state lock. */
@@ -1126,16 +1126,16 @@ static void gen_confirm(struct nfs4_client *clp)
*p++ = i++;
}

-static struct nfs4_stid *find_stateid(stateid_t *t)
+static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
{
- return idr_find(&stateids, t->si_opaque.so_id);
+ return idr_find(&cl->cl_stateids, t->si_opaque.so_id);
}

-static struct nfs4_stid *find_stateid_by_type(stateid_t *t, char typemask)
+static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
{
struct nfs4_stid *s;

- s = find_stateid(t);
+ s = find_stateid(cl, t);
if (!s)
return NULL;
if (typemask & s->sc_type)
@@ -1143,16 +1143,6 @@ static struct nfs4_stid *find_stateid_by_type(stateid_t *t, char typemask)
return NULL;
}

-static struct nfs4_ol_stateid *find_ol_stateid_by_type(stateid_t *t, char typemask)
-{
- struct nfs4_stid *s;
-
- s = find_stateid_by_type(t, typemask);
- if (!s)
- return NULL;
- return openlockstateid(s);
-}
-
static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
struct svc_rqst *rqstp, nfs4_verifier *verf)
{
@@ -1175,6 +1165,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
}
}

+ idr_init(&clp->cl_stateids);
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_refcount, 0);
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
@@ -2611,24 +2602,24 @@ static int share_access_to_flags(u32 share_access)
return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
}

-static struct nfs4_delegation *find_deleg_stateid(stateid_t *s)
+static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
{
struct nfs4_stid *ret;

- ret = find_stateid_by_type(s, NFS4_DELEG_STID);
+ ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
if (!ret)
return NULL;
return delegstateid(ret);
}

static __be32
-nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
+nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open *open,
struct nfs4_delegation **dp)
{
int flags;
__be32 status = nfserr_bad_stateid;

- *dp = find_deleg_stateid(&open->op_delegate_stateid);
+ *dp = find_deleg_stateid(cl, &open->op_delegate_stateid);
if (*dp == NULL)
goto out;
flags = share_access_to_flags(open->op_share_access);
@@ -2920,6 +2911,7 @@ __be32
nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct nfsd4_compoundres *resp = rqstp->rq_resp;
+ struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
struct nfs4_file *fp = NULL;
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_ol_stateid *stp = NULL;
@@ -2939,7 +2931,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
if (fp) {
if ((status = nfs4_check_open(fp, open, &stp)))
goto out;
- status = nfs4_check_deleg(fp, open, &dp);
+ status = nfs4_check_deleg(cl, fp, open, &dp);
if (status)
goto out;
} else {
@@ -3256,7 +3248,7 @@ static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_sess
return nfserr_old_stateid;
}

-__be32 nfs4_validate_stateid(stateid_t *stateid)
+__be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
{
struct nfs4_stid *s;
struct nfs4_ol_stateid *ols;
@@ -3265,7 +3257,7 @@ __be32 nfs4_validate_stateid(stateid_t *stateid)
if (STALE_STATEID(stateid))
return nfserr_stale_stateid;

- s = find_stateid(stateid);
+ s = find_stateid(cl, stateid);
if (!s)
return nfserr_stale_stateid;
status = check_stateid_generation(stateid, &s->sc_stateid, 1);
@@ -3280,6 +3272,24 @@ __be32 nfs4_validate_stateid(stateid_t *stateid)
return nfs_ok;
}

+static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s)
+{
+ struct nfs4_client *cl;
+
+ if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+ return nfserr_bad_stateid;
+ if (STALE_STATEID(stateid))
+ return nfserr_stale_stateid;
+ cl = find_confirmed_client(&stateid->si_opaque.so_clid);
+ if (!cl)
+ return nfserr_expired;
+ *s = find_stateid_by_type(cl, stateid, typemask);
+ if (!*s)
+ return nfserr_bad_stateid;
+ return nfs_ok;
+
+}
+
/*
* Checks for stateid operations
*/
@@ -3303,18 +3313,9 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
return check_special_stateids(current_fh, stateid, flags);

- status = nfserr_stale_stateid;
- if (STALE_STATEID(stateid))
- goto out;
-
- /*
- * We assume that any stateid that has the current boot time,
- * but that we can't find, is expired:
- */
- status = nfserr_expired;
- s = find_stateid(stateid);
- if (!s)
- goto out;
+ status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s);
+ if (status)
+ return status;
status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
@@ -3384,10 +3385,11 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
stateid_t *stateid = &free_stateid->fr_stateid;
struct nfs4_stid *s;
+ struct nfs4_client *cl = cstate->session->se_client;
__be32 ret = nfserr_bad_stateid;

nfs4_lock_state();
- s = find_stateid(stateid);
+ s = find_stateid(cl, stateid);
if (!s)
goto out;
switch (s->sc_type) {
@@ -3419,15 +3421,6 @@ setlkflg (int type)
RD_STATE : WR_STATE;
}

-static __be32 nfs4_nospecial_stateid_checks(stateid_t *stateid)
-{
- if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
- return nfserr_bad_stateid;
- if (STALE_STATEID(stateid))
- return nfserr_stale_stateid;
- return nfs_ok;
-}
-
static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
{
struct svc_fh *current_fh = &cstate->current_fh;
@@ -3458,17 +3451,16 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
struct nfs4_ol_stateid **stpp)
{
__be32 status;
+ struct nfs4_stid *s;

dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
seqid, STATEID_VAL(stateid));

*stpp = NULL;
- status = nfs4_nospecial_stateid_checks(stateid);
+ status = nfsd4_lookup_stateid(stateid, typemask, &s);
if (status)
return status;
- *stpp = find_ol_stateid_by_type(stateid, typemask);
- if (*stpp == NULL)
- return nfserr_expired;
+ *stpp = openlockstateid(s);
cstate->replay_owner = (*stpp)->st_stateowner;
renew_client((*stpp)->st_stateowner->so_client);

@@ -3673,6 +3665,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
struct nfs4_delegation *dp;
stateid_t *stateid = &dr->dr_stateid;
+ struct nfs4_stid *s;
struct inode *inode;
__be32 status;

@@ -3681,16 +3674,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
inode = cstate->current_fh.fh_dentry->d_inode;

nfs4_lock_state();
- status = nfserr_bad_stateid;
- if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
- goto out;
- status = nfserr_stale_stateid;
- if (STALE_STATEID(stateid))
- goto out;
- status = nfserr_expired;
- dp = find_deleg_stateid(stateid);
- if (!dp)
+ status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s);
+ if (status)
goto out;
+ dp = delegstateid(s);
status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
@@ -4409,7 +4396,6 @@ nfs4_state_init(void)
for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
}
- idr_init(&stateids);
for (i = 0; i < LOCK_HASH_SIZE; i++) {
INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 2429fff..5779acd 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3287,6 +3287,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
struct nfsd4_test_stateid *test_stateid)
{
struct nfsd4_compoundargs *argp;
+ struct nfs4_client *cl = resp->cstate.session->se_client;
stateid_t si;
__be32 *p;
int i;
@@ -3302,7 +3303,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
nfs4_lock_state();
for (i = 0; i < test_stateid->ts_num_ids; i++) {
nfsd4_decode_stateid(argp, &si);
- valid = nfs4_validate_stateid(&si);
+ valid = nfs4_validate_stateid(cl, &si);
RESERVE_SPACE(4);
*p++ = htonl(valid);
resp->p = p;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 55a4d6a..13f6f9f 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -35,6 +35,7 @@
#ifndef _NFSD4_STATE_H
#define _NFSD4_STATE_H

+#include <linux/idr.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/nfsd/nfsfh.h>
#include "nfsfh.h"
@@ -231,6 +232,7 @@ struct nfs4_client {
struct list_head cl_idhash; /* hash by cl_clientid.id */
struct list_head cl_strhash; /* hash by cl_name */
struct list_head cl_openowners;
+ struct idr cl_stateids; /* stateid lookup */
struct list_head cl_delegations;
struct list_head cl_lru; /* tail queue */
struct xdr_netobj cl_name; /* id generated by client */
@@ -508,7 +510,7 @@ extern void nfsd4_recdir_purge_old(void);
extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
extern void release_session_client(struct nfsd4_session *);
-extern __be32 nfs4_validate_stateid(stateid_t *);
+extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);

#endif /* NFSD4_STATE_H */
--
1.7.4.1


2011-09-26 22:39:45

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 1/4] nfsd4: move client * to nfs4_stateid, add init_stid helper

This will be convenient.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4callback.c | 8 ++++----
fs/nfsd/nfs4state.c | 48 ++++++++++++++++++++++++++----------------------
fs/nfsd/state.h | 2 +-
3 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 93b5e40..de018ec 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -787,7 +787,7 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
{
struct nfsd4_callback *cb = calldata;
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_client;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
u32 minorversion = clp->cl_minorversion;

cb->cb_minorversion = minorversion;
@@ -809,7 +809,7 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
{
struct nfsd4_callback *cb = calldata;
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_client;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;

dprintk("%s: minorversion=%d\n", __func__,
clp->cl_minorversion);
@@ -832,7 +832,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
{
struct nfsd4_callback *cb = calldata;
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_client;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
struct rpc_clnt *current_rpc_client = clp->cl_cb_client;

nfsd4_cb_done(task, calldata);
@@ -1006,7 +1006,7 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
void nfsd4_cb_recall(struct nfs4_delegation *dp)
{
struct nfsd4_callback *cb = &dp->dl_recall;
- struct nfs4_client *clp = dp->dl_client;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;

dp->dl_retries = 1;
cb->cb_op = dp;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index edcced1..cb36c9a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -224,6 +224,19 @@ static inline void hash_stid(struct nfs4_stid *stid)
list_add(&stid->sc_hash, &stateid_hashtbl[hashval]);
}

+static void init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type)
+{
+ stateid_t *s = &stid->sc_stateid;
+
+ stid->sc_type = type;
+ stid->sc_client = cl;
+ s->si_opaque.so_clid = cl->cl_clientid;
+ s->si_opaque.so_id = current_stateid++;
+ /* Will be incremented before return to client: */
+ s->si_generation = 0;
+ hash_stid(stid);
+}
+
static struct nfs4_delegation *
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
{
@@ -245,19 +258,20 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
if (dp == NULL)
return dp;
+ init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID);
+ /*
+ * delegation seqid's are never incremented. The 4.1 special
+ * meaning of seqid 0 isn't really meaningful, really, but let's
+ * avoid 0 anyway just for consistency and use 1:
+ */
+ dp->dl_stid.sc_stateid.si_generation = 1;
num_delegations++;
INIT_LIST_HEAD(&dp->dl_perfile);
INIT_LIST_HEAD(&dp->dl_perclnt);
INIT_LIST_HEAD(&dp->dl_recall_lru);
- dp->dl_client = clp;
get_nfs4_file(fp);
dp->dl_file = fp;
dp->dl_type = type;
- dp->dl_stid.sc_type = NFS4_DELEG_STID;
- dp->dl_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
- dp->dl_stid.sc_stateid.si_opaque.so_id = current_stateid++;
- dp->dl_stid.sc_stateid.si_generation = 1;
- hash_stid(&dp->dl_stid);
fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
dp->dl_time = 0;
atomic_set(&dp->dl_count, 1);
@@ -2333,18 +2347,13 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd
struct nfs4_openowner *oo = open->op_openowner;
struct nfs4_client *clp = oo->oo_owner.so_client;

+ init_stid(&stp->st_stid, clp, NFS4_OPEN_STID);
INIT_LIST_HEAD(&stp->st_lockowners);
list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
list_add(&stp->st_perfile, &fp->fi_stateids);
- stp->st_stid.sc_type = NFS4_OPEN_STID;
stp->st_stateowner = &oo->oo_owner;
get_nfs4_file(fp);
stp->st_file = fp;
- stp->st_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
- stp->st_stid.sc_stateid.si_opaque.so_id = current_stateid++;
- /* note will be incremented before first return to client: */
- stp->st_stid.sc_stateid.si_generation = 0;
- hash_stid(&stp->st_stid);
stp->st_access_bmap = 0;
stp->st_deny_bmap = 0;
__set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK,
@@ -2792,7 +2801,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
if (!fl)
return -ENOMEM;
fl->fl_file = find_readable_file(fp);
- list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+ list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
if (status) {
list_del_init(&dp->dl_perclnt);
@@ -2821,7 +2830,7 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
atomic_inc(&fp->fi_delegees);
list_add(&dp->dl_perfile, &fp->fi_delegations);
spin_unlock(&recall_lock);
- list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+ list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
return 0;
}

@@ -3295,7 +3304,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
status = nfs4_check_delegmode(dp, flags);
if (status)
goto out;
- renew_client(dp->dl_client);
+ renew_client(dp->dl_stid.sc_client);
if (filpp) {
*filpp = dp->dl_file->fi_deleg_file;
BUG_ON(!*filpp);
@@ -3665,7 +3674,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
- renew_client(dp->dl_client);
+ renew_client(dp->dl_stid.sc_client);

unhash_delegation(dp);
out:
@@ -3819,17 +3828,12 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
stp = nfs4_alloc_stateid();
if (stp == NULL)
goto out;
+ init_stid(&stp->st_stid, clp, NFS4_LOCK_STID);
list_add(&stp->st_perfile, &fp->fi_stateids);
list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
stp->st_stateowner = &lo->lo_owner;
- stp->st_stid.sc_type = NFS4_LOCK_STID;
get_nfs4_file(fp);
stp->st_file = fp;
- stp->st_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
- stp->st_stid.sc_stateid.si_opaque.so_id = current_stateid++;
- /* note will be incremented before first return to client: */
- stp->st_stid.sc_stateid.si_generation = 0;
- hash_stid(&stp->st_stid);
stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index da68bf6..70062b7 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -81,6 +81,7 @@ struct nfs4_stid {
unsigned char sc_type;
struct list_head sc_hash;
stateid_t sc_stateid;
+ struct nfs4_client *sc_client;
};

struct nfs4_delegation {
@@ -88,7 +89,6 @@ struct nfs4_delegation {
struct list_head dl_perclnt;
struct list_head dl_recall_lru; /* delegation recalled */
atomic_t dl_count; /* ref count */
- struct nfs4_client *dl_client;
struct nfs4_file *dl_file;
u32 dl_type;
time_t dl_time;
--
1.7.4.1


2011-09-14 11:45:30

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 25/25] nfsd4: better stateid hashing

First, we shouldn't care here about the structure of the opaque part of
the stateid. Second, this hash is really dumb. (I'm not sure the
replacement is much better, though--to look at it another patch.)

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ea338d0..0cd3464 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -168,9 +168,9 @@ static unsigned int file_hashval(struct inode *ino)
return hash_ptr(ino, FILE_HASH_BITS);
}

-static unsigned int stateid_hashval(u32 owner_id, u32 file_id)
+static unsigned int stateid_hashval(stateid_t *s)
{
- return (owner_id + file_id) & STATEID_HASH_MASK;
+ return opaque_hashval(&s->si_opaque, sizeof(stateid_opaque_t)) & STATEID_HASH_MASK;
}

static struct list_head file_hashtbl[FILE_HASH_SIZE];
@@ -221,7 +221,7 @@ static inline void hash_stid(struct nfs4_stid *stid)
stateid_t *s = &stid->sc_stateid;
unsigned int hashval;

- hashval = stateid_hashval(s->si_stateownerid, s->si_fileid);
+ hashval = stateid_hashval(s);
list_add(&stid->sc_hash, &stateid_hashtbl[hashval]);
}

@@ -1083,7 +1083,7 @@ static struct nfs4_stid *find_stateid(stateid_t *t)
struct nfs4_stid *s;
unsigned int hashval;

- hashval = stateid_hashval(t->si_stateownerid, t->si_fileid);
+ hashval = stateid_hashval(t);
list_for_each_entry(s, &stateid_hashtbl[hashval], sc_hash)
if (same_stateid(&s->sc_stateid, t))
return s;
--
1.7.4.1


2011-09-26 22:39:45

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 2/4] nfsd4: use idr for stateid's

The idr system is designed exactly for generating id and looking up
integer id's. Thanks to Trond for pointing it out.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 124 ++++++++++++++++++++++++++++++---------------------
fs/nfsd/state.h | 1 -
2 files changed, 73 insertions(+), 52 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index cb36c9a..a9e71cd 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -32,6 +32,7 @@
*
*/

+#include <linux/idr.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/slab.h>
@@ -49,7 +50,6 @@
time_t nfsd4_lease = 90; /* default lease time */
time_t nfsd4_grace = 90;
static time_t boot_time;
-static u32 current_stateid = 1;
static stateid_t zerostateid; /* bits all 0 */
static stateid_t onestateid; /* bits all 1 */
static u64 current_sessionid = 1;
@@ -149,10 +149,7 @@ static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
#define FILE_HASH_BITS 8
#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)

-/* hash table for (open)nfs4_ol_stateid */
-#define STATEID_HASH_BITS 10
-#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
-#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
+struct idr stateids;

static unsigned int file_hashval(struct inode *ino)
{
@@ -160,13 +157,7 @@ static unsigned int file_hashval(struct inode *ino)
return hash_ptr(ino, FILE_HASH_BITS);
}

-static unsigned int stateid_hashval(stateid_t *s)
-{
- return opaque_hashval(&s->si_opaque, sizeof(stateid_opaque_t)) & STATEID_HASH_MASK;
-}
-
static struct list_head file_hashtbl[FILE_HASH_SIZE];
-static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];

static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
{
@@ -215,26 +206,52 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
__nfs4_file_put_access(fp, oflag);
}

-static inline void hash_stid(struct nfs4_stid *stid)
+static inline int get_new_stid(struct nfs4_stid *stid)
{
- stateid_t *s = &stid->sc_stateid;
- unsigned int hashval;
+ static int min_stateid = 0;
+ int new_stid;
+ int error;
+
+ if (!idr_pre_get(&stateids, GFP_KERNEL))
+ return -ENOMEM;
+
+ error = idr_get_new_above(&stateids, stid, min_stateid, &new_stid);
+ /*
+ * All this code is currently serialized; the preallocation
+ * above should still be ours:
+ */
+ BUG_ON(error);
+ /*
+ * It shouldn't be a problem to reuse an opaque stateid value.
+ * I don't think it is for 4.1. But with 4.0 I worry that, for
+ * example, a stray write retransmission could be accepted by
+ * the server when it should have been rejected. Therefore,
+ * adopt a trick from the sctp code to attempt to maximize the
+ * amount of time until an id is reused, by ensuring they always
+ * "increase" (mod INT_MAX):
+ */

- hashval = stateid_hashval(s);
- list_add(&stid->sc_hash, &stateid_hashtbl[hashval]);
+ min_stateid = new_stid+1;
+ if (min_stateid == INT_MAX)
+ min_stateid = 0;
+ return new_stid;
}

-static void init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type)
+static inline __be32 init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type)
{
stateid_t *s = &stid->sc_stateid;
+ int new_id;

stid->sc_type = type;
stid->sc_client = cl;
s->si_opaque.so_clid = cl->cl_clientid;
- s->si_opaque.so_id = current_stateid++;
+ new_id = get_new_stid(stid);
+ if (new_id < 0)
+ return nfserr_jukebox;
+ s->si_opaque.so_id = (u32)new_id;
/* Will be incremented before return to client: */
s->si_generation = 0;
- hash_stid(stid);
+ return 0;
}

static struct nfs4_delegation *
@@ -242,6 +259,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
{
struct nfs4_delegation *dp;
struct nfs4_file *fp = stp->st_file;
+ __be32 status;

dprintk("NFSD alloc_init_deleg\n");
/*
@@ -258,11 +276,15 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
if (dp == NULL)
return dp;
- init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID);
+ status = init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID);
+ if (status) {
+ kmem_cache_free(deleg_slab, dp);
+ return NULL;
+ }
/*
* delegation seqid's are never incremented. The 4.1 special
- * meaning of seqid 0 isn't really meaningful, really, but let's
- * avoid 0 anyway just for consistency and use 1:
+ * meaning of seqid 0 isn't meaningful, really, but let's avoid
+ * 0 anyway just for consistency and use 1:
*/
dp->dl_stid.sc_stateid.si_generation = 1;
num_delegations++;
@@ -300,11 +322,16 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp)
}
}

+static void unhash_stid(struct nfs4_stid *s)
+{
+ idr_remove(&stateids, s->sc_stateid.si_opaque.so_id);
+}
+
/* Called under the state lock. */
static void
unhash_delegation(struct nfs4_delegation *dp)
{
- list_del_init(&dp->dl_stid.sc_hash);
+ unhash_stid(&dp->dl_stid);
list_del_init(&dp->dl_perclnt);
spin_lock(&recall_lock);
list_del_init(&dp->dl_perfile);
@@ -457,7 +484,7 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)
struct file *file;

unhash_generic_stateid(stp);
- list_del(&stp->st_stid.sc_hash);
+ unhash_stid(&stp->st_stid);
file = find_any_file(stp->st_file);
if (file)
locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
@@ -506,7 +533,7 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
static void release_open_stateid(struct nfs4_ol_stateid *stp)
{
unhash_open_stateid(stp);
- list_del(&stp->st_stid.sc_hash);
+ unhash_stid(&stp->st_stid);
free_generic_stateid(stp);
}

@@ -528,7 +555,7 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;

if (s) {
- list_del_init(&s->st_stid.sc_hash);
+ unhash_stid(&s->st_stid);
free_generic_stateid(s);
oo->oo_last_closed_stid = NULL;
}
@@ -1099,23 +1126,9 @@ static void gen_confirm(struct nfs4_client *clp)
*p++ = i++;
}

-static int
-same_stateid(stateid_t *id_one, stateid_t *id_two)
-{
- return 0 == memcmp(&id_one->si_opaque, &id_two->si_opaque,
- sizeof(stateid_opaque_t));
-}
-
static struct nfs4_stid *find_stateid(stateid_t *t)
{
- struct nfs4_stid *s;
- unsigned int hashval;
-
- hashval = stateid_hashval(t);
- list_for_each_entry(s, &stateid_hashtbl[hashval], sc_hash)
- if (same_stateid(&s->sc_stateid, t))
- return s;
- return NULL;
+ return idr_find(&stateids, t->si_opaque.so_id);
}

static struct nfs4_stid *find_stateid_by_type(stateid_t *t, char typemask)
@@ -2342,12 +2355,14 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
return oo;
}

-static inline void
-init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
+static inline __be32 init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
struct nfs4_openowner *oo = open->op_openowner;
struct nfs4_client *clp = oo->oo_owner.so_client;
+ __be32 status;

- init_stid(&stp->st_stid, clp, NFS4_OPEN_STID);
+ status = init_stid(&stp->st_stid, clp, NFS4_OPEN_STID);
+ if (status)
+ return status;
INIT_LIST_HEAD(&stp->st_lockowners);
list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
list_add(&stp->st_perfile, &fp->fi_stateids);
@@ -2360,6 +2375,7 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd
&stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
stp->st_openstp = NULL;
+ return nfs_ok;
}

static void
@@ -2949,7 +2965,11 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs4_new_open(rqstp, &stp, fp, current_fh, open);
if (status)
goto out;
- init_open_stateid(stp, fp, open);
+ status = init_open_stateid(stp, fp, open);
+ if (status) {
+ release_open_stateid(stp);
+ goto out;
+ }
status = nfsd4_truncate(rqstp, current_fh, open);
if (status) {
release_open_stateid(stp);
@@ -3824,11 +3844,16 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
{
struct nfs4_ol_stateid *stp;
struct nfs4_client *clp = lo->lo_owner.so_client;
+ __be32 status;

stp = nfs4_alloc_stateid();
if (stp == NULL)
- goto out;
- init_stid(&stp->st_stid, clp, NFS4_LOCK_STID);
+ return NULL;
+ status = init_stid(&stp->st_stid, clp, NFS4_LOCK_STID);
+ if (status) {
+ free_generic_stateid(stp);
+ return NULL;
+ }
list_add(&stp->st_perfile, &fp->fi_stateids);
list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
stp->st_stateowner = &lo->lo_owner;
@@ -3837,8 +3862,6 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;
-
-out:
return stp;
}

@@ -4386,8 +4409,7 @@ nfs4_state_init(void)
for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
}
- for (i = 0; i < STATEID_HASH_SIZE; i++)
- INIT_LIST_HEAD(&stateid_hashtbl[i]);
+ idr_init(&stateids);
for (i = 0; i < LOCK_HASH_SIZE; i++) {
INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 70062b7..3ed5f99 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -79,7 +79,6 @@ struct nfs4_stid {
/* For an open stateid kept around *only* to process close replays: */
#define NFS4_CLOSED_STID 8
unsigned char sc_type;
- struct list_head sc_hash;
stateid_t sc_stateid;
struct nfs4_client *sc_client;
};
--
1.7.4.1


2011-09-14 11:45:28

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 17/25] nfsd4: rename init_stateid

Note this is actually open-stateid specific.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 4813463..73b5e1e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2314,7 +2314,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
}

static inline void
-init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
+init_open_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
struct nfs4_openowner *oo = open->op_openowner;
unsigned int hashval = stateid_hashval(oo->oo_owner.so_id, fp->fi_id);

@@ -2934,7 +2934,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs4_new_open(rqstp, &stp, fp, current_fh, open);
if (status)
goto out;
- init_stateid(stp, fp, open);
+ init_open_stateid(stp, fp, open);
status = nfsd4_truncate(rqstp, current_fh, open);
if (status) {
release_open_stateid(stp);
--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 01/25] nfsd4: centralize handling of replay owners

Set the stateowner associated with a replay in one spot in
nfs4_preprocess_seqid_op() and keep it in cstate. This allows removing
a few lines of boilerplate from all the nfs4_preprocess_seqid_op()
callers.

Also turn ENCODE_SEQID_OP_TAIL into a function while we're here.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 25 ++++---------------------
fs/nfsd/nfs4xdr.c | 34 +++++++++++++++++++---------------
2 files changed, 23 insertions(+), 36 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 80af79e..e4535ff 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3425,12 +3425,15 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
/* It's not stale; let's assume it's expired: */
if (sop == NULL)
return nfserr_expired;
- *sopp = sop;
+ nfs4_get_stateowner(sop);
+ cstate->replay_owner = sop;
goto check_replay;
}

*stpp = stp;
*sopp = sop = stp->st_stateowner;
+ nfs4_get_stateowner(sop);
+ cstate->replay_owner = sop;

if (nfs4_check_fh(current_fh, stp)) {
dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
@@ -3501,10 +3504,6 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

nfsd4_create_clid_dir(sop->so_client);
out:
- if (oc->oc_stateowner) {
- nfs4_get_stateowner(oc->oc_stateowner);
- cstate->replay_owner = oc->oc_stateowner;
- }
nfs4_unlock_state();
return status;
}
@@ -3574,10 +3573,6 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
status = nfs_ok;
out:
- if (od->od_stateowner) {
- nfs4_get_stateowner(od->od_stateowner);
- cstate->replay_owner = od->od_stateowner;
- }
nfs4_unlock_state();
return status;
}
@@ -3618,10 +3613,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (list_empty(&close->cl_stateowner->so_stateids))
move_to_close_lru(close->cl_stateowner);
out:
- if (close->cl_stateowner) {
- nfs4_get_stateowner(close->cl_stateowner);
- cstate->replay_owner = close->cl_stateowner;
- }
nfs4_unlock_state();
return status;
}
@@ -4086,10 +4077,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
out:
if (status && lock->lk_is_new && lock_sop)
release_lockowner(lock_sop);
- if (lock->lk_replay_owner) {
- nfs4_get_stateowner(lock->lk_replay_owner);
- cstate->replay_owner = lock->lk_replay_owner;
- }
nfs4_unlock_state();
return status;
}
@@ -4244,10 +4231,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));

out:
- if (locku->lu_stateowner) {
- nfs4_get_stateowner(locku->lu_stateowner);
- cstate->replay_owner = locku->lu_stateowner;
- }
nfs4_unlock_state();
return status;

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index f982d85..ee12678 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1630,15 +1630,19 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c)
* we know whether the error to be returned is a sequence id mutating error.
*/

-#define ENCODE_SEQID_OP_TAIL(stateowner) do { \
- if (seqid_mutating_err(ntohl(nfserr)) && stateowner) { \
- stateowner->so_seqid++; \
- stateowner->so_replay.rp_status = nfserr; \
- stateowner->so_replay.rp_buflen = \
- (((char *)(resp)->p - (char *)save)); \
- memcpy(stateowner->so_replay.rp_buf, save, \
- stateowner->so_replay.rp_buflen); \
- } } while (0);
+static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, __be32 nfserr)
+{
+ struct nfs4_stateowner *stateowner = resp->cstate.replay_owner;
+
+ if (seqid_mutating_err(ntohl(nfserr)) && stateowner) {
+ stateowner->so_seqid++;
+ stateowner->so_replay.rp_status = nfserr;
+ stateowner->so_replay.rp_buflen =
+ (char *)resp->p - (char *)save;
+ memcpy(stateowner->so_replay.rp_buf, save,
+ stateowner->so_replay.rp_buflen);
+ }
+}

/* Encode as an array of strings the string given with components
* separated @sep.
@@ -2495,7 +2499,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
if (!nfserr)
nfsd4_encode_stateid(resp, &close->cl_stateid);

- ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}

@@ -2599,7 +2603,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
else if (nfserr == nfserr_denied)
nfsd4_encode_lock_denied(resp, &lock->lk_denied);

- ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}

@@ -2619,7 +2623,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
if (!nfserr)
nfsd4_encode_stateid(resp, &locku->lu_stateid);

- ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}

@@ -2700,7 +2704,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
}
/* XXX save filehandle here */
out:
- ENCODE_SEQID_OP_TAIL(open->op_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}

@@ -2712,7 +2716,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct
if (!nfserr)
nfsd4_encode_stateid(resp, &oc->oc_resp_stateid);

- ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}

@@ -2724,7 +2728,7 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
if (!nfserr)
nfsd4_encode_stateid(resp, &od->od_stateid);

- ENCODE_SEQID_OP_TAIL(od->od_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}

--
1.7.4.1


2011-09-28 01:49:32

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic

On Tue, Sep 27, 2011 at 12:55:56PM -0400, Bryan Schumaker wrote:
> I'm getting the following warning that I was able to bisect to this patch:

I suspect this may fix it. (Untested.)

--b.

commit 8da87285a245c82d23183414cec7069f18721afd
Author: J. Bruce Fields <[email protected]>
Date: Tue Sep 27 21:42:29 2011 -0400

nfsd4: fix state lock usage in LOCKU

In commit 5ec094c1096ab3bb795651855d53f18daa26afde "nfsd4: extend state
lock over seqid replay logic" I modified the exit logic of all the
seqid-based procedures except nfsd4_locku(). Fix the oversight.

The result of the bug was a double-unlock while handling the LOCKU
procedure, and a warning like:

[ 142.150014] WARNING: at kernel/mutex-debug.c:78 debug_mutex_unlock+0xda/0xe0()
...
[ 142.152927] Pid: 742, comm: nfsd Not tainted 3.1.0-rc1-SLIM+ #9
[ 142.152927] Call Trace:
[ 142.152927] [<ffffffff8105fa4f>] warn_slowpath_common+0x7f/0xc0
[ 142.152927] [<ffffffff8105faaa>] warn_slowpath_null+0x1a/0x20
[ 142.152927] [<ffffffff810960ca>] debug_mutex_unlock+0xda/0xe0
[ 142.152927] [<ffffffff813e4200>] __mutex_unlock_slowpath+0x80/0x140
[ 142.152927] [<ffffffff813e42ce>] mutex_unlock+0xe/0x10
[ 142.152927] [<ffffffffa03bd3f5>] nfs4_lock_state+0x35/0x40 [nfsd]
[ 142.152927] [<ffffffffa03b0b71>] nfsd4_proc_compound+0x2a1/0x690
[nfsd]
[ 142.152927] [<ffffffffa039f9fb>] nfsd_dispatch+0xeb/0x230 [nfsd]
[ 142.152927] [<ffffffffa02b1055>] svc_process_common+0x345/0x690
[sunrpc]
[ 142.152927] [<ffffffff81058d10>] ? try_to_wake_up+0x280/0x280
[ 142.152927] [<ffffffffa02b16e2>] svc_process+0x102/0x150 [sunrpc]
[ 142.152927] [<ffffffffa039f0bd>] nfsd+0xbd/0x160 [nfsd]
[ 142.152927] [<ffffffffa039f000>] ? 0xffffffffa039efff
[ 142.152927] [<ffffffff8108230c>] kthread+0x8c/0xa0
[ 142.152927] [<ffffffff813e8694>] kernel_thread_helper+0x4/0x10
[ 142.152927] [<ffffffff81082280>] ? kthread_worker_fn+0x190/0x190
[ 142.152927] [<ffffffff813e8690>] ? gs_change+0x13/0x13

Reported-by: Bryan Schumaker <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 752c0f8..9daf254 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4199,7 +4199,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

out:
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;

out_nfserr:

2011-09-14 11:45:29

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 22/25] nfsd4: hash deleg stateid's like any other

It's simpler to look up delegation stateid's in the same hash table as
any other stateid.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 112 +++++++++++++++++++++------------------------------
fs/nfsd/state.h | 5 ++
2 files changed, 51 insertions(+), 66 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 581a5d0..24685a0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -60,8 +60,6 @@ static u64 current_sessionid = 1;
#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t)))

/* forward declarations */
-static struct nfs4_delegation * search_for_delegation(stateid_t *stid);
-static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);

/* Locking: */
@@ -256,10 +254,12 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
get_nfs4_file(fp);
dp->dl_file = fp;
dp->dl_type = type;
+ dp->dl_stid.sc_type = NFS4_DELEG_STID;
dp->dl_stid.sc_stateid.si_boot = boot_time;
dp->dl_stid.sc_stateid.si_stateownerid = current_delegid++;
dp->dl_stid.sc_stateid.si_fileid = 0;
dp->dl_stid.sc_stateid.si_generation = 1;
+ hash_stid(&dp->dl_stid);
fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
dp->dl_time = 0;
atomic_set(&dp->dl_count, 1);
@@ -292,6 +292,7 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp)
static void
unhash_delegation(struct nfs4_delegation *dp)
{
+ list_del_init(&dp->dl_stid.sc_hash);
list_del_init(&dp->dl_perclnt);
spin_lock(&recall_lock);
list_del_init(&dp->dl_perfile);
@@ -1077,7 +1078,7 @@ same_stateid(stateid_t *id_one, stateid_t *id_two)
return id_one->si_fileid == id_two->si_fileid;
}

-static struct nfs4_ol_stateid *find_stateid(stateid_t *t)
+static struct nfs4_stid *find_stateid(stateid_t *t)
{
struct nfs4_stid *s;
unsigned int hashval;
@@ -1085,22 +1086,42 @@ static struct nfs4_ol_stateid *find_stateid(stateid_t *t)
hashval = stateid_hashval(t->si_stateownerid, t->si_fileid);
list_for_each_entry(s, &stateid_hashtbl[hashval], sc_hash)
if (same_stateid(&s->sc_stateid, t))
- return openlockstateid(s);
+ return s;
return NULL;
}

-static struct nfs4_ol_stateid *find_stateid_by_type(stateid_t *t, char typemask)
+static struct nfs4_ol_stateid *find_ol_stateid(stateid_t *t)
{
- struct nfs4_ol_stateid *s;
+ struct nfs4_stid *s;
+
+ s = find_stateid(t);
+ if (!s)
+ return NULL;
+ return openlockstateid(s);
+}
+
+static struct nfs4_stid *find_stateid_by_type(stateid_t *t, char typemask)
+{
+ struct nfs4_stid *s;

s = find_stateid(t);
if (!s)
return NULL;
- if (typemask & s->st_stid.sc_type)
+ if (typemask & s->sc_type)
return s;
return NULL;
}

+static struct nfs4_ol_stateid *find_ol_stateid_by_type(stateid_t *t, char typemask)
+{
+ struct nfs4_stid *s;
+
+ s = find_stateid_by_type(t, typemask);
+ if (!s)
+ return NULL;
+ return openlockstateid(s);
+}
+
static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
struct svc_rqst *rqstp, nfs4_verifier *verf)
{
@@ -2573,26 +2594,21 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
return nfs_ok;
}

-static struct nfs4_delegation *
-find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
+static int share_access_to_flags(u32 share_access)
{
- struct nfs4_delegation *dp;
+ share_access &= ~NFS4_SHARE_WANT_MASK;

- spin_lock(&recall_lock);
- list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
- if (dp->dl_stid.sc_stateid.si_stateownerid == stid->si_stateownerid) {
- spin_unlock(&recall_lock);
- return dp;
- }
- spin_unlock(&recall_lock);
- return NULL;
+ return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
}

-static int share_access_to_flags(u32 share_access)
+static struct nfs4_delegation *find_deleg_stateid(stateid_t *s)
{
- share_access &= ~NFS4_SHARE_WANT_MASK;
+ struct nfs4_stid *ret;

- return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
+ ret = find_stateid_by_type(s, NFS4_DELEG_STID);
+ if (!ret)
+ return NULL;
+ return delegstateid(ret);
}

static __be32
@@ -2602,7 +2618,7 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
int flags;
__be32 status = nfserr_bad_stateid;

- *dp = find_delegation_file(fp, &open->op_delegate_stateid);
+ *dp = find_deleg_stateid(&open->op_delegate_stateid);
if (*dp == NULL)
goto out;
flags = share_access_to_flags(open->op_share_access);
@@ -3252,7 +3268,7 @@ __be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
goto out;

status = nfserr_expired;
- stp = find_stateid(stateid);
+ stp = find_ol_stateid(stateid);
if (!stp)
goto out;
status = nfserr_bad_stateid;
@@ -3301,7 +3317,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
*/
status = nfserr_expired;
if (is_delegation_stateid(stateid)) {
- dp = find_delegation_stateid(ino, stateid);
+ dp = find_deleg_stateid(stateid);
if (!dp)
goto out;
status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
@@ -3316,7 +3332,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
BUG_ON(!*filpp);
}
} else { /* open or lock stateid */
- stp = find_stateid(stateid);
+ stp = find_ol_stateid(stateid);
if (!stp)
goto out;
status = nfserr_bad_stateid;
@@ -3348,9 +3364,10 @@ out:
static __be32
nfsd4_free_delegation_stateid(stateid_t *stateid)
{
- struct nfs4_delegation *dp = search_for_delegation(stateid);
+ struct nfs4_delegation *dp = find_deleg_stateid(stateid);
if (dp)
return nfserr_locks_held;
+
return nfserr_bad_stateid;
}

@@ -3391,7 +3408,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
}

- stp = find_stateid(stateid);
+ stp = find_ol_stateid(stateid);
if (!stp) {
ret = nfserr_bad_stateid;
goto out;
@@ -3460,7 +3477,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
status = nfs4_nospecial_stateid_checks(stateid);
if (status)
return status;
- *stpp = find_stateid_by_type(stateid, typemask);
+ *stpp = find_ol_stateid_by_type(stateid, typemask);
if (*stpp == NULL)
return nfserr_expired;
cstate->replay_owner = (*stpp)->st_stateowner;
@@ -3672,7 +3689,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (!is_delegation_stateid(stateid))
goto out;
status = nfserr_expired;
- dp = find_delegation_stateid(inode, stateid);
+ dp = find_deleg_stateid(stateid);
if (!dp)
goto out;
status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
@@ -3733,43 +3750,6 @@ lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];

-static struct nfs4_delegation *
-search_for_delegation(stateid_t *stid)
-{
- struct nfs4_file *fp;
- struct nfs4_delegation *dp;
- struct list_head *pos;
- int i;
-
- for (i = 0; i < FILE_HASH_SIZE; i++) {
- list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
- list_for_each(pos, &fp->fi_delegations) {
- dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
- if (same_stateid(&dp->dl_stid.sc_stateid, stid))
- return dp;
- }
- }
- }
- return NULL;
-}
-
-static struct nfs4_delegation *
-find_delegation_stateid(struct inode *ino, stateid_t *stid)
-{
- struct nfs4_file *fp;
- struct nfs4_delegation *dl;
-
- dprintk("NFSD: %s: stateid=" STATEID_FMT "\n", __func__,
- STATEID_VAL(stid));
-
- fp = find_file(ino);
- if (!fp)
- return NULL;
- dl = find_delegation_file(fp, stid);
- put_nfs4_file(fp);
- return dl;
-}
-
/*
* TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
* we can't properly handle lock requests that go beyond the (2^63 - 1)-th
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index e3ff7c9..12c1424 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -113,6 +113,11 @@ struct nfs4_cb_conn {
struct svc_xprt *cb_xprt; /* minorversion 1 only */
};

+static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s)
+{
+ return container_of(s, struct nfs4_delegation, dl_stid);
+}
+
/* Maximum number of slots per session. 160 is useful for long haul TCP */
#define NFSD_MAX_SLOTS_PER_SESSION 160
/* Maximum number of operations per session compound */
--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 06/25] nfsd4: eliminate unused lt_stateowner

This is used only as a local variable.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 8 ++++----
fs/nfsd/xdr4.h | 1 -
2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 834a5f8..a47bf88 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4098,6 +4098,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
struct inode *inode;
struct file_lock file_lock;
+ struct nfs4_stateowner *so;
int error;
__be32 status;

@@ -4107,7 +4108,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (check_lock_length(lockt->lt_offset, lockt->lt_length))
return nfserr_inval;

- lockt->lt_stateowner = NULL;
nfs4_lock_state();

status = nfserr_stale_clientid;
@@ -4134,10 +4134,10 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
}

- lockt->lt_stateowner = find_lockstateowner_str(inode,
+ so = find_lockstateowner_str(inode,
&lockt->lt_clientid, &lockt->lt_owner);
- if (lockt->lt_stateowner)
- file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner;
+ if (so)
+ file_lock.fl_owner = (fl_owner_t)so;
file_lock.fl_pid = current->tgid;
file_lock.fl_flags = FL_POSIX;

diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index de236fb..27a3dfa 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -184,7 +184,6 @@ struct nfsd4_lockt {
struct xdr_netobj lt_owner;
u64 lt_offset;
u64 lt_length;
- struct nfs4_stateowner * lt_stateowner;
struct nfsd4_lock_denied lt_denied;
};

--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 10/25] nfsd4: move CLOSE_STATE special case to caller

Move the CLOSE_STATE case into the unique caller that cares about it
rather than putting it in preprocess_seqid_op.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 56 ++++++++++++++++++++++++--------------------------
fs/nfsd/state.h | 1 -
2 files changed, 27 insertions(+), 30 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9c44630..eb11626 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3070,15 +3070,13 @@ laundromat_main(struct work_struct *not_used)
}

static struct nfs4_stateowner *
-search_close_lru(u32 st_id, int flags)
+search_close_lru(u32 st_id)
{
- struct nfs4_stateowner *local = NULL;
+ struct nfs4_stateowner *local;

- if (flags & CLOSE_STATE) {
- list_for_each_entry(local, &close_lru, so_close_lru) {
- if (local->so_id == st_id)
- return local;
- }
+ list_for_each_entry(local, &close_lru, so_close_lru) {
+ if (local->so_id == st_id)
+ return local;
}
return NULL;
}
@@ -3381,7 +3379,6 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
stateid_t *stateid, int flags,
struct nfs4_stateid **stpp)
{
- struct nfs4_stateid *stp;
struct nfs4_stateowner *sop;
struct svc_fh *current_fh = &cstate->current_fh;
__be32 status;
@@ -3404,28 +3401,14 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
* the confirmed flag is incorrecly set, or the generation
* number is incorrect.
*/
- stp = find_stateid(stateid, flags);
- if (stp == NULL) {
- /*
- * Also, we should make sure this isn't just the result of
- * a replayed close:
- */
- sop = search_close_lru(stateid->si_stateownerid, flags);
- /* It's not stale; let's assume it's expired: */
- if (sop == NULL)
- return nfserr_expired;
- cstate->replay_owner = sop;
- status = nfsd4_check_seqid(cstate, sop, seqid);
- if (status)
- return status;
- return nfserr_bad_seqid;
- }
+ *stpp = find_stateid(stateid, flags);
+ if (*stpp == NULL)
+ return nfserr_expired;

- *stpp = stp;
- sop = stp->st_stateowner;
+ sop = (*stpp)->st_stateowner;
cstate->replay_owner = sop;

- if (nfs4_check_fh(current_fh, stp)) {
+ if (nfs4_check_fh(current_fh, *stpp)) {
dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
return nfserr_bad_stateid;
}
@@ -3439,7 +3422,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
" confirmed yet!\n");
return nfserr_bad_stateid;
}
- status = check_stateid_generation(stateid, &stp->st_stateid, nfsd4_has_session(cstate));
+ status = check_stateid_generation(stateid, &(*stpp)->st_stateid, nfsd4_has_session(cstate));
if (status)
return status;
renew_client(sop->so_client);
@@ -3574,7 +3557,22 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/* check close_lru for replay */
status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
&close->cl_stateid,
- OPEN_STATE | CLOSE_STATE, &stp);
+ OPEN_STATE, &stp);
+ if (stp == NULL && status == nfserr_expired) {
+ /*
+ * Also, we should make sure this isn't just the result of
+ * a replayed close:
+ */
+ so = search_close_lru(close->cl_stateid.si_stateownerid);
+ /* It's not stale; let's assume it's expired: */
+ if (so == NULL)
+ goto out;
+ cstate->replay_owner = so;
+ status = nfsd4_check_seqid(cstate, so, close->cl_seqid);
+ if (status)
+ goto out;
+ status = nfserr_bad_seqid;
+ }
if (status)
goto out;
so = stp->st_stateowner;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index f7114fc2..0d88000 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -448,7 +448,6 @@ struct nfs4_stateid {
#define LOCK_STATE 0x00000008
#define RD_STATE 0x00000010
#define WR_STATE 0x00000020
-#define CLOSE_STATE 0x00000040

struct nfsd4_compound_state;

--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 08/25] nfsd4: simplify check_open logic

Sometimes the single-exit style is good, sometimes it's unnecessarily
convoluted....

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 7 ++-----
1 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8edc9ad..8694e60 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2573,7 +2573,6 @@ static __be32
nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
{
struct nfs4_stateid *local;
- __be32 status = nfserr_share_denied;
struct nfs4_stateowner *sop = open->op_stateowner;

list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
@@ -2585,11 +2584,9 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_state
*stpp = local;
/* check for conflicting share reservations */
if (!test_share(local, open))
- goto out;
+ return nfserr_share_denied;
}
- status = 0;
-out:
- return status;
+ return nfs_ok;
}

static inline struct nfs4_stateid *
--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 13/25] nfsd4: rearrange to avoid a forward reference

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 53 +++++++++++++++++++++++++--------------------------
1 files changed, 26 insertions(+), 27 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c28432a..f0eccc2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -60,7 +60,6 @@ static u64 current_sessionid = 1;
#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t)))

/* forward declarations */
-static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
static struct nfs4_delegation * search_for_delegation(stateid_t *stid);
static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
@@ -1061,6 +1060,32 @@ static void gen_confirm(struct nfs4_client *clp)
*p++ = i++;
}

+static int
+same_stateid(stateid_t *id_one, stateid_t *id_two)
+{
+ if (id_one->si_stateownerid != id_two->si_stateownerid)
+ return 0;
+ return id_one->si_fileid == id_two->si_fileid;
+}
+
+static struct nfs4_stateid *find_stateid(stateid_t *t, int flags)
+{
+ struct nfs4_stateid *s;
+ unsigned int hashval;
+
+ hashval = stateid_hashval(t->si_stateownerid, t->si_fileid);
+ list_for_each_entry(s, &stateid_hashtbl[hashval], st_hash) {
+ if (!same_stateid(&s->st_stateid, t))
+ continue;
+ if (flags & LOCK_STATE && s->st_type != NFS4_LOCK_STID)
+ return NULL;
+ if (flags & OPEN_STATE && s->st_type != NFS4_OPEN_STID)
+ return NULL;
+ return s;
+ }
+ return NULL;
+}
+
static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
struct svc_rqst *rqstp, nfs4_verifier *verf)
{
@@ -3694,32 +3719,6 @@ lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];

-static int
-same_stateid(stateid_t *id_one, stateid_t *id_two)
-{
- if (id_one->si_stateownerid != id_two->si_stateownerid)
- return 0;
- return id_one->si_fileid == id_two->si_fileid;
-}
-
-static struct nfs4_stateid *find_stateid(stateid_t *t, int flags)
-{
- struct nfs4_stateid *s;
- unsigned int hashval;
-
- hashval = stateid_hashval(t->si_stateownerid, t->si_fileid);
- list_for_each_entry(s, &stateid_hashtbl[hashval], st_hash) {
- if (!same_stateid(&s->st_stateid, t))
- continue;
- if (flags & LOCK_STATE && s->st_type != NFS4_LOCK_STID)
- return NULL;
- if (flags & OPEN_STATE && s->st_type != NFS4_OPEN_STID)
- return NULL;
- return s;
- }
- return NULL;
-}
-
static struct nfs4_delegation *
search_for_delegation(stateid_t *stid)
{
--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 04/25] nfsd4: eliminate impossible open replay case

If open fails with any error other than nfserr_replay_me, then the main
nfsd4_proc_compound() loop continues unconditionally to
nfsd4_encode_operation(), which will always call encode_seqid_op_tail.
Thus the condition we check for here does not occur.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 14 ++------------
1 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6cf729a..26b0c75 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2495,18 +2495,8 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
open->op_stateowner = NULL;
goto renew;
}
- if (open->op_seqid == sop->so_seqid - 1) {
- if (sop->so_replay.rp_buflen)
- return nfserr_replay_me;
- /* The original OPEN failed so spectacularly
- * that we don't even have replay data saved!
- * Therefore, we have no choice but to continue
- * processing this OPEN; presumably, we'll
- * fail again for the same reason.
- */
- dprintk("nfsd4_process_open1: replay with no replay cache\n");
- goto renew;
- }
+ if (open->op_seqid == sop->so_seqid - 1)
+ return nfserr_replay_me;
if (open->op_seqid != sop->so_seqid)
return nfserr_bad_seqid;
renew:
--
1.7.4.1


2011-09-14 11:45:28

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 14/25] nfsd4: split up find_stateid

Minor cleanup.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 34 +++++++++++++++++++++-------------
1 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f0eccc2..aa088bc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1068,21 +1068,29 @@ same_stateid(stateid_t *id_one, stateid_t *id_two)
return id_one->si_fileid == id_two->si_fileid;
}

-static struct nfs4_stateid *find_stateid(stateid_t *t, int flags)
+static struct nfs4_stateid *find_stateid(stateid_t *t)
{
struct nfs4_stateid *s;
unsigned int hashval;

hashval = stateid_hashval(t->si_stateownerid, t->si_fileid);
- list_for_each_entry(s, &stateid_hashtbl[hashval], st_hash) {
- if (!same_stateid(&s->st_stateid, t))
- continue;
- if (flags & LOCK_STATE && s->st_type != NFS4_LOCK_STID)
- return NULL;
- if (flags & OPEN_STATE && s->st_type != NFS4_OPEN_STID)
- return NULL;
+ list_for_each_entry(s, &stateid_hashtbl[hashval], st_hash)
+ if (same_stateid(&s->st_stateid, t))
+ return s;
+ return NULL;
+}
+
+static struct nfs4_stateid *find_stateid_by_type(stateid_t *t, int flags)
+{
+ struct nfs4_stateid *s;
+
+ s = find_stateid(t);
+ if (!s)
+ return NULL;
+ if (flags & LOCK_STATE && s->st_type == NFS4_LOCK_STID)
+ return s;
+ if (flags & OPEN_STATE && s->st_type == NFS4_OPEN_STID)
return s;
- }
return NULL;
}

@@ -3241,7 +3249,7 @@ __be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
goto out;

status = nfserr_expired;
- stp = find_stateid(stateid, 0);
+ stp = find_stateid(stateid);
if (!stp)
goto out;
status = nfserr_bad_stateid;
@@ -3306,7 +3314,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
BUG_ON(!*filpp);
}
} else { /* open or lock stateid */
- stp = find_stateid(stateid, flags);
+ stp = find_stateid(stateid);
if (!stp)
goto out;
status = nfserr_bad_stateid;
@@ -3381,7 +3389,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
}

- stp = find_stateid(stateid, 0);
+ stp = find_stateid(stateid);
if (!stp) {
ret = nfserr_bad_stateid;
goto out;
@@ -3440,7 +3448,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
* the confirmed flag is incorrecly set, or the generation
* number is incorrect.
*/
- *stpp = find_stateid(stateid, flags);
+ *stpp = find_stateid_by_type(stateid, flags);
if (*stpp == NULL)
return nfserr_expired;

--
1.7.4.1


2011-09-28 13:45:11

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic

On Wed, Sep 28, 2011 at 09:18:48AM -0400, Bryan Schumaker wrote:
> On 09/27/2011 09:49 PM, J. Bruce Fields wrote:
> > On Tue, Sep 27, 2011 at 12:55:56PM -0400, Bryan Schumaker wrote:
> >> I'm getting the following warning that I was able to bisect to this patch:
> >
> > I suspect this may fix it. (Untested.)
>
> Yeah, that seems to fix it. Thanks!

Thanks for the testing; applying for 3.2.--b.

> >
> > --b.
> >
> > commit 8da87285a245c82d23183414cec7069f18721afd
> > Author: J. Bruce Fields <[email protected]>
> > Date: Tue Sep 27 21:42:29 2011 -0400
> >
> > nfsd4: fix state lock usage in LOCKU
> >
> > In commit 5ec094c1096ab3bb795651855d53f18daa26afde "nfsd4: extend state
> > lock over seqid replay logic" I modified the exit logic of all the
> > seqid-based procedures except nfsd4_locku(). Fix the oversight.
> >
> > The result of the bug was a double-unlock while handling the LOCKU
> > procedure, and a warning like:
> >
> > [ 142.150014] WARNING: at kernel/mutex-debug.c:78 debug_mutex_unlock+0xda/0xe0()
> > ...
> > [ 142.152927] Pid: 742, comm: nfsd Not tainted 3.1.0-rc1-SLIM+ #9
> > [ 142.152927] Call Trace:
> > [ 142.152927] [<ffffffff8105fa4f>] warn_slowpath_common+0x7f/0xc0
> > [ 142.152927] [<ffffffff8105faaa>] warn_slowpath_null+0x1a/0x20
> > [ 142.152927] [<ffffffff810960ca>] debug_mutex_unlock+0xda/0xe0
> > [ 142.152927] [<ffffffff813e4200>] __mutex_unlock_slowpath+0x80/0x140
> > [ 142.152927] [<ffffffff813e42ce>] mutex_unlock+0xe/0x10
> > [ 142.152927] [<ffffffffa03bd3f5>] nfs4_lock_state+0x35/0x40 [nfsd]
> > [ 142.152927] [<ffffffffa03b0b71>] nfsd4_proc_compound+0x2a1/0x690
> > [nfsd]
> > [ 142.152927] [<ffffffffa039f9fb>] nfsd_dispatch+0xeb/0x230 [nfsd]
> > [ 142.152927] [<ffffffffa02b1055>] svc_process_common+0x345/0x690
> > [sunrpc]
> > [ 142.152927] [<ffffffff81058d10>] ? try_to_wake_up+0x280/0x280
> > [ 142.152927] [<ffffffffa02b16e2>] svc_process+0x102/0x150 [sunrpc]
> > [ 142.152927] [<ffffffffa039f0bd>] nfsd+0xbd/0x160 [nfsd]
> > [ 142.152927] [<ffffffffa039f000>] ? 0xffffffffa039efff
> > [ 142.152927] [<ffffffff8108230c>] kthread+0x8c/0xa0
> > [ 142.152927] [<ffffffff813e8694>] kernel_thread_helper+0x4/0x10
> > [ 142.152927] [<ffffffff81082280>] ? kthread_worker_fn+0x190/0x190
> > [ 142.152927] [<ffffffff813e8690>] ? gs_change+0x13/0x13
> >
> > Reported-by: Bryan Schumaker <[email protected]>
> > Signed-off-by: J. Bruce Fields <[email protected]>
> >
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index 752c0f8..9daf254 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -4199,7 +4199,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
> >
> > out:
> > - nfs4_unlock_state();
> > + if (!cstate->replay_owner)
> > + nfs4_unlock_state();
> > return status;
> >
> > out_nfserr:
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> > the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>

2011-09-14 11:45:29

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 21/25] nfsd4: share common stid-hashing helper function

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 15 +++++++++++----
1 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3e3d605..581a5d0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -218,6 +218,15 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
__nfs4_file_put_access(fp, oflag);
}

+static inline void hash_stid(struct nfs4_stid *stid)
+{
+ stateid_t *s = &stid->sc_stateid;
+ unsigned int hashval;
+
+ hashval = stateid_hashval(s->si_stateownerid, s->si_fileid);
+ list_add(&stid->sc_hash, &stateid_hashtbl[hashval]);
+}
+
static struct nfs4_delegation *
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
{
@@ -2316,10 +2325,8 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
static inline void
init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
struct nfs4_openowner *oo = open->op_openowner;
- unsigned int hashval = stateid_hashval(oo->oo_owner.so_id, fp->fi_id);

INIT_LIST_HEAD(&stp->st_lockowners);
- list_add(&stp->st_stid.sc_hash, &stateid_hashtbl[hashval]);
list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
list_add(&stp->st_perfile, &fp->fi_stateids);
stp->st_stid.sc_type = NFS4_OPEN_STID;
@@ -2331,6 +2338,7 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd
stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
/* note will be incremented before first return to client: */
stp->st_stid.sc_stateid.si_generation = 0;
+ hash_stid(&stp->st_stid);
stp->st_access_bmap = 0;
stp->st_deny_bmap = 0;
__set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK,
@@ -3866,12 +3874,10 @@ static struct nfs4_ol_stateid *
alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
{
struct nfs4_ol_stateid *stp;
- unsigned int hashval = stateid_hashval(lo->lo_owner.so_id, fp->fi_id);

stp = nfs4_alloc_stateid();
if (stp == NULL)
goto out;
- list_add(&stp->st_stid.sc_hash, &stateid_hashtbl[hashval]);
list_add(&stp->st_perfile, &fp->fi_stateids);
list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
stp->st_stateowner = &lo->lo_owner;
@@ -3883,6 +3889,7 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
/* note will be incremented before first return to client: */
stp->st_stid.sc_stateid.si_generation = 0;
+ hash_stid(&stp->st_stid);
stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;
--
1.7.4.1


2011-09-19 13:15:52

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

Including the full clientid in the on-the-wire stateid allows more
reliable detection of bad vs. expired stateid's, simplifies code, and
ensures we won't reuse the opaque part of the stateid (as we currently
do when the same openowner closes and reopens the same file).

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 58 +++++++++++---------------------------------------
fs/nfsd/state.h | 18 ++++-----------
2 files changed, 18 insertions(+), 58 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fdd03f6..922f47d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -49,9 +49,7 @@
time_t nfsd4_lease = 90; /* default lease time */
time_t nfsd4_grace = 90;
static time_t boot_time;
-static u32 current_ownerid = 1;
-static u32 current_fileid = 1;
-static u32 current_delegid = 1;
+static u32 current_stateid = 1;
static stateid_t zerostateid; /* bits all 0 */
static stateid_t onestateid; /* bits all 1 */
static u64 current_sessionid = 1;
@@ -136,11 +134,6 @@ unsigned int max_delegations;
#define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS)
#define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1)

-static unsigned int open_ownerid_hashval(const u32 id)
-{
- return id & OPEN_OWNER_HASH_MASK;
-}
-
static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
{
unsigned int ret;
@@ -150,7 +143,6 @@ static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *owner
return ret & OPEN_OWNER_HASH_MASK;
}

-static struct list_head open_ownerid_hashtbl[OPEN_OWNER_HASH_SIZE];
static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];

/* hash table for nfs4_file */
@@ -255,9 +247,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
dp->dl_file = fp;
dp->dl_type = type;
dp->dl_stid.sc_type = NFS4_DELEG_STID;
- dp->dl_stid.sc_stateid.si_boot = boot_time;
- dp->dl_stid.sc_stateid.si_stateownerid = current_delegid++;
- dp->dl_stid.sc_stateid.si_fileid = 0;
+ dp->dl_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
+ dp->dl_stid.sc_stateid.si_opaque.so_id = current_stateid++;
dp->dl_stid.sc_stateid.si_generation = 1;
hash_stid(&dp->dl_stid);
fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
@@ -457,7 +448,6 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
{
struct nfs4_ol_stateid *stp;

- list_del(&lo->lo_owner.so_idhash);
list_del(&lo->lo_owner.so_strhash);
list_del(&lo->lo_perstateid);
while (!list_empty(&lo->lo_owner.so_stateids)) {
@@ -502,7 +492,6 @@ static void unhash_openowner(struct nfs4_openowner *oo)
{
struct nfs4_ol_stateid *stp;

- list_del(&oo->oo_owner.so_idhash);
list_del(&oo->oo_owner.so_strhash);
list_del(&oo->oo_perclient);
while (!list_empty(&oo->oo_owner.so_stateids)) {
@@ -1081,9 +1070,8 @@ static void gen_confirm(struct nfs4_client *clp)
static int
same_stateid(stateid_t *id_one, stateid_t *id_two)
{
- if (id_one->si_stateownerid != id_two->si_stateownerid)
- return 0;
- return id_one->si_fileid == id_two->si_fileid;
+ return 0 == memcmp(&id_one->si_opaque, &id_two->si_opaque,
+ sizeof(stateid_opaque_t));
}

static struct nfs4_stid *find_stateid(stateid_t *t)
@@ -2198,7 +2186,6 @@ alloc_init_file(struct inode *ino)
INIT_LIST_HEAD(&fp->fi_stateids);
INIT_LIST_HEAD(&fp->fi_delegations);
fp->fi_inode = igrab(ino);
- fp->fi_id = current_fileid++;
fp->fi_had_conflict = false;
fp->fi_lease = NULL;
memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
@@ -2295,7 +2282,6 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
sop->so_owner.len = owner->len;

INIT_LIST_HEAD(&sop->so_stateids);
- sop->so_id = current_ownerid++;
sop->so_client = clp;
init_nfs4_replay(&sop->so_replay);
return sop;
@@ -2303,10 +2289,6 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj

static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
{
- unsigned int idhashval;
-
- idhashval = open_ownerid_hashval(oo->oo_owner.so_id);
- list_add(&oo->oo_owner.so_idhash, &open_ownerid_hashtbl[idhashval]);
list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]);
list_add(&oo->oo_perclient, &clp->cl_openowners);
}
@@ -2331,6 +2313,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
static inline void
init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
struct nfs4_openowner *oo = open->op_openowner;
+ struct nfs4_client *clp = oo->oo_owner.so_client;

INIT_LIST_HEAD(&stp->st_lockowners);
list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
@@ -2339,9 +2322,8 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd
stp->st_stateowner = &oo->oo_owner;
get_nfs4_file(fp);
stp->st_file = fp;
- stp->st_stid.sc_stateid.si_boot = boot_time;
- stp->st_stid.sc_stateid.si_stateownerid = oo->oo_owner.so_id;
- stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
+ stp->st_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
+ stp->st_stid.sc_stateid.si_opaque.so_id = current_stateid++;
/* note will be incremented before first return to client: */
stp->st_stid.sc_stateid.si_generation = 0;
hash_stid(&stp->st_stid);
@@ -3095,8 +3077,6 @@ nfs4_laundromat(void)
test_val = u;
break;
}
- dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
- oo->oo_owner.so_id);
release_openowner(oo);
}
if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
@@ -3141,7 +3121,7 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
static int
STALE_STATEID(stateid_t *stateid)
{
- if (stateid->si_boot == boot_time)
+ if (stateid->si_opaque.so_clid.cl_boot == boot_time)
return 0;
dprintk("NFSD: stale stateid " STATEID_FMT "!\n",
STATEID_VAL(stateid));
@@ -3710,11 +3690,6 @@ last_byte_offset(u64 start, u64 len)
return end > start ? end - 1: NFS4_MAX_UINT64;
}

-static unsigned int lockownerid_hashval(u32 id)
-{
- return id & LOCK_HASH_MASK;
-}
-
static inline unsigned int
lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
struct xdr_netobj *ownername)
@@ -3724,7 +3699,6 @@ lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
& LOCK_HASH_MASK;
}

-static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];

/*
@@ -3795,10 +3769,6 @@ find_lockowner_str(struct inode *inode, clientid_t *clid,

static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
{
- unsigned int idhashval;
-
- idhashval = lockownerid_hashval(lo->lo_owner.so_id);
- list_add(&lo->lo_owner.so_idhash, &lock_ownerid_hashtbl[idhashval]);
list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]);
list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
}
@@ -3831,6 +3801,7 @@ static struct nfs4_ol_stateid *
alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
{
struct nfs4_ol_stateid *stp;
+ struct nfs4_client *clp = lo->lo_owner.so_client;

stp = nfs4_alloc_stateid();
if (stp == NULL)
@@ -3841,9 +3812,8 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
stp->st_stid.sc_type = NFS4_LOCK_STID;
get_nfs4_file(fp);
stp->st_file = fp;
- stp->st_stid.sc_stateid.si_boot = boot_time;
- stp->st_stid.sc_stateid.si_stateownerid = lo->lo_owner.so_id;
- stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
+ stp->st_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
+ stp->st_stid.sc_stateid.si_opaque.so_id = current_stateid++;
/* note will be incremented before first return to client: */
stp->st_stid.sc_stateid.si_generation = 0;
hash_stid(&stp->st_stid);
@@ -4252,7 +4222,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
* data structures. */
INIT_LIST_HEAD(&matches);
for (i = 0; i < LOCK_HASH_SIZE; i++) {
- list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
+ list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) {
if (!same_owner_str(sop, owner, clid))
continue;
list_for_each_entry(stp, &sop->so_stateids,
@@ -4398,12 +4368,10 @@ nfs4_state_init(void)
}
for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
- INIT_LIST_HEAD(&open_ownerid_hashtbl[i]);
}
for (i = 0; i < STATEID_HASH_SIZE; i++)
INIT_LIST_HEAD(&stateid_hashtbl[i]);
for (i = 0; i < LOCK_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]);
INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
}
memset(&onestateid, ~0, sizeof(stateid_t));
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index e807abb..d6aec4f 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -45,24 +45,20 @@ typedef struct {
} clientid_t;

typedef struct {
- u32 so_boot;
- u32 so_stateownerid;
- u32 so_fileid;
+ clientid_t so_clid;
+ u32 so_id;
} stateid_opaque_t;

typedef struct {
u32 si_generation;
stateid_opaque_t si_opaque;
} stateid_t;
-#define si_boot si_opaque.so_boot
-#define si_stateownerid si_opaque.so_stateownerid
-#define si_fileid si_opaque.so_fileid

#define STATEID_FMT "(%08x/%08x/%08x/%08x)"
#define STATEID_VAL(s) \
- (s)->si_boot, \
- (s)->si_stateownerid, \
- (s)->si_fileid, \
+ (s)->si_opaque.so_clid.cl_boot, \
+ (s)->si_opaque.so_clid.cl_id, \
+ (s)->si_opaque.so_id, \
(s)->si_generation

struct nfsd4_callback {
@@ -353,11 +349,9 @@ struct nfs4_replay {
*/

struct nfs4_stateowner {
- struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */
struct list_head so_stateids;
int so_is_open_owner; /* 1=openowner,0=lockowner */
- u32 so_id;
struct nfs4_client * so_client;
/* after increment in ENCODE_SEQID_OP_TAIL, represents the next
* sequence id expected from the client: */
@@ -415,8 +409,6 @@ struct nfs4_file {
struct file_lock *fi_lease;
atomic_t fi_delegees;
struct inode *fi_inode;
- u32 fi_id; /* used with stateowner->so_id
- * for stateid_hashtbl hash */
bool fi_had_conflict;
};

--
1.7.4.1


2011-09-26 22:37:22

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 00/25] nfsd4 state cleanup

On Wed, Sep 14, 2011 at 07:44:56AM -0400, J. Bruce Fields wrote:
> - I need to look again at doing a better job of distinguishing
> the bad, expired, and stale cases for stateid's.

OK, and the following patches move to looking up stateid's per clientid,
and also improve those error returns.

--b.

2011-09-14 11:45:29

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 24/25] nfsd4: use deleg changes to cleanup preprocess_stateid_op

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 24 ++++++++++--------------
1 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 30387f3..ea338d0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3290,6 +3290,7 @@ __be32
nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
stateid_t *stateid, int flags, struct file **filpp)
{
+ struct nfs4_stid *s;
struct nfs4_ol_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
struct svc_fh *current_fh = &cstate->current_fh;
@@ -3314,13 +3315,14 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
* but that we can't find, is expired:
*/
status = nfserr_expired;
- if (is_delegation_stateid(stateid)) {
- dp = find_deleg_stateid(stateid);
- if (!dp)
- goto out;
- status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
- if (status)
- goto out;
+ s = find_stateid(stateid);
+ if (!s)
+ goto out;
+ status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
+ if (status)
+ goto out;
+ if (s->sc_type == NFS4_DELEG_STID) {
+ dp = delegstateid(s);
status = nfs4_check_delegmode(dp, flags);
if (status)
goto out;
@@ -3330,19 +3332,13 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
BUG_ON(!*filpp);
}
} else { /* open or lock stateid */
- stp = find_ol_stateid(stateid);
- if (!stp)
- goto out;
+ stp = openlockstateid(s);
status = nfserr_bad_stateid;
if (nfs4_check_fh(current_fh, stp))
goto out;
if (stp->st_stateowner->so_is_open_owner
&& !openowner(stp->st_stateowner)->oo_confirmed)
goto out;
- status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid,
- nfsd4_has_session(cstate));
- if (status)
- goto out;
status = nfs4_check_openmode(stp, flags);
if (status)
goto out;
--
1.7.4.1


2011-09-27 16:55:58

by Anna Schumaker

[permalink] [raw]
Subject: Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic

Hi Bruce,

I'm getting the following warning that I was able to bisect to this patch:

[ 142.149710] ------------[ cut here ]------------
[ 142.150014] WARNING: at kernel/mutex-debug.c:78 debug_mutex_unlock+0xda/0xe0()
[ 142.150258] Hardware name: Bochs
[ 142.150407] Modules linked in: md5 nfsd exportfs nfs lockd fscache auth_rpcgss nfs_acl sunrpc ipv6 ext2 snd_hda_intel snd_hda_codec snd_hwdep psmouse i2c_piix4 evdev serio_raw pcspkr virtio_balloon snd_pcm snd_timer snd soundcore snd_page_alloc floppy i2c_core button processor ext4 mbcache jbd2 crc16 pata_acpi uhci_hcd ata_piix libata usbcore scsi_mod virtio_net virtio_pci virtio_blk virtio virtio_ring
[ 142.152927] Pid: 742, comm: nfsd Not tainted 3.1.0-rc1-SLIM+ #9
[ 142.152927] Call Trace:
[ 142.152927] [<ffffffff8105fa4f>] warn_slowpath_common+0x7f/0xc0
[ 142.152927] [<ffffffff8105faaa>] warn_slowpath_null+0x1a/0x20
[ 142.152927] [<ffffffff810960ca>] debug_mutex_unlock+0xda/0xe0
[ 142.152927] [<ffffffff813e4200>] __mutex_unlock_slowpath+0x80/0x140
[ 142.152927] [<ffffffff813e42ce>] mutex_unlock+0xe/0x10
[ 142.152927] [<ffffffffa03bd3f5>] nfs4_lock_state+0x35/0x40 [nfsd]
[ 142.152927] [<ffffffffa03b0b71>] nfsd4_proc_compound+0x2a1/0x690 [nfsd]
[ 142.152927] [<ffffffffa039f9fb>] nfsd_dispatch+0xeb/0x230 [nfsd]
[ 142.152927] [<ffffffffa02b1055>] svc_process_common+0x345/0x690 [sunrpc]
[ 142.152927] [<ffffffff81058d10>] ? try_to_wake_up+0x280/0x280
[ 142.152927] [<ffffffffa02b16e2>] svc_process+0x102/0x150 [sunrpc]
[ 142.152927] [<ffffffffa039f0bd>] nfsd+0xbd/0x160 [nfsd]
[ 142.152927] [<ffffffffa039f000>] ? 0xffffffffa039efff
[ 142.152927] [<ffffffff8108230c>] kthread+0x8c/0xa0
[ 142.152927] [<ffffffff813e8694>] kernel_thread_helper+0x4/0x10
[ 142.152927] [<ffffffff81082280>] ? kthread_worker_fn+0x190/0x190
[ 142.152927] [<ffffffff813e8690>] ? gs_change+0x13/0x13
[ 142.152927] ---[ end trace 1b4070dc432138aa ]---

I can duplicate it with this python script, the warning shows up on the server after (during?) the f.close() line:

#!/usr/bin/python
import sys
import fcntl
import struct
import datetime

f = open(sys.argv[1], 'rw+')
print "Attempting to lock file:", sys.argv[1]
lockreq = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockreq)
raw_input("Press enter when you are ready to continue... ")
f.close()

- Bryan

On 09/14/2011 07:44 AM, J. Bruce Fields wrote:
> There are currently a couple races in the seqid replay code: a
> retransmission could come while we're still encoding the original reply,
> or a new seqid-mutating call could come as we're encoding a replay.
>
> So, extend the state lock over the encoding (both encoding of a replayed
> reply and caching of the original encoded reply).
>
> I really hate doing this, and previously added the stateowner
> reference-counting code to avoid it (which was insufficient)--but I
> don't see a less complicated alternative at the moment.
>
> Signed-off-by: J. Bruce Fields <[email protected]>
> ---
> fs/nfsd/nfs4proc.c | 5 +++--
> fs/nfsd/nfs4state.c | 12 ++++++++----
> 2 files changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 50bae74..50063a8 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -408,8 +408,8 @@ out:
> if (open->op_stateowner) {
> nfs4_get_stateowner(open->op_stateowner);
> cstate->replay_owner = open->op_stateowner;
> - }
> - nfs4_unlock_state();
> + } else
> + nfs4_unlock_state();
> return status;
> }
>
> @@ -1227,6 +1227,7 @@ encode_op:
> be32_to_cpu(status));
>
> if (cstate->replay_owner) {
> + nfs4_unlock_state();
> nfs4_put_stateowner(cstate->replay_owner);
> cstate->replay_owner = NULL;
> }
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index bc1a9db..6cf729a 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -3501,7 +3501,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>
> nfsd4_create_clid_dir(sop->so_client);
> out:
> - nfs4_unlock_state();
> + if (!cstate->replay_owner)
> + nfs4_unlock_state();
> return status;
> }
>
> @@ -3568,7 +3569,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
> memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
> status = nfs_ok;
> out:
> - nfs4_unlock_state();
> + if (!cstate->replay_owner)
> + nfs4_unlock_state();
> return status;
> }
>
> @@ -3609,7 +3611,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> if (list_empty(&so->so_stateids))
> move_to_close_lru(so);
> out:
> - nfs4_unlock_state();
> + if (!cstate->replay_owner)
> + nfs4_unlock_state();
> return status;
> }
>
> @@ -4071,7 +4074,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> out:
> if (status && lock->lk_is_new && lock_sop)
> release_lockowner(lock_sop);
> - nfs4_unlock_state();
> + if (!cstate->replay_owner)
> + nfs4_unlock_state();
> return status;
> }
>


2011-09-19 13:15:52

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 2/5] nfsd4: match close replays on stateid, not open owner id

Keep around an unhashed copy of the final stateid after the last close
using an openowner, and when identifying a replay, match against that
stateid instead of just against the open owner id. Free it the next
time the seqid is bumped or the stateowner is destroyed.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
fs/nfsd/nfs4xdr.c | 1 +
fs/nfsd/state.h | 3 +++
3 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 59b70af..a174841 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -438,7 +438,6 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp)

static void free_generic_stateid(struct nfs4_ol_stateid *stp)
{
- close_generic_stateid(stp);
kmem_cache_free(stateid_slab, stp);
}

@@ -450,6 +449,7 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)
file = find_any_file(stp->st_file);
if (file)
locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
+ close_generic_stateid(stp);
free_generic_stateid(stp);
}

@@ -485,10 +485,16 @@ release_stateid_lockowners(struct nfs4_ol_stateid *open_stp)
}
}

-static void release_open_stateid(struct nfs4_ol_stateid *stp)
+static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
{
unhash_generic_stateid(stp);
release_stateid_lockowners(stp);
+ close_generic_stateid(stp);
+}
+
+static void release_open_stateid(struct nfs4_ol_stateid *stp)
+{
+ unhash_open_stateid(stp);
free_generic_stateid(stp);
}

@@ -510,6 +516,8 @@ static void release_openowner(struct nfs4_openowner *oo)
{
unhash_openowner(oo);
list_del(&oo->oo_close_lru);
+ if (oo->oo_last_closed_stid)
+ free_generic_stateid(oo->oo_last_closed_stid);
nfs4_free_openowner(oo);
}

@@ -2324,6 +2332,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
oo->oo_owner.so_seqid = open->op_seqid;
oo->oo_flags = 0;
oo->oo_time = 0;
+ oo->oo_last_closed_stid = NULL;
INIT_LIST_HEAD(&oo->oo_close_lru);
hash_openowner(oo, clp, strhashval);
return oo;
@@ -3120,12 +3129,14 @@ laundromat_main(struct work_struct *not_used)
queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
}

-static struct nfs4_openowner * search_close_lru(u32 st_id)
+static struct nfs4_openowner * search_close_lru(stateid_t *s)
{
struct nfs4_openowner *local;
+ struct nfs4_ol_stateid *os;

list_for_each_entry(local, &close_lru, oo_close_lru) {
- if (local->oo_owner.so_id == st_id)
+ os = local->oo_last_closed_stid;
+ if (same_stateid(&os->st_stid.sc_stateid, s))
return local;
}
return NULL;
@@ -3589,6 +3600,27 @@ out:
return status;
}

+void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so)
+{
+ struct nfs4_openowner *oo;
+ struct nfs4_ol_stateid *s;
+
+ if (!so->so_is_open_owner)
+ return;
+ oo = openowner(so);
+ s = oo->oo_last_closed_stid;
+ if (!s)
+ return;
+ if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) {
+ /* Release the last_closed_stid on the next seqid bump: */
+ oo->oo_flags |= NFS4_OO_PURGE_CLOSE;
+ return;
+ }
+ oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE;
+ free_generic_stateid(oo->oo_last_closed_stid);
+ oo->oo_last_closed_stid = NULL;
+}
+
/*
* nfs4_unlock_state() called after encode
*/
@@ -3613,7 +3645,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* Also, we should make sure this isn't just the result of
* a replayed close:
*/
- oo = search_close_lru(close->cl_stateid.si_stateownerid);
+ oo = search_close_lru(&close->cl_stateid);
/* It's not stale; let's assume it's expired: */
if (oo == NULL)
goto out;
@@ -3630,8 +3662,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
update_stateid(&stp->st_stid.sc_stateid);
memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

- /* release_stateid() calls nfsd_close() if needed */
- release_open_stateid(stp);
+ /* unhash_open_stateid() calls nfsd_close() if needed */
+ oo->oo_last_closed_stid = stp;
+ unhash_open_stateid(stp);

/* place unused nfs4_stateowners on so_close_lru list to be
* released by the laundromat service after the lease period
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index f4116cf..7bd57c2 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1636,6 +1636,7 @@ static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, _
(char *)resp->p - (char *)save;
memcpy(stateowner->so_replay.rp_buf, save,
stateowner->so_replay.rp_buflen);
+ nfsd4_purge_closed_stateid(stateowner);
}
}

diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index a8324b8..e807abb 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -370,8 +370,10 @@ struct nfs4_openowner {
struct nfs4_stateowner oo_owner; /* must be first field */
struct list_head oo_perclient;
struct list_head oo_close_lru; /* tail queue */
+ struct nfs4_ol_stateid *oo_last_closed_stid;
time_t oo_time; /* time of placement on so_close_lru */
#define NFS4_OO_CONFIRMED 1
+#define NFS4_OO_PURGE_CLOSE 2
unsigned char oo_flags;
};

@@ -514,5 +516,6 @@ extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
extern void release_session_client(struct nfsd4_session *);
extern __be32 nfs4_validate_stateid(stateid_t *, bool);
+extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);

#endif /* NFSD4_STATE_H */
--
1.7.4.1


2011-09-19 13:15:52

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 5/5] nfsd4: hash closed stateid's like any other

Look up closed stateid's in the stateid hash like any other stateid
rather than searching the close lru.

This is simpler, and fixes a bug: currently we handle only the case of a
close that is the last close for a given stateowner, but not the case of
a close for a stateowner that still has active opens on other files.
Thus in a case like:

open(owner, file1)
open(owner, file2)
close(owner, file2)
close(owner, file2)

the final close won't be recognized as a retransmission.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 101 +++++++++++++++++++++++++++------------------------
fs/nfsd/state.h | 4 ++-
2 files changed, 56 insertions(+), 49 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 922f47d..e5cba83 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -406,7 +406,6 @@ static int nfs4_access_to_omode(u32 access)

static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
{
- list_del(&stp->st_stid.sc_hash);
list_del(&stp->st_perfile);
list_del(&stp->st_perstateowner);
}
@@ -437,6 +436,7 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)
struct file *file;

unhash_generic_stateid(stp);
+ list_del(&stp->st_stid.sc_hash);
file = find_any_file(stp->st_file);
if (file)
locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
@@ -485,6 +485,7 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
static void release_open_stateid(struct nfs4_ol_stateid *stp)
{
unhash_open_stateid(stp);
+ list_del(&stp->st_stid.sc_hash);
free_generic_stateid(stp);
}

@@ -501,12 +502,22 @@ static void unhash_openowner(struct nfs4_openowner *oo)
}
}

+static void release_last_closed_stateid(struct nfs4_openowner *oo)
+{
+ struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
+
+ if (s) {
+ list_del_init(&s->st_stid.sc_hash);
+ free_generic_stateid(s);
+ oo->oo_last_closed_stid = NULL;
+ }
+}
+
static void release_openowner(struct nfs4_openowner *oo)
{
unhash_openowner(oo);
list_del(&oo->oo_close_lru);
- if (oo->oo_last_closed_stid)
- free_generic_stateid(oo->oo_last_closed_stid);
+ release_last_closed_stateid(oo);
nfs4_free_openowner(oo);
}

@@ -3099,23 +3110,11 @@ laundromat_main(struct work_struct *not_used)
queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
}

-static struct nfs4_openowner * search_close_lru(stateid_t *s)
-{
- struct nfs4_openowner *local;
- struct nfs4_ol_stateid *os;
-
- list_for_each_entry(local, &close_lru, oo_close_lru) {
- os = local->oo_last_closed_stid;
- if (same_stateid(&os->st_stid.sc_stateid, s))
- return local;
- }
- return NULL;
-}
-
-static inline int
-nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
+static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
{
- return fhp->fh_dentry->d_inode != stp->st_file->fi_inode;
+ if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode)
+ return nfserr_bad_stateid;
+ return nfs_ok;
}

static int
@@ -3283,7 +3282,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
- if (s->sc_type == NFS4_DELEG_STID) {
+ switch (s->sc_type) {
+ case NFS4_DELEG_STID:
dp = delegstateid(s);
status = nfs4_check_delegmode(dp, flags);
if (status)
@@ -3293,10 +3293,12 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
*filpp = dp->dl_file->fi_deleg_file;
BUG_ON(!*filpp);
}
- } else { /* open or lock stateid */
+ break;
+ case NFS4_OPEN_STID:
+ case NFS4_LOCK_STID:
stp = openlockstateid(s);
- status = nfserr_bad_stateid;
- if (nfs4_check_fh(current_fh, stp))
+ status = nfs4_check_fh(current_fh, stp);
+ if (status)
goto out;
if (stp->st_stateowner->so_is_open_owner
&& !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
@@ -3311,6 +3313,9 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
else
*filpp = find_writeable_file(stp->st_file);
}
+ break;
+ default:
+ return nfserr_bad_stateid;
}
status = nfs_ok;
out:
@@ -3362,6 +3367,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
ret = nfsd4_free_lock_stateid(openlockstateid(s));
else
ret = nfserr_locks_held;
+ break;
+ default:
+ ret = nfserr_bad_stateid;
}
out:
nfs4_unlock_state();
@@ -3390,12 +3398,19 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
struct nfs4_stateowner *sop = stp->st_stateowner;
__be32 status;

- if (nfs4_check_fh(current_fh, stp))
- return nfserr_bad_stateid;
status = nfsd4_check_seqid(cstate, sop, seqid);
if (status)
return status;
- return check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
+ if (stp->st_stid.sc_type == NFS4_CLOSED_STID)
+ /*
+ * "Closed" stateid's exist *only* to return
+ * nfserr_replay_me from the previous step.
+ */
+ return nfserr_bad_stateid;
+ status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
+ if (status)
+ return status;
+ return nfs4_check_fh(current_fh, stp);
}

/*
@@ -3564,8 +3579,13 @@ void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so)
return;
}
oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE;
- free_generic_stateid(oo->oo_last_closed_stid);
- oo->oo_last_closed_stid = NULL;
+ release_last_closed_stateid(oo);
+}
+
+static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
+{
+ unhash_open_stateid(s);
+ s->st_stid.sc_type = NFS4_CLOSED_STID;
}

/*
@@ -3584,24 +3604,10 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
cstate->current_fh.fh_dentry->d_name.name);

nfs4_lock_state();
- /* check close_lru for replay */
- status = nfs4_preprocess_confirmed_seqid_op(cstate, close->cl_seqid,
- &close->cl_stateid, &stp);
- if (stp == NULL && status == nfserr_expired) {
- /*
- * Also, we should make sure this isn't just the result of
- * a replayed close:
- */
- oo = search_close_lru(&close->cl_stateid);
- /* It's not stale; let's assume it's expired: */
- if (oo == NULL)
- goto out;
- cstate->replay_owner = &oo->oo_owner;
- status = nfsd4_check_seqid(cstate, &oo->oo_owner, close->cl_seqid);
- if (status)
- goto out;
- status = nfserr_bad_seqid;
- }
+ status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
+ &close->cl_stateid,
+ NFS4_OPEN_STID|NFS4_CLOSED_STID,
+ &stp);
if (status)
goto out;
oo = openowner(stp->st_stateowner);
@@ -3609,9 +3615,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
update_stateid(&stp->st_stid.sc_stateid);
memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

- /* unhash_open_stateid() calls nfsd_close() if needed */
+ nfsd4_close_open_stateid(stp);
oo->oo_last_closed_stid = stp;
- unhash_open_stateid(stp);

/* place unused nfs4_stateowners on so_close_lru list to be
* released by the laundromat service after the lease period
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index d6aec4f..da68bf6 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -76,7 +76,9 @@ struct nfs4_stid {
#define NFS4_OPEN_STID 1
#define NFS4_LOCK_STID 2
#define NFS4_DELEG_STID 4
- char sc_type;
+/* For an open stateid kept around *only* to process close replays: */
+#define NFS4_CLOSED_STID 8
+ unsigned char sc_type;
struct list_head sc_hash;
stateid_t sc_stateid;
};
--
1.7.4.1


2011-09-28 15:49:34

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

On Tue, Sep 27, 2011 at 12:10:07PM -0400, Bryan Schumaker wrote:
> On 09/19/2011 09:15 AM, J. Bruce Fields wrote:
> > Including the full clientid in the on-the-wire stateid allows more
> > reliable detection of bad vs. expired stateid's, simplifies code, and
> > ensures we won't reuse the opaque part of the stateid (as we currently
> > do when the same openowner closes and reopens the same file).
> >
> > Signed-off-by: J. Bruce Fields <[email protected]>
> > ---
> > fs/nfsd/nfs4state.c | 58 +++++++++++---------------------------------------
> > fs/nfsd/state.h | 18 ++++-----------
> > 2 files changed, 18 insertions(+), 58 deletions(-)
> >
> [ ... ]
> > diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> > index e807abb..d6aec4f 100644
> > --- a/fs/nfsd/state.h
> > +++ b/fs/nfsd/state.h
> > @@ -353,11 +349,9 @@ struct nfs4_replay {
> > */
> >
> > struct nfs4_stateowner {
>
> The comment describing this struct should probably be updated since so_idhash and a few other variables no longer exist.

Yeah, thanks for noticing. The stateid comment doesn't seem that useful
either. How about the following?

--b.

commit 44464d91b253c5340c8dd78927432bf1956b5789
Author: J. Bruce Fields <[email protected]>
Date: Wed Sep 28 11:47:20 2011 -0400

nfsd4: cleanup state.h comments

These comments are mostly out of date.

Reported-by: Bryan Schumaker <[email protected]>

diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 22b065a..aa14f06 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -332,25 +332,6 @@ struct nfs4_replay {
char rp_ibuf[NFSD4_REPLAY_ISIZE];
};

-/*
-* nfs4_stateowner can either be an open_owner, or a lock_owner
-*
-* so_idhash: stateid_hashtbl[] for open owner, lockstateid_hashtbl[]
-* for lock_owner
-* so_strhash: ownerstr_hashtbl[] for open_owner, lock_ownerstr_hashtbl[]
-* for lock_owner
-* so_perclient: nfs4_client->cl_perclient entry - used when nfs4_client
-* struct is reaped.
-* so_perfilestate: heads the list of nfs4_ol_stateid (either open or lock)
-* and is used to ensure no dangling nfs4_ol_stateid references when we
-* release a stateowner.
-* so_perlockowner: (open) nfs4_ol_stateid->st_perlockowner entry - used when
-* close is called to reap associated byte-range locks
-* so_close_lru: (open) stateowner is placed on this list instead of being
-* reaped (when so_perfilestate is empty) to hold the last close replay.
-* reaped by laundramat thread after lease period.
-*/
-
struct nfs4_stateowner {
struct list_head so_strhash; /* hash by op_name */
struct list_head so_stateids;
@@ -366,7 +347,14 @@ struct nfs4_stateowner {
struct nfs4_openowner {
struct nfs4_stateowner oo_owner; /* must be first field */
struct list_head oo_perclient;
- struct list_head oo_close_lru; /* tail queue */
+ /*
+ * We keep around openowners a little while after last close,
+ * which saves clients from having to confirm, and allows us to
+ * handle close replays if they come soon enough. The close_lru
+ * is a list of such openowners, to be reaped by the laundromat
+ * thread eventually if they remain unused:
+ */
+ struct list_head oo_close_lru;
struct nfs4_ol_stateid *oo_last_closed_stid;
time_t oo_time; /* time of placement on so_close_lru */
#define NFS4_OO_CONFIRMED 1
@@ -443,23 +431,6 @@ static inline struct file *find_any_file(struct nfs4_file *f)
return f->fi_fds[O_RDONLY];
}

-/*
-* nfs4_ol_stateid can either be an open stateid or (eventually) a lock stateid
-*
-* (open)nfs4_ol_stateid: one per (open)nfs4_stateowner, nfs4_file
-*
-* st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry
-* st_perfile: file_hashtbl[] entry.
-* st_perfile_state: nfs4_stateowner->so_perfilestate
-* st_perlockowner: (open stateid) list of lock nfs4_stateowners
-* st_access_bmap: used only for open stateid
-* st_deny_bmap: used only for open stateid
-* st_openstp: open stateid lock stateid was derived from
-*
-* XXX: open stateids and lock stateids have diverged sufficiently that
-* we should consider defining separate structs for the two cases.
-*/
-
/* "ol" stands for "Open or Lock". Better suggestions welcome. */
struct nfs4_ol_stateid {
struct nfs4_stid st_stid;

2011-09-26 22:44:20

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 00/25] nfsd4 state cleanup

On Mon, Sep 26, 2011 at 06:36:43PM -0400, J. Bruce Fields wrote:
> On Mon, Sep 19, 2011 at 09:14:16AM -0400, bfields wrote:
> > On Wed, Sep 14, 2011 at 07:44:56AM -0400, J. Bruce Fields wrote:
> > > And then also still to do:
> > > - close replays: we keep around a stateid to handle close
> > > replays only in the case where it's the last stateid for an
> > > openowner, but that's not sufficient.
> >
> > A fix for this follows.
>
> (Committed for 3.2).--b.

And also I should have said, I've added more pynfs tests, including a
test for this, and some additional tests for conflicts between read
delegations and server-side operations, to:

git://linux-nfs.org/~bfields/pynfs.git

--b.

2011-09-19 13:14:20

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 00/25] nfsd4 state cleanup

On Wed, Sep 14, 2011 at 07:44:56AM -0400, J. Bruce Fields wrote:
> This is just another batch of little cleanups and bugfixes to the nfsd4
> state code.
>
> What I'm actually thinking I'd like to do next is change the way
> stateid's are composed to make it possible to look up the client first.
> Once the client's looked up, lookup of the individual stateid, and most
> of the following work, looks to me like it could be done under a
> per-client lock. The set of clients doesn't change very much so we
> could use locking that favors readers (maybe rcu) for that part. So
> that could be a first step towards saner locking.
>
> And then also still to do:
> - close replays: we keep around a stateid to handle close
> replays only in the case where it's the last stateid for an
> openowner, but that's not sufficient.

A fix for this follows.

--b.

2011-09-14 11:45:29

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 19/25] nfsd4: move some of nfs4_stateid into a separate structure

We want delegations to share more with open/lock stateid's, so first
we'll pull out some of the common stuff we want to share.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 174 +++++++++++++++++++++++++-------------------------
fs/nfsd/state.h | 29 ++++++---
2 files changed, 106 insertions(+), 97 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 768382d..d0bb5a5 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -159,7 +159,7 @@ static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
#define FILE_HASH_BITS 8
#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)

-/* hash table for (open)nfs4_stateid */
+/* hash table for (open)nfs4_ol_stateid */
#define STATEID_HASH_BITS 10
#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
@@ -219,7 +219,7 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
}

static struct nfs4_delegation *
-alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
+alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
{
struct nfs4_delegation *dp;
struct nfs4_file *fp = stp->st_file;
@@ -380,7 +380,7 @@ set_deny(unsigned int *deny, unsigned long bmap) {
}

static int
-test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
+test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) {
unsigned int access, deny;

set_access(&access, stp->st_access_bmap);
@@ -403,14 +403,14 @@ static int nfs4_access_to_omode(u32 access)
BUG();
}

-static void unhash_generic_stateid(struct nfs4_stateid *stp)
+static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
{
- list_del(&stp->st_hash);
+ list_del(&stp->st_stid.sc_hash);
list_del(&stp->st_perfile);
list_del(&stp->st_perstateowner);
}

-static void close_generic_stateid(struct nfs4_stateid *stp)
+static void close_generic_stateid(struct nfs4_ol_stateid *stp)
{
int i;

@@ -426,13 +426,13 @@ static void close_generic_stateid(struct nfs4_stateid *stp)
stp->st_file = NULL;
}

-static void free_generic_stateid(struct nfs4_stateid *stp)
+static void free_generic_stateid(struct nfs4_ol_stateid *stp)
{
close_generic_stateid(stp);
kmem_cache_free(stateid_slab, stp);
}

-static void release_lock_stateid(struct nfs4_stateid *stp)
+static void release_lock_stateid(struct nfs4_ol_stateid *stp)
{
struct file *file;

@@ -445,14 +445,14 @@ static void release_lock_stateid(struct nfs4_stateid *stp)

static void unhash_lockowner(struct nfs4_lockowner *lo)
{
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;

list_del(&lo->lo_owner.so_idhash);
list_del(&lo->lo_owner.so_strhash);
list_del(&lo->lo_perstateid);
while (!list_empty(&lo->lo_owner.so_stateids)) {
stp = list_first_entry(&lo->lo_owner.so_stateids,
- struct nfs4_stateid, st_perstateowner);
+ struct nfs4_ol_stateid, st_perstateowner);
release_lock_stateid(stp);
}
}
@@ -464,7 +464,7 @@ static void release_lockowner(struct nfs4_lockowner *lo)
}

static void
-release_stateid_lockowners(struct nfs4_stateid *open_stp)
+release_stateid_lockowners(struct nfs4_ol_stateid *open_stp)
{
struct nfs4_lockowner *lo;

@@ -475,7 +475,7 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp)
}
}

-static void release_open_stateid(struct nfs4_stateid *stp)
+static void release_open_stateid(struct nfs4_ol_stateid *stp)
{
unhash_generic_stateid(stp);
release_stateid_lockowners(stp);
@@ -484,14 +484,14 @@ static void release_open_stateid(struct nfs4_stateid *stp)

static void unhash_openowner(struct nfs4_openowner *oo)
{
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;

list_del(&oo->oo_owner.so_idhash);
list_del(&oo->oo_owner.so_strhash);
list_del(&oo->oo_perclient);
while (!list_empty(&oo->oo_owner.so_stateids)) {
stp = list_first_entry(&oo->oo_owner.so_stateids,
- struct nfs4_stateid, st_perstateowner);
+ struct nfs4_ol_stateid, st_perstateowner);
release_open_stateid(stp);
}
}
@@ -1068,26 +1068,26 @@ same_stateid(stateid_t *id_one, stateid_t *id_two)
return id_one->si_fileid == id_two->si_fileid;
}

-static struct nfs4_stateid *find_stateid(stateid_t *t)
+static struct nfs4_ol_stateid *find_stateid(stateid_t *t)
{
- struct nfs4_stateid *s;
+ struct nfs4_stid *s;
unsigned int hashval;

hashval = stateid_hashval(t->si_stateownerid, t->si_fileid);
- list_for_each_entry(s, &stateid_hashtbl[hashval], st_hash)
- if (same_stateid(&s->st_stateid, t))
- return s;
+ list_for_each_entry(s, &stateid_hashtbl[hashval], sc_hash)
+ if (same_stateid(&s->sc_stateid, t))
+ return openlockstateid(s);
return NULL;
}

-static struct nfs4_stateid *find_stateid_by_type(stateid_t *t, char typemask)
+static struct nfs4_ol_stateid *find_stateid_by_type(stateid_t *t, char typemask)
{
- struct nfs4_stateid *s;
+ struct nfs4_ol_stateid *s;

s = find_stateid(t);
if (!s)
return NULL;
- if (typemask & s->st_type)
+ if (typemask & s->st_stid.sc_type)
return s;
return NULL;
}
@@ -2232,7 +2232,7 @@ nfsd4_init_slabs(void)
if (file_slab == NULL)
goto out_nomem;
stateid_slab = kmem_cache_create("nfsd4_stateids",
- sizeof(struct nfs4_stateid), 0, 0, NULL);
+ sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
if (stateid_slab == NULL)
goto out_nomem;
deleg_slab = kmem_cache_create("nfsd4_delegations",
@@ -2314,23 +2314,23 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
}

static inline void
-init_open_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
+init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
struct nfs4_openowner *oo = open->op_openowner;
unsigned int hashval = stateid_hashval(oo->oo_owner.so_id, fp->fi_id);

INIT_LIST_HEAD(&stp->st_lockowners);
- list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
+ list_add(&stp->st_stid.sc_hash, &stateid_hashtbl[hashval]);
list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
list_add(&stp->st_perfile, &fp->fi_stateids);
- stp->st_type = NFS4_OPEN_STID;
+ stp->st_stid.sc_type = NFS4_OPEN_STID;
stp->st_stateowner = &oo->oo_owner;
get_nfs4_file(fp);
stp->st_file = fp;
- stp->st_stateid.si_boot = boot_time;
- stp->st_stateid.si_stateownerid = oo->oo_owner.so_id;
- stp->st_stateid.si_fileid = fp->fi_id;
+ stp->st_stid.sc_stateid.si_boot = boot_time;
+ stp->st_stid.sc_stateid.si_stateownerid = oo->oo_owner.so_id;
+ stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
/* note will be incremented before first return to client: */
- stp->st_stateid.si_generation = 0;
+ stp->st_stid.sc_stateid.si_generation = 0;
stp->st_access_bmap = 0;
stp->st_deny_bmap = 0;
__set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK,
@@ -2422,7 +2422,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_file *fp;
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
__be32 ret;

dprintk("NFSD: nfs4_share_conflict\n");
@@ -2611,9 +2611,9 @@ out:
}

static __be32
-nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
+nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp)
{
- struct nfs4_stateid *local;
+ struct nfs4_ol_stateid *local;
struct nfs4_openowner *oo = open->op_openowner;

list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
@@ -2630,7 +2630,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_state
return nfs_ok;
}

-static inline struct nfs4_stateid *
+static inline struct nfs4_ol_stateid *
nfs4_alloc_stateid(void)
{
return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
@@ -2672,11 +2672,11 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
}

static __be32
-nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
+nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_ol_stateid **stpp,
struct nfs4_file *fp, struct svc_fh *cur_fh,
struct nfsd4_open *open)
{
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
__be32 status;

stp = nfs4_alloc_stateid();
@@ -2708,7 +2708,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
}

static __be32
-nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
+nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
{
u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
bool new_access;
@@ -2820,7 +2820,7 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
* Attempt to hand out a delegation.
*/
static void
-nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp)
+nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
{
struct nfs4_delegation *dp;
struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
@@ -2888,7 +2888,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfsd4_compoundres *resp = rqstp->rq_resp;
struct nfs4_file *fp = NULL;
struct inode *ino = current_fh->fh_dentry->d_inode;
- struct nfs4_stateid *stp = NULL;
+ struct nfs4_ol_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
__be32 status;

@@ -2938,8 +2938,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
goto out;
}
}
- update_stateid(&stp->st_stateid);
- memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

if (nfsd4_has_session(&resp->cstate))
open->op_openowner->oo_confirmed = 1;
@@ -2953,7 +2953,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs_ok;

dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
- STATEID_VAL(&stp->st_stateid));
+ STATEID_VAL(&stp->st_stid.sc_stateid));
out:
if (fp)
put_nfs4_file(fp);
@@ -3122,7 +3122,7 @@ static struct nfs4_openowner * search_close_lru(u32 st_id)
}

static inline int
-nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
+nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
{
return fhp->fh_dentry->d_inode != stp->st_file->fi_inode;
}
@@ -3153,7 +3153,7 @@ access_permit_write(unsigned long access_bmap)
}

static
-__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
+__be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
{
__be32 status = nfserr_openmode;

@@ -3237,7 +3237,7 @@ static int is_delegation_stateid(stateid_t *stateid)

__be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
{
- struct nfs4_stateid *stp = NULL;
+ struct nfs4_ol_stateid *stp = NULL;
__be32 status = nfserr_stale_stateid;

if (STALE_STATEID(stateid))
@@ -3252,7 +3252,7 @@ __be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
&& !openowner(stp->st_stateowner)->oo_confirmed)
goto out;

- status = check_stateid_generation(stateid, &stp->st_stateid, has_session);
+ status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, has_session);
if (status)
goto out;

@@ -3268,7 +3268,7 @@ __be32
nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
stateid_t *stateid, int flags, struct file **filpp)
{
- struct nfs4_stateid *stp = NULL;
+ struct nfs4_ol_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
struct svc_fh *current_fh = &cstate->current_fh;
struct inode *ino = current_fh->fh_dentry->d_inode;
@@ -3317,7 +3317,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
if (stp->st_stateowner->so_is_open_owner
&& !openowner(stp->st_stateowner)->oo_confirmed)
goto out;
- status = check_stateid_generation(stateid, &stp->st_stateid,
+ status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid,
nfsd4_has_session(cstate));
if (status)
goto out;
@@ -3347,7 +3347,7 @@ nfsd4_free_delegation_stateid(stateid_t *stateid)
}

static __be32
-nfsd4_free_lock_stateid(struct nfs4_stateid *stp)
+nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
{
if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
return nfserr_locks_held;
@@ -3374,7 +3374,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_free_stateid *free_stateid)
{
stateid_t *stateid = &free_stateid->fr_stateid;
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
__be32 ret;

nfs4_lock_state();
@@ -3388,11 +3388,11 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
ret = nfserr_bad_stateid;
goto out;
}
- ret = check_stateid_generation(stateid, &stp->st_stateid, 1);
+ ret = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, 1);
if (ret)
goto out;

- if (stp->st_type == NFS4_OPEN_STID) {
+ if (stp->st_stid.sc_type == NFS4_OPEN_STID) {
ret = nfserr_locks_held;
goto out;
} else {
@@ -3421,7 +3421,7 @@ static __be32 nfs4_nospecial_stateid_checks(stateid_t *stateid)
return nfs_ok;
}

-static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_stateid *stp)
+static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
{
struct svc_fh *current_fh = &cstate->current_fh;
struct nfs4_stateowner *sop = stp->st_stateowner;
@@ -3432,7 +3432,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
status = nfsd4_check_seqid(cstate, sop, seqid);
if (status)
return status;
- return check_stateid_generation(stateid, &stp->st_stateid, nfsd4_has_session(cstate));
+ return check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
}

/*
@@ -3441,7 +3441,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
static __be32
nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
stateid_t *stateid, char typemask,
- struct nfs4_stateid **stpp)
+ struct nfs4_ol_stateid **stpp)
{
__be32 status;

@@ -3461,7 +3461,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
}

-static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_stateid **stpp)
+static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp)
{
__be32 status;
struct nfs4_openowner *oo;
@@ -3482,7 +3482,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
__be32 status;
struct nfs4_openowner *oo;
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;

dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3504,10 +3504,10 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (oo->oo_confirmed)
goto out;
oo->oo_confirmed = 1;
- update_stateid(&stp->st_stateid);
- memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
- __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stateid));
+ __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));

nfsd4_create_clid_dir(oo->oo_owner.so_client);
status = nfs_ok;
@@ -3517,7 +3517,7 @@ out:
return status;
}

-static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access)
+static inline void nfs4_file_downgrade(struct nfs4_ol_stateid *stp, unsigned int to_access)
{
int i;

@@ -3545,7 +3545,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
struct nfsd4_open_downgrade *od)
{
__be32 status;
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;

dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3575,8 +3575,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,

reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);

- update_stateid(&stp->st_stateid);
- memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
status = nfs_ok;
out:
if (!cstate->replay_owner)
@@ -3593,7 +3593,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
__be32 status;
struct nfs4_openowner *oo;
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;

dprintk("NFSD: nfsd4_close on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3622,8 +3622,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
oo = openowner(stp->st_stateowner);
status = nfs_ok;
- update_stateid(&stp->st_stateid);
- memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

/* release_stateid() calls nfsd_close() if needed */
release_open_stateid(stp);
@@ -3828,7 +3828,7 @@ find_lockowner_str(struct inode *inode, clientid_t *clid,
return NULL;
}

-static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp)
+static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
{
unsigned int idhashval;

@@ -3847,7 +3847,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s
*/

static struct nfs4_lockowner *
-alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) {
+alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) {
struct nfs4_lockowner *lo;

lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
@@ -3862,27 +3862,27 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
return lo;
}

-static struct nfs4_stateid *
-alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_stateid *open_stp)
+static struct nfs4_ol_stateid *
+alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
{
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
unsigned int hashval = stateid_hashval(lo->lo_owner.so_id, fp->fi_id);

stp = nfs4_alloc_stateid();
if (stp == NULL)
goto out;
- list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
+ list_add(&stp->st_stid.sc_hash, &stateid_hashtbl[hashval]);
list_add(&stp->st_perfile, &fp->fi_stateids);
list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
stp->st_stateowner = &lo->lo_owner;
- stp->st_type = NFS4_LOCK_STID;
+ stp->st_stid.sc_type = NFS4_LOCK_STID;
get_nfs4_file(fp);
stp->st_file = fp;
- stp->st_stateid.si_boot = boot_time;
- stp->st_stateid.si_stateownerid = lo->lo_owner.so_id;
- stp->st_stateid.si_fileid = fp->fi_id;
+ stp->st_stid.sc_stateid.si_boot = boot_time;
+ stp->st_stid.sc_stateid.si_stateownerid = lo->lo_owner.so_id;
+ stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
/* note will be incremented before first return to client: */
- stp->st_stateid.si_generation = 0;
+ stp->st_stid.sc_stateid.si_generation = 0;
stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;
@@ -3898,7 +3898,7 @@ check_lock_length(u64 offset, u64 length)
LOFF_OVERFLOW(offset, length)));
}

-static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access)
+static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
{
struct nfs4_file *fp = lock_stp->st_file;
int oflag = nfs4_access_to_omode(access);
@@ -3918,7 +3918,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
struct nfs4_openowner *open_sop = NULL;
struct nfs4_lockowner *lock_sop = NULL;
- struct nfs4_stateid *lock_stp;
+ struct nfs4_ol_stateid *lock_stp;
struct nfs4_file *fp;
struct file *filp = NULL;
struct file_lock file_lock;
@@ -3949,7 +3949,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* Use open owner and open stateid to create lock owner and
* lock stateid.
*/
- struct nfs4_stateid *open_stp = NULL;
+ struct nfs4_ol_stateid *open_stp = NULL;

status = nfserr_stale_clientid;
if (!nfsd4_has_session(cstate) &&
@@ -4052,8 +4052,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
switch (-err) {
case 0: /* success! */
- update_stateid(&lock_stp->st_stateid);
- memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid,
+ update_stateid(&lock_stp->st_stid.sc_stateid);
+ memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid,
sizeof(stateid_t));
status = 0;
break;
@@ -4172,7 +4172,7 @@ __be32
nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_locku *locku)
{
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
struct file *filp = NULL;
struct file_lock file_lock;
__be32 status;
@@ -4220,8 +4220,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/*
* OK, unlock succeeded; the only thing left to do is update the stateid.
*/
- update_stateid(&stp->st_stateid);
- memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

out:
nfs4_unlock_state();
@@ -4264,7 +4264,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
clientid_t *clid = &rlockowner->rl_clientid;
struct nfs4_stateowner *sop;
struct nfs4_lockowner *lo;
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner;
struct list_head matches;
int i;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index ef949eb..d7fffab 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -328,10 +328,10 @@ struct nfs4_replay {
* for lock_owner
* so_perclient: nfs4_client->cl_perclient entry - used when nfs4_client
* struct is reaped.
-* so_perfilestate: heads the list of nfs4_stateid (either open or lock)
-* and is used to ensure no dangling nfs4_stateid references when we
+* so_perfilestate: heads the list of nfs4_ol_stateid (either open or lock)
+* and is used to ensure no dangling nfs4_ol_stateid references when we
* release a stateowner.
-* so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when
+* so_perlockowner: (open) nfs4_ol_stateid->st_perlockowner entry - used when
* close is called to reap associated byte-range locks
* so_close_lru: (open) stateowner is placed on this list instead of being
* reaped (when so_perfilestate is empty) to hold the last close replay.
@@ -430,9 +430,9 @@ static inline struct file *find_any_file(struct nfs4_file *f)
}

/*
-* nfs4_stateid can either be an open stateid or (eventually) a lock stateid
+* nfs4_ol_stateid can either be an open stateid or (eventually) a lock stateid
*
-* (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file
+* (open)nfs4_ol_stateid: one per (open)nfs4_stateowner, nfs4_file
*
* st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry
* st_perfile: file_hashtbl[] entry.
@@ -446,22 +446,31 @@ static inline struct file *find_any_file(struct nfs4_file *f)
* we should consider defining separate structs for the two cases.
*/

-struct nfs4_stateid {
+struct nfs4_stid {
#define NFS4_OPEN_STID 1
#define NFS4_LOCK_STID 2
- char st_type;
- struct list_head st_hash;
+ char sc_type;
+ struct list_head sc_hash;
+ stateid_t sc_stateid;
+};
+
+struct nfs4_ol_stateid {
+ struct nfs4_stid st_stid;
struct list_head st_perfile;
struct list_head st_perstateowner;
struct list_head st_lockowners;
struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file;
- stateid_t st_stateid;
unsigned long st_access_bmap;
unsigned long st_deny_bmap;
- struct nfs4_stateid * st_openstp;
+ struct nfs4_ol_stateid * st_openstp;
};

+static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)
+{
+ return container_of(s, struct nfs4_ol_stateid, st_stid);
+}
+
/* flags for preprocess_seqid_op() */
#define RD_STATE 0x00000010
#define WR_STATE 0x00000020
--
1.7.4.1


2011-09-19 13:15:52

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 3/5] nfsd4: simplify free_stateid

We no longer need is_deleg_stateid, for example.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 66 +++++++++++---------------------------------------
1 files changed, 15 insertions(+), 51 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a174841..fdd03f6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1098,16 +1098,6 @@ static struct nfs4_stid *find_stateid(stateid_t *t)
return NULL;
}

-static struct nfs4_ol_stateid *find_ol_stateid(stateid_t *t)
-{
- struct nfs4_stid *s;
-
- s = find_stateid(t);
- if (!s)
- return NULL;
- return openlockstateid(s);
-}
-
static struct nfs4_stid *find_stateid_by_type(stateid_t *t, char typemask)
{
struct nfs4_stid *s;
@@ -3251,11 +3241,6 @@ static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_sess
return nfserr_old_stateid;
}

-static int is_delegation_stateid(stateid_t *stateid)
-{
- return stateid->si_fileid == 0;
-}
-
__be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
{
struct nfs4_stid *s;
@@ -3353,16 +3338,6 @@ out:
}

static __be32
-nfsd4_free_delegation_stateid(stateid_t *stateid)
-{
- struct nfs4_delegation *dp = find_deleg_stateid(stateid);
- if (dp)
- return nfserr_locks_held;
-
- return nfserr_bad_stateid;
-}
-
-static __be32
nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
{
if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
@@ -3382,40 +3357,32 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return nfs_ok;
}

-/*
- * Free a state id
- */
__be32
nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_free_stateid *free_stateid)
{
stateid_t *stateid = &free_stateid->fr_stateid;
- struct nfs4_ol_stateid *stp;
- __be32 ret;
+ struct nfs4_stid *s;
+ __be32 ret = nfserr_bad_stateid;

nfs4_lock_state();
- if (is_delegation_stateid(stateid)) {
- ret = nfsd4_free_delegation_stateid(stateid);
- goto out;
- }
-
- stp = find_ol_stateid(stateid);
- if (!stp) {
- ret = nfserr_bad_stateid;
- goto out;
- }
- ret = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, 1);
- if (ret)
+ s = find_stateid(stateid);
+ if (!s)
goto out;
-
- if (stp->st_stid.sc_type == NFS4_OPEN_STID) {
+ switch (s->sc_type) {
+ case NFS4_DELEG_STID:
ret = nfserr_locks_held;
goto out;
- } else {
- ret = nfsd4_free_lock_stateid(stp);
- goto out;
+ case NFS4_OPEN_STID:
+ case NFS4_LOCK_STID:
+ ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
+ if (ret)
+ goto out;
+ if (s->sc_type == NFS4_LOCK_STID)
+ ret = nfsd4_free_lock_stateid(openlockstateid(s));
+ else
+ ret = nfserr_locks_held;
}
-
out:
nfs4_unlock_state();
return ret;
@@ -3698,9 +3665,6 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_stale_stateid;
if (STALE_STATEID(stateid))
goto out;
- status = nfserr_bad_stateid;
- if (!is_delegation_stateid(stateid))
- goto out;
status = nfserr_expired;
dp = find_deleg_stateid(stateid);
if (!dp)
--
1.7.4.1


2011-09-28 13:19:05

by Anna Schumaker

[permalink] [raw]
Subject: Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic

On 09/27/2011 09:49 PM, J. Bruce Fields wrote:
> On Tue, Sep 27, 2011 at 12:55:56PM -0400, Bryan Schumaker wrote:
>> I'm getting the following warning that I was able to bisect to this patch:
>
> I suspect this may fix it. (Untested.)

Yeah, that seems to fix it. Thanks!
>
> --b.
>
> commit 8da87285a245c82d23183414cec7069f18721afd
> Author: J. Bruce Fields <[email protected]>
> Date: Tue Sep 27 21:42:29 2011 -0400
>
> nfsd4: fix state lock usage in LOCKU
>
> In commit 5ec094c1096ab3bb795651855d53f18daa26afde "nfsd4: extend state
> lock over seqid replay logic" I modified the exit logic of all the
> seqid-based procedures except nfsd4_locku(). Fix the oversight.
>
> The result of the bug was a double-unlock while handling the LOCKU
> procedure, and a warning like:
>
> [ 142.150014] WARNING: at kernel/mutex-debug.c:78 debug_mutex_unlock+0xda/0xe0()
> ...
> [ 142.152927] Pid: 742, comm: nfsd Not tainted 3.1.0-rc1-SLIM+ #9
> [ 142.152927] Call Trace:
> [ 142.152927] [<ffffffff8105fa4f>] warn_slowpath_common+0x7f/0xc0
> [ 142.152927] [<ffffffff8105faaa>] warn_slowpath_null+0x1a/0x20
> [ 142.152927] [<ffffffff810960ca>] debug_mutex_unlock+0xda/0xe0
> [ 142.152927] [<ffffffff813e4200>] __mutex_unlock_slowpath+0x80/0x140
> [ 142.152927] [<ffffffff813e42ce>] mutex_unlock+0xe/0x10
> [ 142.152927] [<ffffffffa03bd3f5>] nfs4_lock_state+0x35/0x40 [nfsd]
> [ 142.152927] [<ffffffffa03b0b71>] nfsd4_proc_compound+0x2a1/0x690
> [nfsd]
> [ 142.152927] [<ffffffffa039f9fb>] nfsd_dispatch+0xeb/0x230 [nfsd]
> [ 142.152927] [<ffffffffa02b1055>] svc_process_common+0x345/0x690
> [sunrpc]
> [ 142.152927] [<ffffffff81058d10>] ? try_to_wake_up+0x280/0x280
> [ 142.152927] [<ffffffffa02b16e2>] svc_process+0x102/0x150 [sunrpc]
> [ 142.152927] [<ffffffffa039f0bd>] nfsd+0xbd/0x160 [nfsd]
> [ 142.152927] [<ffffffffa039f000>] ? 0xffffffffa039efff
> [ 142.152927] [<ffffffff8108230c>] kthread+0x8c/0xa0
> [ 142.152927] [<ffffffff813e8694>] kernel_thread_helper+0x4/0x10
> [ 142.152927] [<ffffffff81082280>] ? kthread_worker_fn+0x190/0x190
> [ 142.152927] [<ffffffff813e8690>] ? gs_change+0x13/0x13
>
> Reported-by: Bryan Schumaker <[email protected]>
> Signed-off-by: J. Bruce Fields <[email protected]>
>
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 752c0f8..9daf254 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -4199,7 +4199,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
>
> out:
> - nfs4_unlock_state();
> + if (!cstate->replay_owner)
> + nfs4_unlock_state();
> return status;
>
> out_nfserr:
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


2011-09-14 11:45:29

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 23/25] nfsd4: fix test_stateid for delegation stateid's

Test_stateid should handle delegation stateid's as well.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 34 ++++++++++++++++------------------
1 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 24685a0..30387f3 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3261,28 +3261,26 @@ static int is_delegation_stateid(stateid_t *stateid)

__be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
{
- struct nfs4_ol_stateid *stp = NULL;
- __be32 status = nfserr_stale_stateid;
+ struct nfs4_stid *s;
+ struct nfs4_ol_stateid *ols;
+ __be32 status;

if (STALE_STATEID(stateid))
- goto out;
-
- status = nfserr_expired;
- stp = find_ol_stateid(stateid);
- if (!stp)
- goto out;
- status = nfserr_bad_stateid;
- if (stp->st_stateowner->so_is_open_owner
- && !openowner(stp->st_stateowner)->oo_confirmed)
- goto out;
+ return nfserr_stale_stateid;

- status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, has_session);
+ s = find_stateid(stateid);
+ if (!s)
+ return nfserr_stale_stateid;
+ status = check_stateid_generation(stateid, &s->sc_stateid, has_session);
if (status)
- goto out;
-
- status = nfs_ok;
-out:
- return status;
+ return status;
+ if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID)))
+ return nfs_ok;
+ ols = openlockstateid(s);
+ if (ols->st_stateowner->so_is_open_owner
+ && !openowner(ols->st_stateowner)->oo_confirmed)
+ return nfserr_bad_stateid;
+ return nfs_ok;
}

/*
--
1.7.4.1


2011-09-14 11:45:28

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 15/25] nfsd4: split preprocess_seqid, cleanup

Move most of this into helper functions. Also move the non-CONFIRM case
into caller, providing a helper function for that purpose.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 87 ++++++++++++++++++++++++++------------------------
fs/nfsd/state.h | 1 -
2 files changed, 45 insertions(+), 43 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index aa088bc..ad20bbf 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3253,7 +3253,6 @@ __be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
if (!stp)
goto out;
status = nfserr_bad_stateid;
-
if (stp->st_stateowner->so_is_open_owner
&& !openowner(stp->st_stateowner)->oo_confirmed)
goto out;
@@ -3418,6 +3417,29 @@ setlkflg (int type)
RD_STATE : WR_STATE;
}

+static __be32 nfs4_nospecial_stateid_checks(stateid_t *stateid)
+{
+ if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+ return nfserr_bad_stateid;
+ if (STALE_STATEID(stateid))
+ return nfserr_stale_stateid;
+ return nfs_ok;
+}
+
+static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_stateid *stp)
+{
+ struct svc_fh *current_fh = &cstate->current_fh;
+ struct nfs4_stateowner *sop = stp->st_stateowner;
+ __be32 status;
+
+ if (nfs4_check_fh(current_fh, stp))
+ return nfserr_bad_stateid;
+ status = nfsd4_check_seqid(cstate, sop, seqid);
+ if (status)
+ return status;
+ return check_stateid_generation(stateid, &stp->st_stateid, nfsd4_has_session(cstate));
+}
+
/*
* Checks for sequence id mutating operations.
*/
@@ -3426,54 +3448,36 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
stateid_t *stateid, int flags,
struct nfs4_stateid **stpp)
{
- struct nfs4_stateowner *sop;
- struct svc_fh *current_fh = &cstate->current_fh;
__be32 status;

dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
seqid, STATEID_VAL(stateid));

*stpp = NULL;
-
- if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
- dprintk("NFSD: preprocess_seqid_op: magic stateid!\n");
- return nfserr_bad_stateid;
- }
-
- if (STALE_STATEID(stateid))
- return nfserr_stale_stateid;
-
- /*
- * We return BAD_STATEID if filehandle doesn't match stateid,
- * the confirmed flag is incorrecly set, or the generation
- * number is incorrect.
- */
+ status = nfs4_nospecial_stateid_checks(stateid);
+ if (status)
+ return status;
*stpp = find_stateid_by_type(stateid, flags);
if (*stpp == NULL)
return nfserr_expired;
+ cstate->replay_owner = (*stpp)->st_stateowner;
+ renew_client((*stpp)->st_stateowner->so_client);

- sop = (*stpp)->st_stateowner;
- cstate->replay_owner = sop;
+ return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
+}

- if (nfs4_check_fh(current_fh, *stpp)) {
- dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
- return nfserr_bad_stateid;
- }
+static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_stateid **stpp)
+{
+ __be32 status;
+ struct nfs4_openowner *oo;

- status = nfsd4_check_seqid(cstate, sop, seqid);
+ status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
+ OPEN_STATE, stpp);
if (status)
return status;
-
- if (sop->so_is_open_owner && !openowner(sop)->oo_confirmed
- && !(flags & CONFIRM)) {
- dprintk("NFSD: preprocess_seqid_op: stateowner not"
- " confirmed yet!\n");
+ oo = openowner((*stpp)->st_stateowner);
+ if (!oo->oo_confirmed)
return nfserr_bad_stateid;
- }
- status = check_stateid_generation(stateid, &(*stpp)->st_stateid, nfsd4_has_session(cstate));
- if (status)
- return status;
- renew_client(sop->so_client);
return nfs_ok;
}

@@ -3497,7 +3501,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

status = nfs4_preprocess_seqid_op(cstate,
oc->oc_seqid, &oc->oc_req_stateid,
- CONFIRM | OPEN_STATE, &stp);
+ OPEN_STATE, &stp);
if (status)
goto out;
oo = openowner(stp->st_stateowner);
@@ -3557,8 +3561,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
return nfserr_inval;

nfs4_lock_state();
- status = nfs4_preprocess_seqid_op(cstate, od->od_seqid,
- &od->od_stateid, OPEN_STATE, &stp);
+ status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
+ &od->od_stateid, &stp);
if (status)
goto out;
status = nfserr_inval;
@@ -3602,9 +3606,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

nfs4_lock_state();
/* check close_lru for replay */
- status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
- &close->cl_stateid,
- OPEN_STATE, &stp);
+ status = nfs4_preprocess_confirmed_seqid_op(cstate, close->cl_seqid,
+ &close->cl_stateid, &stp);
if (stp == NULL && status == nfserr_expired) {
/*
* Also, we should make sure this isn't just the result of
@@ -3963,10 +3966,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;

/* validate and update open stateid and open seqid */
- status = nfs4_preprocess_seqid_op(cstate,
+ status = nfs4_preprocess_confirmed_seqid_op(cstate,
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
- OPEN_STATE, &open_stp);
+ &open_stp);
if (status)
goto out;
open_sop = openowner(open_stp->st_stateowner);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 7994ed9..9745cc7 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -463,7 +463,6 @@ struct nfs4_stateid {
};

/* flags for preprocess_seqid_op() */
-#define CONFIRM 0x00000002
#define OPEN_STATE 0x00000004
#define LOCK_STATE 0x00000008
#define RD_STATE 0x00000010
--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 02/25] nfsd4: cleanup seqid op stateowner usage

Now that the replay owner is in the cstate we can remove it from a lot
of other individual operations and further simplify
nfs4_preprocess_seqid_op().

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 57 +++++++++++++++++++++-----------------------------
fs/nfsd/nfs4xdr.c | 5 ----
fs/nfsd/xdr4.h | 7 ------
3 files changed, 24 insertions(+), 45 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e4535ff..bc1a9db 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3388,7 +3388,6 @@ setlkflg (int type)
static __be32
nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
stateid_t *stateid, int flags,
- struct nfs4_stateowner **sopp,
struct nfs4_stateid **stpp)
{
struct nfs4_stateid *stp;
@@ -3400,7 +3399,6 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
seqid, STATEID_VAL(stateid));

*stpp = NULL;
- *sopp = NULL;

if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
dprintk("NFSD: preprocess_seqid_op: magic stateid!\n");
@@ -3431,7 +3429,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
}

*stpp = stp;
- *sopp = sop = stp->st_stateowner;
+ sop = stp->st_stateowner;
nfs4_get_stateowner(sop);
cstate->replay_owner = sop;

@@ -3467,7 +3465,6 @@ check_replay:
}
dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
sop->so_seqid, seqid);
- *sopp = NULL;
return nfserr_bad_seqid;
}

@@ -3489,13 +3486,13 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

nfs4_lock_state();

- if ((status = nfs4_preprocess_seqid_op(cstate,
+ status = nfs4_preprocess_seqid_op(cstate,
oc->oc_seqid, &oc->oc_req_stateid,
- CONFIRM | OPEN_STATE,
- &oc->oc_stateowner, &stp)))
+ CONFIRM | OPEN_STATE, &stp);
+ if (status)
goto out;

- sop = oc->oc_stateowner;
+ sop = stp->st_stateowner;
sop->so_confirmed = 1;
update_stateid(&stp->st_stateid);
memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
@@ -3547,11 +3544,9 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
return nfserr_inval;

nfs4_lock_state();
- if ((status = nfs4_preprocess_seqid_op(cstate,
- od->od_seqid,
- &od->od_stateid,
- OPEN_STATE,
- &od->od_stateowner, &stp)))
+ status = nfs4_preprocess_seqid_op(cstate, od->od_seqid,
+ &od->od_stateid, OPEN_STATE, &stp);
+ if (status)
goto out;

status = nfserr_inval;
@@ -3586,6 +3581,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
__be32 status;
struct nfs4_stateid *stp;
+ struct nfs4_stateowner *so;

dprintk("NFSD: nfsd4_close on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3593,12 +3589,12 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

nfs4_lock_state();
/* check close_lru for replay */
- if ((status = nfs4_preprocess_seqid_op(cstate,
- close->cl_seqid,
+ status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
&close->cl_stateid,
- OPEN_STATE | CLOSE_STATE,
- &close->cl_stateowner, &stp)))
+ OPEN_STATE | CLOSE_STATE, &stp);
+ if (status)
goto out;
+ so = stp->st_stateowner;
status = nfs_ok;
update_stateid(&stp->st_stateid);
memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
@@ -3610,8 +3606,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* released by the laundromat service after the lease period
* to enable us to handle CLOSE replay
*/
- if (list_empty(&close->cl_stateowner->so_stateids))
- move_to_close_lru(close->cl_stateowner);
+ if (list_empty(&so->so_stateids))
+ move_to_close_lru(so);
out:
nfs4_unlock_state();
return status;
@@ -3962,12 +3958,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs4_preprocess_seqid_op(cstate,
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
- OPEN_STATE,
- &lock->lk_replay_owner, &open_stp);
+ OPEN_STATE, &open_stp);
if (status)
goto out;
status = nfserr_bad_stateid;
- open_sop = lock->lk_replay_owner;
+ open_sop = open_stp->st_stateowner;
if (!nfsd4_has_session(cstate) &&
!same_clid(&open_sop->so_client->cl_clientid,
&lock->v.new.clientid))
@@ -3993,14 +3988,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs4_preprocess_seqid_op(cstate,
lock->lk_old_lock_seqid,
&lock->lk_old_lock_stateid,
- LOCK_STATE,
- &lock->lk_replay_owner, &lock_stp);
+ LOCK_STATE, &lock_stp);
if (status)
goto out;
- lock_sop = lock->lk_replay_owner;
+ lock_sop = lock_stp->st_stateowner;
fp = lock_stp->st_file;
}
- /* lock->lk_replay_owner and lock_stp have been created or found */
+ /* lock_sop and lock_stp have been created or found */

lkflg = setlkflg(lock->lk_type);
status = nfs4_check_openmode(lock_stp, lkflg);
@@ -4191,13 +4185,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

nfs4_lock_state();

- if ((status = nfs4_preprocess_seqid_op(cstate,
- locku->lu_seqid,
- &locku->lu_stateid,
- LOCK_STATE,
- &locku->lu_stateowner, &stp)))
+ status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
+ &locku->lu_stateid, LOCK_STATE, &stp);
+ if (status)
goto out;
-
filp = find_any_file(stp->st_file);
if (!filp) {
status = nfserr_lock_range;
@@ -4206,7 +4197,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
BUG_ON(!filp);
locks_init_lock(&file_lock);
file_lock.fl_type = F_UNLCK;
- file_lock.fl_owner = (fl_owner_t) locku->lu_stateowner;
+ file_lock.fl_owner = (fl_owner_t) stp->st_stateowner;
file_lock.fl_pid = current->tgid;
file_lock.fl_file = filp;
file_lock.fl_flags = FL_POSIX;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index ee12678..462c6ef 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -456,7 +456,6 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
{
DECODE_HEAD;

- close->cl_stateowner = NULL;
READ_BUF(4);
READ32(close->cl_seqid);
return nfsd4_decode_stateid(argp, &close->cl_stateid);
@@ -551,7 +550,6 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
{
DECODE_HEAD;

- lock->lk_replay_owner = NULL;
/*
* type, reclaim(boolean), offset, length, new_lock_owner(boolean)
*/
@@ -611,7 +609,6 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
{
DECODE_HEAD;

- locku->lu_stateowner = NULL;
READ_BUF(8);
READ32(locku->lu_type);
if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
@@ -739,7 +736,6 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
{
DECODE_HEAD;

- open_conf->oc_stateowner = NULL;
status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
if (status)
return status;
@@ -754,7 +750,6 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
{
DECODE_HEAD;

- open_down->od_stateowner = NULL;
status = nfsd4_decode_stateid(argp, &open_down->od_stateid);
if (status)
return status;
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 663193b..341f0a1 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -81,7 +81,6 @@ struct nfsd4_access {
struct nfsd4_close {
u32 cl_seqid; /* request */
stateid_t cl_stateid; /* request+response */
- struct nfs4_stateowner * cl_stateowner; /* response */
};

struct nfsd4_commit {
@@ -165,9 +164,6 @@ struct nfsd4_lock {
} ok;
struct nfsd4_lock_denied denied;
} u;
- /* The lk_replay_owner is the open owner in the open_to_lock_owner
- * case and the lock owner otherwise: */
- struct nfs4_stateowner *lk_replay_owner;
};
#define lk_new_open_seqid v.new.open_seqid
#define lk_new_open_stateid v.new.open_stateid
@@ -199,7 +195,6 @@ struct nfsd4_locku {
stateid_t lu_stateid;
u64 lu_offset;
u64 lu_length;
- struct nfs4_stateowner *lu_stateowner;
};


@@ -243,7 +238,6 @@ struct nfsd4_open_confirm {
stateid_t oc_req_stateid /* request */;
u32 oc_seqid /* request */;
stateid_t oc_resp_stateid /* response */;
- struct nfs4_stateowner * oc_stateowner; /* response */
};

struct nfsd4_open_downgrade {
@@ -251,7 +245,6 @@ struct nfsd4_open_downgrade {
u32 od_seqid;
u32 od_share_access;
u32 od_share_deny;
- struct nfs4_stateowner *od_stateowner;
};


--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 12/25] nfsd4: split out some free_generic_stateid code

We'll use this elsewhere.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 567130d..c28432a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -411,7 +411,7 @@ static void unhash_generic_stateid(struct nfs4_stateid *stp)
list_del(&stp->st_perstateowner);
}

-static void free_generic_stateid(struct nfs4_stateid *stp)
+static void close_generic_stateid(struct nfs4_stateid *stp)
{
int i;

@@ -420,9 +420,16 @@ static void free_generic_stateid(struct nfs4_stateid *stp)
if (test_bit(i, &stp->st_access_bmap))
nfs4_file_put_access(stp->st_file,
nfs4_access_to_omode(i));
+ __clear_bit(i, &stp->st_access_bmap);
}
}
put_nfs4_file(stp->st_file);
+ stp->st_file = NULL;
+}
+
+static void free_generic_stateid(struct nfs4_stateid *stp)
+{
+ close_generic_stateid(stp);
kmem_cache_free(stateid_slab, stp);
}

--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 07/25] nfsd4: share common seqid checks

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 41 +++++++++++++++++++++--------------------
1 files changed, 21 insertions(+), 20 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a47bf88..8edc9ad 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2456,6 +2456,16 @@ static const struct lock_manager_operations nfsd_lease_mng_ops = {
.lm_change = nfsd_change_deleg_cb,
};

+static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
+{
+ if (nfsd4_has_session(cstate))
+ return nfs_ok;
+ if (seqid == so->so_seqid - 1)
+ return nfserr_replay_me;
+ if (seqid == so->so_seqid)
+ return nfs_ok;
+ return nfserr_bad_seqid;
+}

__be32
nfsd4_process_open1(struct nfsd4_compound_state *cstate,
@@ -2465,6 +2475,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
struct nfs4_client *clp = NULL;
unsigned int strhashval;
struct nfs4_stateowner *sop = NULL;
+ __be32 status;

if (!check_name(open->op_owner))
return nfserr_inval;
@@ -2482,9 +2493,6 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
return nfserr_expired;
goto renew;
}
- /* When sessions are used, skip open sequenceid processing */
- if (nfsd4_has_session(cstate))
- goto renew;
if (!sop->so_confirmed) {
/* Replace unconfirmed owners without checking for replay. */
clp = sop->so_client;
@@ -2492,10 +2500,9 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
open->op_stateowner = NULL;
goto renew;
}
- if (open->op_seqid == sop->so_seqid - 1)
- return nfserr_replay_me;
- if (open->op_seqid != sop->so_seqid)
- return nfserr_bad_seqid;
+ status = nfsd4_check_seqid(cstate, sop, open->op_seqid);
+ if (status)
+ return status;
renew:
if (open->op_stateowner == NULL) {
sop = alloc_init_open_stateowner(strhashval, clp, open);
@@ -3411,7 +3418,10 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
if (sop == NULL)
return nfserr_expired;
cstate->replay_owner = sop;
- goto check_replay;
+ status = nfsd4_check_seqid(cstate, sop, seqid);
+ if (status)
+ return status;
+ return nfserr_bad_seqid;
}

*stpp = stp;
@@ -3423,8 +3433,9 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
return nfserr_bad_stateid;
}

- if (!nfsd4_has_session(cstate) && seqid != sop->so_seqid)
- goto check_replay;
+ status = nfsd4_check_seqid(cstate, sop, seqid);
+ if (status)
+ return status;

if (sop->so_confirmed && flags & CONFIRM) {
dprintk("NFSD: preprocess_seqid_op: expected"
@@ -3441,16 +3452,6 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
return status;
renew_client(sop->so_client);
return nfs_ok;
-
-check_replay:
- if (seqid == sop->so_seqid - 1) {
- dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
- /* indicate replay to calling function */
- return nfserr_replay_me;
- }
- dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
- sop->so_seqid, seqid);
- return nfserr_bad_seqid;
}

__be32
--
1.7.4.1


2011-09-19 13:15:52

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 1/5] nfsd4: replace oo_confirmed by flag bit

I want at least one more bit here. So, let's haul out the caps lock key
and add a flags field.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4proc.c | 4 ++--
fs/nfsd/nfs4state.c | 24 ++++++++++++------------
fs/nfsd/state.h | 3 ++-
3 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 752a367..aa769df 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -375,7 +375,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
break;
case NFS4_OPEN_CLAIM_PREVIOUS:
- open->op_openowner->oo_confirmed = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
/*
* The CURRENT_FH is already set to the file being
* opened. (1) set open->op_cinfo, (2) set
@@ -388,7 +388,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
break;
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
- open->op_openowner->oo_confirmed = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
dprintk("NFSD: unsupported OPEN claim type %d\n",
open->op_claim_type);
status = nfserr_notsupp;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e7f83bd..59b70af 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2322,7 +2322,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
return NULL;
oo->oo_owner.so_is_open_owner = 1;
oo->oo_owner.so_seqid = open->op_seqid;
- oo->oo_confirmed = 0;
+ oo->oo_flags = 0;
oo->oo_time = 0;
INIT_LIST_HEAD(&oo->oo_close_lru);
hash_openowner(oo, clp, strhashval);
@@ -2549,7 +2549,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
return nfserr_expired;
goto renew;
}
- if (!oo->oo_confirmed) {
+ if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
/* Replace unconfirmed owners without checking for replay. */
clp = oo->oo_owner.so_client;
release_openowner(oo);
@@ -2616,7 +2616,7 @@ out:
return nfs_ok;
if (status)
return status;
- open->op_openowner->oo_confirmed = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
return nfs_ok;
}

@@ -2749,7 +2749,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
static void
nfs4_set_claim_prev(struct nfsd4_open *open)
{
- open->op_openowner->oo_confirmed = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
open->op_openowner->oo_owner.so_client->cl_firststate = 1;
}

@@ -2853,7 +2853,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_
* had the chance to reclaim theirs.... */
if (locks_in_grace())
goto out;
- if (!cb_up || !oo->oo_confirmed)
+ if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
goto out;
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
flag = NFS4_OPEN_DELEGATE_WRITE;
@@ -2952,7 +2952,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

if (nfsd4_has_session(&resp->cstate))
- open->op_openowner->oo_confirmed = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;

/*
* Attempt to hand out a delegation. No error return, because the
@@ -2973,7 +2973,7 @@ out:
* To finish the open response, we just need to set the rflags.
*/
open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
- if (!open->op_openowner->oo_confirmed &&
+ if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
!nfsd4_has_session(&resp->cstate))
open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;

@@ -3264,7 +3264,7 @@ __be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
return nfs_ok;
ols = openlockstateid(s);
if (ols->st_stateowner->so_is_open_owner
- && !openowner(ols->st_stateowner)->oo_confirmed)
+ && !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
return nfserr_bad_stateid;
return nfs_ok;
}
@@ -3323,7 +3323,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
if (nfs4_check_fh(current_fh, stp))
goto out;
if (stp->st_stateowner->so_is_open_owner
- && !openowner(stp->st_stateowner)->oo_confirmed)
+ && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
goto out;
status = nfs4_check_openmode(stp, flags);
if (status)
@@ -3476,7 +3476,7 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs
if (status)
return status;
oo = openowner((*stpp)->st_stateowner);
- if (!oo->oo_confirmed)
+ if (!(oo->oo_flags & NFS4_OO_CONFIRMED))
return nfserr_bad_stateid;
return nfs_ok;
}
@@ -3506,9 +3506,9 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
oo = openowner(stp->st_stateowner);
status = nfserr_bad_stateid;
- if (oo->oo_confirmed)
+ if (oo->oo_flags & NFS4_OO_CONFIRMED)
goto out;
- oo->oo_confirmed = 1;
+ oo->oo_flags |= NFS4_OO_CONFIRMED;
update_stateid(&stp->st_stid.sc_stateid);
memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 12c1424..a8324b8 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -371,7 +371,8 @@ struct nfs4_openowner {
struct list_head oo_perclient;
struct list_head oo_close_lru; /* tail queue */
time_t oo_time; /* time of placement on so_close_lru */
- int oo_confirmed; /* successful OPEN_CONFIRM? */
+#define NFS4_OO_CONFIRMED 1
+ unsigned char oo_flags;
};

struct nfs4_lockowner {
--
1.7.4.1


2011-09-26 22:39:45

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 3/4] nfsd4: assume test_stateid always has session

Test_stateid is 4.1-only and only allowed after a sequence operation, so
this check is unnecessary.

Cc: Bryan Schumaker <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 6 +++---
fs/nfsd/nfs4xdr.c | 2 +-
fs/nfsd/state.h | 2 +-
fs/nfsd/xdr4.h | 1 -
4 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a9e71cd..daf75fa 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3256,7 +3256,7 @@ static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_sess
return nfserr_old_stateid;
}

-__be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
+__be32 nfs4_validate_stateid(stateid_t *stateid)
{
struct nfs4_stid *s;
struct nfs4_ol_stateid *ols;
@@ -3268,7 +3268,7 @@ __be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
s = find_stateid(stateid);
if (!s)
return nfserr_stale_stateid;
- status = check_stateid_generation(stateid, &s->sc_stateid, has_session);
+ status = check_stateid_generation(stateid, &s->sc_stateid, 1);
if (status)
return status;
if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID)))
@@ -3374,7 +3374,7 @@ __be32
nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_test_stateid *test_stateid)
{
- test_stateid->ts_has_session = nfsd4_has_session(cstate);
+ /* real work is done during encoding */
return nfs_ok;
}

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 7bd57c2..2429fff 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3302,7 +3302,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
nfs4_lock_state();
for (i = 0; i < test_stateid->ts_num_ids; i++) {
nfsd4_decode_stateid(argp, &si);
- valid = nfs4_validate_stateid(&si, test_stateid->ts_has_session);
+ valid = nfs4_validate_stateid(&si);
RESERVE_SPACE(4);
*p++ = htonl(valid);
resp->p = p;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 3ed5f99..55a4d6a 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -508,7 +508,7 @@ extern void nfsd4_recdir_purge_old(void);
extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
extern void release_session_client(struct nfsd4_session *);
-extern __be32 nfs4_validate_stateid(stateid_t *, bool);
+extern __be32 nfs4_validate_stateid(stateid_t *);
extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);

#endif /* NFSD4_STATE_H */
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index a767b57..c901214 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -343,7 +343,6 @@ struct nfsd4_saved_compoundargs {

struct nfsd4_test_stateid {
__be32 ts_num_ids;
- bool ts_has_session;
struct nfsd4_compoundargs *ts_saved_args;
struct nfsd4_saved_compoundargs ts_savedp;
};
--
1.7.4.1


2011-09-14 11:45:29

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 20/25] nfsd4: add common dl_stid field to delegation

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4callback.c | 2 +-
fs/nfsd/nfs4state.c | 20 ++++++++++----------
fs/nfsd/state.h | 20 +++++++++++---------
3 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 02eb4ed..93b5e40 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -351,7 +351,7 @@ static void encode_cb_recall4args(struct xdr_stream *xdr,
__be32 *p;

encode_nfs_cb_opnum4(xdr, OP_CB_RECALL);
- encode_stateid4(xdr, &dp->dl_stateid);
+ encode_stateid4(xdr, &dp->dl_stid.sc_stateid);

p = xdr_reserve_space(xdr, 4);
*p++ = xdr_zero; /* truncate */
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d0bb5a5..3e3d605 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -247,10 +247,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
get_nfs4_file(fp);
dp->dl_file = fp;
dp->dl_type = type;
- dp->dl_stateid.si_boot = boot_time;
- dp->dl_stateid.si_stateownerid = current_delegid++;
- dp->dl_stateid.si_fileid = 0;
- dp->dl_stateid.si_generation = 1;
+ dp->dl_stid.sc_stateid.si_boot = boot_time;
+ dp->dl_stid.sc_stateid.si_stateownerid = current_delegid++;
+ dp->dl_stid.sc_stateid.si_fileid = 0;
+ dp->dl_stid.sc_stateid.si_generation = 1;
fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
dp->dl_time = 0;
atomic_set(&dp->dl_count, 1);
@@ -2572,7 +2572,7 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)

spin_lock(&recall_lock);
list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
- if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) {
+ if (dp->dl_stid.sc_stateid.si_stateownerid == stid->si_stateownerid) {
spin_unlock(&recall_lock);
return dp;
}
@@ -2861,10 +2861,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_
if (status)
goto out_free;

- memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));
+ memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));

dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
- STATEID_VAL(&dp->dl_stateid));
+ STATEID_VAL(&dp->dl_stid.sc_stateid));
out:
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
&& flag == NFS4_OPEN_DELEGATE_NONE
@@ -3296,7 +3296,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
dp = find_delegation_stateid(ino, stateid);
if (!dp)
goto out;
- status = check_stateid_generation(stateid, &dp->dl_stateid, nfsd4_has_session(cstate));
+ status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
status = nfs4_check_delegmode(dp, flags);
@@ -3667,7 +3667,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
dp = find_delegation_stateid(inode, stateid);
if (!dp)
goto out;
- status = check_stateid_generation(stateid, &dp->dl_stateid, nfsd4_has_session(cstate));
+ status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
renew_client(dp->dl_client);
@@ -3737,7 +3737,7 @@ search_for_delegation(stateid_t *stid)
list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
list_for_each(pos, &fp->fi_delegations) {
dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
- if (same_stateid(&dp->dl_stateid, stid))
+ if (same_stateid(&dp->dl_stid.sc_stateid, stid))
return dp;
}
}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index d7fffab..e3ff7c9 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -76,6 +76,15 @@ struct nfsd4_callback {
bool cb_done;
};

+struct nfs4_stid {
+#define NFS4_OPEN_STID 1
+#define NFS4_LOCK_STID 2
+#define NFS4_DELEG_STID 4
+ char sc_type;
+ struct list_head sc_hash;
+ stateid_t sc_stateid;
+};
+
struct nfs4_delegation {
struct list_head dl_perfile;
struct list_head dl_perclnt;
@@ -86,7 +95,7 @@ struct nfs4_delegation {
u32 dl_type;
time_t dl_time;
/* For recall: */
- stateid_t dl_stateid;
+ struct nfs4_stid dl_stid;
struct knfsd_fh dl_fh;
int dl_retries;
struct nfsd4_callback dl_recall;
@@ -446,14 +455,7 @@ static inline struct file *find_any_file(struct nfs4_file *f)
* we should consider defining separate structs for the two cases.
*/

-struct nfs4_stid {
-#define NFS4_OPEN_STID 1
-#define NFS4_LOCK_STID 2
- char sc_type;
- struct list_head sc_hash;
- stateid_t sc_stateid;
-};
-
+/* "ol" stands for "Open or Lock". Better suggestions welcome. */
struct nfs4_ol_stateid {
struct nfs4_stid st_stid;
struct list_head st_perfile;
--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 11/25] nfsd4: split stateowners into open and lockowners

The stateowner has some fields that only make sense for openowners, and
some that only make sense for lockowners, and I find it a lot clearer if
those are separated out.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4proc.c | 18 ++--
fs/nfsd/nfs4state.c | 367 ++++++++++++++++++++++++++-------------------------
fs/nfsd/nfs4xdr.c | 2 +-
fs/nfsd/state.h | 33 ++++-
fs/nfsd/xdr4.h | 2 +-
5 files changed, 224 insertions(+), 198 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index ce151f0..460eeb3 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -250,7 +250,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
fh_dup2(current_fh, &resfh);

/* set reply cache */
- fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
+ fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
&resfh.fh_handle);
if (!created)
status = do_open_permission(rqstp, current_fh, open,
@@ -277,7 +277,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));

/* set replay cache */
- fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
+ fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
&current_fh->fh_handle);

open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
@@ -306,9 +306,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__be32 status;
struct nfsd4_compoundres *resp;

- dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
+ dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n",
(int)open->op_fname.len, open->op_fname.data,
- open->op_stateowner);
+ open->op_openowner);

/* This check required by spec. */
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
@@ -332,7 +332,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
resp = rqstp->rq_resp;
status = nfsd4_process_open1(&resp->cstate, open);
if (status == nfserr_replay_me) {
- struct nfs4_replay *rp = &open->op_stateowner->so_replay;
+ struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay;
fh_put(&cstate->current_fh);
fh_copy_shallow(&cstate->current_fh.fh_handle,
&rp->rp_openfh);
@@ -374,7 +374,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
break;
case NFS4_OPEN_CLAIM_PREVIOUS:
- open->op_stateowner->so_confirmed = 1;
+ open->op_openowner->oo_confirmed = 1;
/*
* The CURRENT_FH is already set to the file being
* opened. (1) set open->op_cinfo, (2) set
@@ -387,7 +387,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
break;
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
- open->op_stateowner->so_confirmed = 1;
+ open->op_openowner->oo_confirmed = 1;
dprintk("NFSD: unsupported OPEN claim type %d\n",
open->op_claim_type);
status = nfserr_notsupp;
@@ -405,8 +405,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
*/
status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
out:
- if (open->op_stateowner)
- cstate->replay_owner = open->op_stateowner;
+ if (open->op_openowner)
+ cstate->replay_owner = &open->op_openowner->oo_owner;
else
nfs4_unlock_state();
return status;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index eb11626..567130d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -63,7 +63,7 @@ static u64 current_sessionid = 1;
static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
static struct nfs4_delegation * search_for_delegation(stateid_t *stid);
static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
-static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner);
+static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);

/* Locking: */

@@ -77,7 +77,8 @@ static DEFINE_MUTEX(client_mutex);
*/
static DEFINE_SPINLOCK(recall_lock);

-static struct kmem_cache *stateowner_slab = NULL;
+static struct kmem_cache *openowner_slab = NULL;
+static struct kmem_cache *lockowner_slab = NULL;
static struct kmem_cache *file_slab = NULL;
static struct kmem_cache *stateid_slab = NULL;
static struct kmem_cache *deleg_slab = NULL;
@@ -432,41 +433,39 @@ static void release_lock_stateid(struct nfs4_stateid *stp)
unhash_generic_stateid(stp);
file = find_any_file(stp->st_file);
if (file)
- locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
+ locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
free_generic_stateid(stp);
}

-static void unhash_lockowner(struct nfs4_stateowner *sop)
+static void unhash_lockowner(struct nfs4_lockowner *lo)
{
struct nfs4_stateid *stp;

- list_del(&sop->so_idhash);
- list_del(&sop->so_strhash);
- list_del(&sop->so_perstateid);
- while (!list_empty(&sop->so_stateids)) {
- stp = list_first_entry(&sop->so_stateids,
+ list_del(&lo->lo_owner.so_idhash);
+ list_del(&lo->lo_owner.so_strhash);
+ list_del(&lo->lo_perstateid);
+ while (!list_empty(&lo->lo_owner.so_stateids)) {
+ stp = list_first_entry(&lo->lo_owner.so_stateids,
struct nfs4_stateid, st_perstateowner);
release_lock_stateid(stp);
}
}

-static void release_lockowner(struct nfs4_stateowner *sop)
+static void release_lockowner(struct nfs4_lockowner *lo)
{
- unhash_lockowner(sop);
- nfs4_free_stateowner(sop);
+ unhash_lockowner(lo);
+ nfs4_free_lockowner(lo);
}

static void
release_stateid_lockowners(struct nfs4_stateid *open_stp)
{
- struct nfs4_stateowner *lock_sop;
+ struct nfs4_lockowner *lo;

while (!list_empty(&open_stp->st_lockowners)) {
- lock_sop = list_entry(open_stp->st_lockowners.next,
- struct nfs4_stateowner, so_perstateid);
- /* list_del(&open_stp->st_lockowners); */
- BUG_ON(lock_sop->so_is_open_owner);
- release_lockowner(lock_sop);
+ lo = list_entry(open_stp->st_lockowners.next,
+ struct nfs4_lockowner, lo_perstateid);
+ release_lockowner(lo);
}
}

@@ -477,26 +476,25 @@ static void release_open_stateid(struct nfs4_stateid *stp)
free_generic_stateid(stp);
}

-static void unhash_openowner(struct nfs4_stateowner *sop)
+static void unhash_openowner(struct nfs4_openowner *oo)
{
struct nfs4_stateid *stp;

- list_del(&sop->so_idhash);
- list_del(&sop->so_strhash);
- list_del(&sop->so_perclient);
- list_del(&sop->so_perstateid); /* XXX: necessary? */
- while (!list_empty(&sop->so_stateids)) {
- stp = list_first_entry(&sop->so_stateids,
+ list_del(&oo->oo_owner.so_idhash);
+ list_del(&oo->oo_owner.so_strhash);
+ list_del(&oo->oo_perclient);
+ while (!list_empty(&oo->oo_owner.so_stateids)) {
+ stp = list_first_entry(&oo->oo_owner.so_stateids,
struct nfs4_stateid, st_perstateowner);
release_open_stateid(stp);
}
}

-static void release_openowner(struct nfs4_stateowner *sop)
+static void release_openowner(struct nfs4_openowner *oo)
{
- unhash_openowner(sop);
- list_del(&sop->so_close_lru);
- nfs4_free_stateowner(sop);
+ unhash_openowner(oo);
+ list_del(&oo->oo_close_lru);
+ nfs4_free_openowner(oo);
}

#define SESSION_HASH_SIZE 512
@@ -961,7 +959,7 @@ unhash_client_locked(struct nfs4_client *clp)
static void
expire_client(struct nfs4_client *clp)
{
- struct nfs4_stateowner *sop;
+ struct nfs4_openowner *oo;
struct nfs4_delegation *dp;
struct list_head reaplist;

@@ -979,8 +977,8 @@ expire_client(struct nfs4_client *clp)
unhash_delegation(dp);
}
while (!list_empty(&clp->cl_openowners)) {
- sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
- release_openowner(sop);
+ oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
+ release_openowner(oo);
}
nfsd4_shutdown_callback(clp);
if (clp->cl_cb_conn.cb_xprt)
@@ -2173,7 +2171,8 @@ nfsd4_free_slab(struct kmem_cache **slab)
void
nfsd4_free_slabs(void)
{
- nfsd4_free_slab(&stateowner_slab);
+ nfsd4_free_slab(&openowner_slab);
+ nfsd4_free_slab(&lockowner_slab);
nfsd4_free_slab(&file_slab);
nfsd4_free_slab(&stateid_slab);
nfsd4_free_slab(&deleg_slab);
@@ -2182,9 +2181,13 @@ nfsd4_free_slabs(void)
static int
nfsd4_init_slabs(void)
{
- stateowner_slab = kmem_cache_create("nfsd4_stateowners",
- sizeof(struct nfs4_stateowner), 0, 0, NULL);
- if (stateowner_slab == NULL)
+ openowner_slab = kmem_cache_create("nfsd4_openowners",
+ sizeof(struct nfs4_openowner), 0, 0, NULL);
+ if (openowner_slab == NULL)
+ goto out_nomem;
+ lockowner_slab = kmem_cache_create("nfsd4_lockowners",
+ sizeof(struct nfs4_openowner), 0, 0, NULL);
+ if (lockowner_slab == NULL)
goto out_nomem;
file_slab = kmem_cache_create("nfsd4_files",
sizeof(struct nfs4_file), 0, 0, NULL);
@@ -2205,11 +2208,16 @@ out_nomem:
return -ENOMEM;
}

-void
-nfs4_free_stateowner(struct nfs4_stateowner *sop)
+void nfs4_free_openowner(struct nfs4_openowner *oo)
+{
+ kfree(oo->oo_owner.so_owner.data);
+ kmem_cache_free(openowner_slab, oo);
+}
+
+void nfs4_free_lockowner(struct nfs4_lockowner *lo)
{
- kfree(sop->so_owner.data);
- kmem_cache_free(stateowner_slab, sop);
+ kfree(lo->lo_owner.so_owner.data);
+ kmem_cache_free(lockowner_slab, lo);
}

static void init_nfs4_replay(struct nfs4_replay *rp)
@@ -2219,74 +2227,72 @@ static void init_nfs4_replay(struct nfs4_replay *rp)
rp->rp_buf = rp->rp_ibuf;
}

-static inline struct nfs4_stateowner *alloc_stateowner(struct xdr_netobj *owner, struct nfs4_client *clp)
+static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
{
struct nfs4_stateowner *sop;

- sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL);
+ sop = kmem_cache_alloc(slab, GFP_KERNEL);
if (!sop)
return NULL;

sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
if (!sop->so_owner.data) {
- kmem_cache_free(stateowner_slab, sop);
+ kmem_cache_free(slab, sop);
return NULL;
}
sop->so_owner.len = owner->len;

- INIT_LIST_HEAD(&sop->so_perclient);
INIT_LIST_HEAD(&sop->so_stateids);
- INIT_LIST_HEAD(&sop->so_perstateid);
- INIT_LIST_HEAD(&sop->so_close_lru);
sop->so_id = current_ownerid++;
- sop->so_time = 0;
sop->so_client = clp;
init_nfs4_replay(&sop->so_replay);
return sop;
}

-static void hash_openowner(struct nfs4_stateowner *sop, struct nfs4_client *clp, unsigned int strhashval)
+static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
{
unsigned int idhashval;

- idhashval = open_ownerid_hashval(sop->so_id);
- list_add(&sop->so_idhash, &open_ownerid_hashtbl[idhashval]);
- list_add(&sop->so_strhash, &open_ownerstr_hashtbl[strhashval]);
- list_add(&sop->so_perclient, &clp->cl_openowners);
+ idhashval = open_ownerid_hashval(oo->oo_owner.so_id);
+ list_add(&oo->oo_owner.so_idhash, &open_ownerid_hashtbl[idhashval]);
+ list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]);
+ list_add(&oo->oo_perclient, &clp->cl_openowners);
}

-static struct nfs4_stateowner *
+static struct nfs4_openowner *
alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
- struct nfs4_stateowner *sop;
+ struct nfs4_openowner *oo;

- sop = alloc_stateowner(&open->op_owner, clp);
- if (!sop)
+ oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
+ if (!oo)
return NULL;
- sop->so_is_open_owner = 1;
- sop->so_seqid = open->op_seqid;
- sop->so_confirmed = 0;
- hash_openowner(sop, clp, strhashval);
- return sop;
+ oo->oo_owner.so_is_open_owner = 1;
+ oo->oo_owner.so_seqid = open->op_seqid;
+ oo->oo_confirmed = 0;
+ oo->oo_time = 0;
+ INIT_LIST_HEAD(&oo->oo_close_lru);
+ hash_openowner(oo, clp, strhashval);
+ return oo;
}

static inline void
init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
- struct nfs4_stateowner *sop = open->op_stateowner;
- unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
+ struct nfs4_openowner *oo = open->op_openowner;
+ unsigned int hashval = stateid_hashval(oo->oo_owner.so_id, fp->fi_id);

INIT_LIST_HEAD(&stp->st_hash);
INIT_LIST_HEAD(&stp->st_perstateowner);
INIT_LIST_HEAD(&stp->st_lockowners);
INIT_LIST_HEAD(&stp->st_perfile);
list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
- list_add(&stp->st_perstateowner, &sop->so_stateids);
+ list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
list_add(&stp->st_perfile, &fp->fi_stateids);
stp->st_type = NFS4_OPEN_STID;
- stp->st_stateowner = sop;
+ stp->st_stateowner = &oo->oo_owner;
get_nfs4_file(fp);
stp->st_file = fp;
stp->st_stateid.si_boot = boot_time;
- stp->st_stateid.si_stateownerid = sop->so_id;
+ stp->st_stateid.si_stateownerid = oo->oo_owner.so_id;
stp->st_stateid.si_fileid = fp->fi_id;
/* note will be incremented before first return to client: */
stp->st_stateid.si_generation = 0;
@@ -2299,12 +2305,12 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
}

static void
-move_to_close_lru(struct nfs4_stateowner *sop)
+move_to_close_lru(struct nfs4_openowner *oo)
{
- dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
+ dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);

- list_move_tail(&sop->so_close_lru, &close_lru);
- sop->so_time = get_seconds();
+ list_move_tail(&oo->oo_close_lru, &close_lru);
+ oo->oo_time = get_seconds();
}

static int
@@ -2316,14 +2322,14 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
(sop->so_client->cl_clientid.cl_id == clid->cl_id);
}

-static struct nfs4_stateowner *
+static struct nfs4_openowner *
find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
{
struct nfs4_stateowner *so = NULL;

list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) {
if (same_owner_str(so, &open->op_owner, &open->op_clientid))
- return so;
+ return container_of(so, struct nfs4_openowner, oo_owner);
}
return NULL;
}
@@ -2474,7 +2480,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
clientid_t *clientid = &open->op_clientid;
struct nfs4_client *clp = NULL;
unsigned int strhashval;
- struct nfs4_stateowner *sop = NULL;
+ struct nfs4_openowner *oo = NULL;
__be32 status;

if (!check_name(open->op_owner))
@@ -2484,34 +2490,34 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
return nfserr_stale_clientid;

strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner);
- sop = find_openstateowner_str(strhashval, open);
- open->op_stateowner = sop;
- if (!sop) {
+ oo = find_openstateowner_str(strhashval, open);
+ open->op_openowner = oo;
+ if (!oo) {
/* Make sure the client's lease hasn't expired. */
clp = find_confirmed_client(clientid);
if (clp == NULL)
return nfserr_expired;
goto renew;
}
- if (!sop->so_confirmed) {
+ if (!oo->oo_confirmed) {
/* Replace unconfirmed owners without checking for replay. */
- clp = sop->so_client;
- release_openowner(sop);
- open->op_stateowner = NULL;
+ clp = oo->oo_owner.so_client;
+ release_openowner(oo);
+ open->op_openowner = NULL;
goto renew;
}
- status = nfsd4_check_seqid(cstate, sop, open->op_seqid);
+ status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
if (status)
return status;
renew:
- if (open->op_stateowner == NULL) {
- sop = alloc_init_open_stateowner(strhashval, clp, open);
- if (sop == NULL)
+ if (open->op_openowner == NULL) {
+ oo = alloc_init_open_stateowner(strhashval, clp, open);
+ if (oo == NULL)
return nfserr_jukebox;
- open->op_stateowner = sop;
+ open->op_openowner = oo;
}
- list_del_init(&sop->so_close_lru);
- renew_client(sop->so_client);
+ list_del_init(&oo->oo_close_lru);
+ renew_client(oo->oo_owner.so_client);
return nfs_ok;
}

@@ -2565,7 +2571,7 @@ out:
return nfs_ok;
if (status)
return status;
- open->op_stateowner->so_confirmed = 1;
+ open->op_openowner->oo_confirmed = 1;
return nfs_ok;
}

@@ -2573,14 +2579,14 @@ static __be32
nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
{
struct nfs4_stateid *local;
- struct nfs4_stateowner *sop = open->op_stateowner;
+ struct nfs4_openowner *oo = open->op_openowner;

list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
/* ignore lock owners */
if (local->st_stateowner->so_is_open_owner == 0)
continue;
/* remember if we have seen this open owner */
- if (local->st_stateowner == sop)
+ if (local->st_stateowner == &oo->oo_owner)
*stpp = local;
/* check for conflicting share reservations */
if (!test_share(local, open))
@@ -2698,8 +2704,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
static void
nfs4_set_claim_prev(struct nfsd4_open *open)
{
- open->op_stateowner->so_confirmed = 1;
- open->op_stateowner->so_client->cl_firststate = 1;
+ open->op_openowner->oo_confirmed = 1;
+ open->op_openowner->oo_owner.so_client->cl_firststate = 1;
}

/* Should we give out recallable state?: */
@@ -2782,11 +2788,11 @@ static void
nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp)
{
struct nfs4_delegation *dp;
- struct nfs4_stateowner *sop = stp->st_stateowner;
+ struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
int cb_up;
int status, flag = 0;

- cb_up = nfsd4_cb_channel_good(sop->so_client);
+ cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
flag = NFS4_OPEN_DELEGATE_NONE;
open->op_recall = 0;
switch (open->op_claim_type) {
@@ -2802,7 +2808,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
* had the chance to reclaim theirs.... */
if (locks_in_grace())
goto out;
- if (!cb_up || !sop->so_confirmed)
+ if (!cb_up || !oo->oo_confirmed)
goto out;
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
flag = NFS4_OPEN_DELEGATE_WRITE;
@@ -2813,7 +2819,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
goto out;
}

- dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
+ dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag);
if (dp == NULL)
goto out_no_deleg;
status = nfs4_set_delegation(dp, flag);
@@ -2901,7 +2907,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));

if (nfsd4_has_session(&resp->cstate))
- open->op_stateowner->so_confirmed = 1;
+ open->op_openowner->oo_confirmed = 1;

/*
* Attempt to hand out a delegation. No error return, because the
@@ -2922,7 +2928,7 @@ out:
* To finish the open response, we just need to set the rflags.
*/
open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
- if (!open->op_stateowner->so_confirmed &&
+ if (!open->op_openowner->oo_confirmed &&
!nfsd4_has_session(&resp->cstate))
open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;

@@ -2981,7 +2987,7 @@ static time_t
nfs4_laundromat(void)
{
struct nfs4_client *clp;
- struct nfs4_stateowner *sop;
+ struct nfs4_openowner *oo;
struct nfs4_delegation *dp;
struct list_head *pos, *next, reaplist;
time_t cutoff = get_seconds() - nfsd4_lease;
@@ -3038,16 +3044,16 @@ nfs4_laundromat(void)
}
test_val = nfsd4_lease;
list_for_each_safe(pos, next, &close_lru) {
- sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
- if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) {
- u = sop->so_time - cutoff;
+ oo = container_of(pos, struct nfs4_openowner, oo_close_lru);
+ if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) {
+ u = oo->oo_time - cutoff;
if (test_val > u)
test_val = u;
break;
}
dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
- sop->so_id);
- release_openowner(sop);
+ oo->oo_owner.so_id);
+ release_openowner(oo);
}
if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
@@ -3069,13 +3075,12 @@ laundromat_main(struct work_struct *not_used)
queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
}

-static struct nfs4_stateowner *
-search_close_lru(u32 st_id)
+static struct nfs4_openowner * search_close_lru(u32 st_id)
{
- struct nfs4_stateowner *local;
+ struct nfs4_openowner *local;

- list_for_each_entry(local, &close_lru, so_close_lru) {
- if (local->so_id == st_id)
+ list_for_each_entry(local, &close_lru, oo_close_lru) {
+ if (local->oo_owner.so_id == st_id)
return local;
}
return NULL;
@@ -3209,7 +3214,8 @@ __be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
goto out;
status = nfserr_bad_stateid;

- if (!stp->st_stateowner->so_confirmed)
+ if (stp->st_stateowner->so_is_open_owner
+ && !openowner(stp->st_stateowner)->oo_confirmed)
goto out;

status = check_stateid_generation(stateid, &stp->st_stateid, has_session);
@@ -3274,7 +3280,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
status = nfserr_bad_stateid;
if (nfs4_check_fh(current_fh, stp))
goto out;
- if (!stp->st_stateowner->so_confirmed)
+ if (stp->st_stateowner->so_is_open_owner
+ && !openowner(stp->st_stateowner)->oo_confirmed)
goto out;
status = check_stateid_generation(stateid, &stp->st_stateid,
nfsd4_has_session(cstate));
@@ -3308,7 +3315,7 @@ nfsd4_free_delegation_stateid(stateid_t *stateid)
static __be32
nfsd4_free_lock_stateid(struct nfs4_stateid *stp)
{
- if (check_for_locks(stp->st_file, stp->st_stateowner))
+ if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
return nfserr_locks_held;
release_lock_stateid(stp);
return nfs_ok;
@@ -3417,7 +3424,8 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
if (status)
return status;

- if (!sop->so_confirmed && !(flags & CONFIRM)) {
+ if (sop->so_is_open_owner && !openowner(sop)->oo_confirmed
+ && !(flags & CONFIRM)) {
dprintk("NFSD: preprocess_seqid_op: stateowner not"
" confirmed yet!\n");
return nfserr_bad_stateid;
@@ -3434,7 +3442,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_open_confirm *oc)
{
__be32 status;
- struct nfs4_stateowner *sop;
+ struct nfs4_openowner *oo;
struct nfs4_stateid *stp;

dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
@@ -3452,17 +3460,17 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
CONFIRM | OPEN_STATE, &stp);
if (status)
goto out;
- sop = stp->st_stateowner;
+ oo = openowner(stp->st_stateowner);
status = nfserr_bad_stateid;
- if (sop->so_confirmed)
+ if (oo->oo_confirmed)
goto out;
- sop->so_confirmed = 1;
+ oo->oo_confirmed = 1;
update_stateid(&stp->st_stateid);
memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stateid));

- nfsd4_create_clid_dir(sop->so_client);
+ nfsd4_create_clid_dir(oo->oo_owner.so_client);
status = nfs_ok;
out:
if (!cstate->replay_owner)
@@ -3513,7 +3521,6 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
&od->od_stateid, OPEN_STATE, &stp);
if (status)
goto out;
-
status = nfserr_inval;
if (!test_bit(od->od_share_access, &stp->st_access_bmap)) {
dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n",
@@ -3546,8 +3553,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_close *close)
{
__be32 status;
+ struct nfs4_openowner *oo;
struct nfs4_stateid *stp;
- struct nfs4_stateowner *so;

dprintk("NFSD: nfsd4_close on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3563,19 +3570,19 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* Also, we should make sure this isn't just the result of
* a replayed close:
*/
- so = search_close_lru(close->cl_stateid.si_stateownerid);
+ oo = search_close_lru(close->cl_stateid.si_stateownerid);
/* It's not stale; let's assume it's expired: */
- if (so == NULL)
+ if (oo == NULL)
goto out;
- cstate->replay_owner = so;
- status = nfsd4_check_seqid(cstate, so, close->cl_seqid);
+ cstate->replay_owner = &oo->oo_owner;
+ status = nfsd4_check_seqid(cstate, &oo->oo_owner, close->cl_seqid);
if (status)
goto out;
status = nfserr_bad_seqid;
}
if (status)
goto out;
- so = stp->st_stateowner;
+ oo = openowner(stp->st_stateowner);
status = nfs_ok;
update_stateid(&stp->st_stateid);
memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
@@ -3587,8 +3594,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* released by the laundromat service after the lease period
* to enable us to handle CLOSE replay
*/
- if (list_empty(&so->so_stateids))
- move_to_close_lru(so);
+ if (list_empty(&oo->oo_owner.so_stateids))
+ move_to_close_lru(oo);
out:
if (!cstate->replay_owner)
nfs4_unlock_state();
@@ -3768,17 +3775,17 @@ static const struct lock_manager_operations nfsd_posix_mng_ops = {
static inline void
nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
{
- struct nfs4_stateowner *sop;
+ struct nfs4_lockowner *lo;

if (fl->fl_lmops == &nfsd_posix_mng_ops) {
- sop = (struct nfs4_stateowner *) fl->fl_owner;
- deny->ld_owner.data = kmemdup(sop->so_owner.data,
- sop->so_owner.len, GFP_KERNEL);
+ lo = (struct nfs4_lockowner *) fl->fl_owner;
+ deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
+ lo->lo_owner.so_owner.len, GFP_KERNEL);
if (!deny->ld_owner.data)
/* We just don't care that much */
goto nevermind;
- deny->ld_owner.len = sop->so_owner.len;
- deny->ld_clientid = sop->so_client->cl_clientid;
+ deny->ld_owner.len = lo->lo_owner.so_owner.len;
+ deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
} else {
nevermind:
deny->ld_owner.len = 0;
@@ -3795,8 +3802,8 @@ nevermind:
deny->ld_type = NFS4_WRITE_LT;
}

-static struct nfs4_stateowner *
-find_lockstateowner_str(struct inode *inode, clientid_t *clid,
+static struct nfs4_lockowner *
+find_lockowner_str(struct inode *inode, clientid_t *clid,
struct xdr_netobj *owner)
{
unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner);
@@ -3804,19 +3811,19 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,

list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
if (same_owner_str(op, owner, clid))
- return op;
+ return lockowner(op);
}
return NULL;
}

-static void hash_lockowner(struct nfs4_stateowner *sop, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp)
+static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp)
{
unsigned int idhashval;

- idhashval = lockownerid_hashval(sop->so_id);
- list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
- list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
- list_add(&sop->so_perstateid, &open_stp->st_lockowners);
+ idhashval = lockownerid_hashval(lo->lo_owner.so_id);
+ list_add(&lo->lo_owner.so_idhash, &lock_ownerid_hashtbl[idhashval]);
+ list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]);
+ list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
}

/*
@@ -3827,28 +3834,27 @@ static void hash_lockowner(struct nfs4_stateowner *sop, unsigned int strhashval,
* strhashval = lock_ownerstr_hashval
*/

-static struct nfs4_stateowner *
+static struct nfs4_lockowner *
alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) {
- struct nfs4_stateowner *sop;
+ struct nfs4_lockowner *lo;

- sop = alloc_stateowner(&lock->lk_new_owner, clp);
- if (!sop)
+ lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
+ if (!lo)
return NULL;
- INIT_LIST_HEAD(&sop->so_stateids);
- sop->so_is_open_owner = 0;
+ INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
+ lo->lo_owner.so_is_open_owner = 0;
/* It is the openowner seqid that will be incremented in encode in the
* case of new lockowners; so increment the lock seqid manually: */
- sop->so_seqid = lock->lk_new_lock_seqid + 1;
- sop->so_confirmed = 1;
- hash_lockowner(sop, strhashval, clp, open_stp);
- return sop;
+ lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1;
+ hash_lockowner(lo, strhashval, clp, open_stp);
+ return lo;
}

static struct nfs4_stateid *
-alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp)
+alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_stateid *open_stp)
{
struct nfs4_stateid *stp;
- unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
+ unsigned int hashval = stateid_hashval(lo->lo_owner.so_id, fp->fi_id);

stp = nfs4_alloc_stateid();
if (stp == NULL)
@@ -3859,13 +3865,13 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
INIT_LIST_HEAD(&stp->st_lockowners); /* not used */
list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
list_add(&stp->st_perfile, &fp->fi_stateids);
- list_add(&stp->st_perstateowner, &sop->so_stateids);
- stp->st_stateowner = sop;
+ list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
+ stp->st_stateowner = &lo->lo_owner;
stp->st_type = NFS4_LOCK_STID;
get_nfs4_file(fp);
stp->st_file = fp;
stp->st_stateid.si_boot = boot_time;
- stp->st_stateid.si_stateownerid = sop->so_id;
+ stp->st_stateid.si_stateownerid = lo->lo_owner.so_id;
stp->st_stateid.si_fileid = fp->fi_id;
/* note will be incremented before first return to client: */
stp->st_stateid.si_generation = 0;
@@ -3902,8 +3908,8 @@ __be32
nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_lock *lock)
{
- struct nfs4_stateowner *open_sop = NULL;
- struct nfs4_stateowner *lock_sop = NULL;
+ struct nfs4_openowner *open_sop = NULL;
+ struct nfs4_lockowner *lock_sop = NULL;
struct nfs4_stateid *lock_stp;
struct nfs4_file *fp;
struct file *filp = NULL;
@@ -3949,23 +3955,23 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
OPEN_STATE, &open_stp);
if (status)
goto out;
+ open_sop = openowner(open_stp->st_stateowner);
status = nfserr_bad_stateid;
- open_sop = open_stp->st_stateowner;
if (!nfsd4_has_session(cstate) &&
- !same_clid(&open_sop->so_client->cl_clientid,
+ !same_clid(&open_sop->oo_owner.so_client->cl_clientid,
&lock->v.new.clientid))
goto out;
/* create lockowner and lock stateid */
fp = open_stp->st_file;
- strhashval = lock_ownerstr_hashval(fp->fi_inode,
- open_sop->so_client->cl_clientid.cl_id,
+ strhashval = lock_ownerstr_hashval(fp->fi_inode,
+ open_sop->oo_owner.so_client->cl_clientid.cl_id,
&lock->v.new.owner);
/* XXX: Do we need to check for duplicate stateowners on
* the same file, or should they just be allowed (and
* create new stateids)? */
status = nfserr_jukebox;
lock_sop = alloc_init_lock_stateowner(strhashval,
- open_sop->so_client, open_stp, lock);
+ open_sop->oo_owner.so_client, open_stp, lock);
if (lock_sop == NULL)
goto out;
lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
@@ -3974,12 +3980,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
} else {
/* lock (lock owner + lock stateid) already exists */
status = nfs4_preprocess_seqid_op(cstate,
- lock->lk_old_lock_seqid,
- &lock->lk_old_lock_stateid,
+ lock->lk_old_lock_seqid,
+ &lock->lk_old_lock_stateid,
LOCK_STATE, &lock_stp);
if (status)
goto out;
- lock_sop = lock_stp->st_stateowner;
+ lock_sop = lockowner(lock_stp->st_stateowner);
fp = lock_stp->st_file;
}
/* lock_sop and lock_stp have been created or found */
@@ -4092,7 +4098,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
struct inode *inode;
struct file_lock file_lock;
- struct nfs4_stateowner *so;
+ struct nfs4_lockowner *lo;
int error;
__be32 status;

@@ -4128,10 +4134,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
}

- so = find_lockstateowner_str(inode,
- &lockt->lt_clientid, &lockt->lt_owner);
- if (so)
- file_lock.fl_owner = (fl_owner_t)so;
+ lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);
+ if (lo)
+ file_lock.fl_owner = (fl_owner_t)lo;
file_lock.fl_pid = current->tgid;
file_lock.fl_flags = FL_POSIX;

@@ -4186,7 +4191,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
BUG_ON(!filp);
locks_init_lock(&file_lock);
file_lock.fl_type = F_UNLCK;
- file_lock.fl_owner = (fl_owner_t) stp->st_stateowner;
+ file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
file_lock.fl_pid = current->tgid;
file_lock.fl_file = filp;
file_lock.fl_flags = FL_POSIX;
@@ -4225,7 +4230,7 @@ out_nfserr:
* 0: no locks held by lockowner
*/
static int
-check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner)
+check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
{
struct file_lock **flpp;
struct inode *inode = filp->fi_inode;
@@ -4250,6 +4255,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
{
clientid_t *clid = &rlockowner->rl_clientid;
struct nfs4_stateowner *sop;
+ struct nfs4_lockowner *lo;
struct nfs4_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner;
struct list_head matches;
@@ -4279,11 +4285,10 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
continue;
list_for_each_entry(stp, &sop->so_stateids,
st_perstateowner) {
- if (check_for_locks(stp->st_file, sop))
+ lo = lockowner(sop);
+ if (check_for_locks(stp->st_file, lo))
goto out;
- /* Note: so_perclient unused for lockowners,
- * so it's OK to fool with here. */
- list_add(&sop->so_perclient, &matches);
+ list_add(&lo->lo_list, &matches);
}
}
}
@@ -4292,12 +4297,12 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
* have been checked. */
status = nfs_ok;
while (!list_empty(&matches)) {
- sop = list_entry(matches.next, struct nfs4_stateowner,
- so_perclient);
+ lo = list_entry(matches.next, struct nfs4_lockowner,
+ lo_list);
/* unhash_stateowner deletes so_perclient only
* for openowners. */
- list_del(&sop->so_perclient);
- release_lockowner(sop);
+ list_del(&lo->lo_list);
+ release_lockowner(lo);
}
out:
nfs4_unlock_state();
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index c4dcba3..182570b 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -646,7 +646,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)

memset(open->op_bmval, 0, sizeof(open->op_bmval));
open->op_iattr.ia_valid = 0;
- open->op_stateowner = NULL;
+ open->op_openowner = NULL;

/* seqid, share_access, share_deny, clientid, ownerlen */
READ_BUF(16 + sizeof(clientid_t));
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 0d88000..7994ed9 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -337,14 +337,11 @@ struct nfs4_replay {
* reaped (when so_perfilestate is empty) to hold the last close replay.
* reaped by laundramat thread after lease period.
*/
+
struct nfs4_stateowner {
struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */
- struct list_head so_perclient;
struct list_head so_stateids;
- struct list_head so_perstateid; /* for lockowners only */
- struct list_head so_close_lru; /* tail queue */
- time_t so_time; /* time of placement on so_close_lru */
int so_is_open_owner; /* 1=openowner,0=lockowner */
u32 so_id;
struct nfs4_client * so_client;
@@ -352,10 +349,33 @@ struct nfs4_stateowner {
* sequence id expected from the client: */
u32 so_seqid;
struct xdr_netobj so_owner; /* open owner name */
- int so_confirmed; /* successful OPEN_CONFIRM? */
struct nfs4_replay so_replay;
};

+struct nfs4_openowner {
+ struct nfs4_stateowner oo_owner; /* must be first field */
+ struct list_head oo_perclient;
+ struct list_head oo_close_lru; /* tail queue */
+ time_t oo_time; /* time of placement on so_close_lru */
+ int oo_confirmed; /* successful OPEN_CONFIRM? */
+};
+
+struct nfs4_lockowner {
+ struct nfs4_stateowner lo_owner; /* must be first element */
+ struct list_head lo_perstateid; /* for lockowners only */
+ struct list_head lo_list; /* for temporary uses */
+};
+
+static inline struct nfs4_openowner * openowner(struct nfs4_stateowner *so)
+{
+ return container_of(so, struct nfs4_openowner, oo_owner);
+}
+
+static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
+{
+ return container_of(so, struct nfs4_lockowner, lo_owner);
+}
+
/*
* nfs4_file: a file opened by some number of (open) nfs4_stateowners.
* o fi_perfile list is used to search for conflicting
@@ -457,7 +477,8 @@ extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void);
extern int nfs4_in_grace(void);
extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
-extern void nfs4_free_stateowner(struct nfs4_stateowner *sop);
+extern void nfs4_free_openowner(struct nfs4_openowner *);
+extern void nfs4_free_lockowner(struct nfs4_lockowner *);
extern int set_callback_cred(void);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 27a3dfa..f95a724 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -227,7 +227,7 @@ struct nfsd4_open {
struct nfsd4_change_info op_cinfo; /* response */
u32 op_rflags; /* response */
int op_truncate; /* used during processing */
- struct nfs4_stateowner *op_stateowner; /* used during processing */
+ struct nfs4_openowner *op_openowner; /* used during processing */
struct nfs4_acl *op_acl;
};
#define op_iattr iattr
--
1.7.4.1


2011-09-14 11:45:28

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 18/25] nfsd4: remove redundant stateid initialization

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 7 -------
1 files changed, 0 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 73b5e1e..768382d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2318,10 +2318,7 @@ init_open_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_o
struct nfs4_openowner *oo = open->op_openowner;
unsigned int hashval = stateid_hashval(oo->oo_owner.so_id, fp->fi_id);

- INIT_LIST_HEAD(&stp->st_hash);
- INIT_LIST_HEAD(&stp->st_perstateowner);
INIT_LIST_HEAD(&stp->st_lockowners);
- INIT_LIST_HEAD(&stp->st_perfile);
list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
list_add(&stp->st_perfile, &fp->fi_stateids);
@@ -3874,10 +3871,6 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
stp = nfs4_alloc_stateid();
if (stp == NULL)
goto out;
- INIT_LIST_HEAD(&stp->st_hash);
- INIT_LIST_HEAD(&stp->st_perfile);
- INIT_LIST_HEAD(&stp->st_perstateowner);
- INIT_LIST_HEAD(&stp->st_lockowners); /* not used */
list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
list_add(&stp->st_perfile, &fp->fi_stateids);
list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
--
1.7.4.1


2011-09-14 11:45:27

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 05/25] nfsd4: drop most stateowner refcounting

Maybe we'll bring it back some day, but we don't have much real use for
it now.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4proc.c | 6 ++----
fs/nfsd/nfs4state.c | 23 ++++++++++++-----------
fs/nfsd/nfs4xdr.c | 11 ++++++-----
fs/nfsd/state.h | 15 +--------------
fs/nfsd/xdr4.h | 2 +-
5 files changed, 22 insertions(+), 35 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 50063a8..ce151f0 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -405,10 +405,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
*/
status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
out:
- if (open->op_stateowner) {
- nfs4_get_stateowner(open->op_stateowner);
+ if (open->op_stateowner)
cstate->replay_owner = open->op_stateowner;
- } else
+ else
nfs4_unlock_state();
return status;
}
@@ -1228,7 +1227,6 @@ encode_op:

if (cstate->replay_owner) {
nfs4_unlock_state();
- nfs4_put_stateowner(cstate->replay_owner);
cstate->replay_owner = NULL;
}
/* XXX Ugh, we need to get rid of this kind of special case: */
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 26b0c75..834a5f8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -453,7 +453,7 @@ static void unhash_lockowner(struct nfs4_stateowner *sop)
static void release_lockowner(struct nfs4_stateowner *sop)
{
unhash_lockowner(sop);
- nfs4_put_stateowner(sop);
+ nfs4_free_stateowner(sop);
}

static void
@@ -496,7 +496,7 @@ static void release_openowner(struct nfs4_stateowner *sop)
{
unhash_openowner(sop);
list_del(&sop->so_close_lru);
- nfs4_put_stateowner(sop);
+ nfs4_free_stateowner(sop);
}

#define SESSION_HASH_SIZE 512
@@ -2206,10 +2206,8 @@ out_nomem:
}

void
-nfs4_free_stateowner(struct kref *kref)
+nfs4_free_stateowner(struct nfs4_stateowner *sop)
{
- struct nfs4_stateowner *sop =
- container_of(kref, struct nfs4_stateowner, so_ref);
kfree(sop->so_owner.data);
kmem_cache_free(stateowner_slab, sop);
}
@@ -2236,7 +2234,6 @@ static inline struct nfs4_stateowner *alloc_stateowner(struct xdr_netobj *owner,
}
sop->so_owner.len = owner->len;

- kref_init(&sop->so_ref);
INIT_LIST_HEAD(&sop->so_perclient);
INIT_LIST_HEAD(&sop->so_stateids);
INIT_LIST_HEAD(&sop->so_perstateid);
@@ -3413,14 +3410,12 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
/* It's not stale; let's assume it's expired: */
if (sop == NULL)
return nfserr_expired;
- nfs4_get_stateowner(sop);
cstate->replay_owner = sop;
goto check_replay;
}

*stpp = stp;
sop = stp->st_stateowner;
- nfs4_get_stateowner(sop);
cstate->replay_owner = sop;

if (nfs4_check_fh(current_fh, stp)) {
@@ -3783,11 +3778,17 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)

if (fl->fl_lmops == &nfsd_posix_mng_ops) {
sop = (struct nfs4_stateowner *) fl->fl_owner;
- kref_get(&sop->so_ref);
- deny->ld_sop = sop;
+ deny->ld_owner.data = kmemdup(sop->so_owner.data,
+ sop->so_owner.len, GFP_KERNEL);
+ if (!deny->ld_owner.data)
+ /* We just don't care that much */
+ goto nevermind;
+ deny->ld_owner.len = sop->so_owner.len;
deny->ld_clientid = sop->so_client->cl_clientid;
} else {
- deny->ld_sop = NULL;
+nevermind:
+ deny->ld_owner.len = 0;
+ deny->ld_owner.data = NULL;
deny->ld_clientid.cl_boot = 0;
deny->ld_clientid.cl_id = 0;
}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 462c6ef..c4dcba3 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2570,17 +2570,18 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh
static void
nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld)
{
+ struct xdr_netobj *conf = &ld->ld_owner;
__be32 *p;

- RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0));
+ RESERVE_SPACE(32 + XDR_LEN(conf->len));
WRITE64(ld->ld_start);
WRITE64(ld->ld_length);
WRITE32(ld->ld_type);
- if (ld->ld_sop) {
+ if (conf->len) {
WRITEMEM(&ld->ld_clientid, 8);
- WRITE32(ld->ld_sop->so_owner.len);
- WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len);
- kref_put(&ld->ld_sop->so_ref, nfs4_free_stateowner);
+ WRITE32(conf->len);
+ WRITEMEM(conf->data, conf->len);
+ kfree(conf->data);
} else { /* non - nfsv4 lock in conflict, no clientid nor owner */
WRITE64((u64)0); /* clientid */
WRITE32(0); /* length of owner name */
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index c425717..f7114fc2 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -338,7 +338,6 @@ struct nfs4_replay {
* reaped by laundramat thread after lease period.
*/
struct nfs4_stateowner {
- struct kref so_ref;
struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */
struct list_head so_perclient;
@@ -459,7 +458,7 @@ extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void);
extern int nfs4_in_grace(void);
extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
-extern void nfs4_free_stateowner(struct kref *kref);
+extern void nfs4_free_stateowner(struct nfs4_stateowner *sop);
extern int set_callback_cred(void);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
@@ -482,16 +481,4 @@ extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
extern void release_session_client(struct nfsd4_session *);
extern __be32 nfs4_validate_stateid(stateid_t *, bool);

-static inline void
-nfs4_put_stateowner(struct nfs4_stateowner *so)
-{
- kref_put(&so->so_ref, nfs4_free_stateowner);
-}
-
-static inline void
-nfs4_get_stateowner(struct nfs4_stateowner *so)
-{
- kref_get(&so->so_ref);
-}
-
#endif /* NFSD4_STATE_H */
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 341f0a1..de236fb 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -130,7 +130,7 @@ struct nfsd4_link {

struct nfsd4_lock_denied {
clientid_t ld_clientid;
- struct nfs4_stateowner *ld_sop;
+ struct xdr_netobj ld_owner;
u64 ld_start;
u64 ld_length;
u32 ld_type;
--
1.7.4.1


2011-10-03 14:57:53

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

On Mon, Oct 03, 2011 at 04:43:40PM +0200, Benny Halevy wrote:
> Bruce, it seems with this patch, doing si_opaque.so_id = current_stateid
> makes all stateid's unique, regardless of their type.
> Is find_stateid_by_type still needed?
>
> And if the opaque part of the stateid isn't unique,
> shouldn't find_stateid_by_type go over the hash bucket by itself
> to look for other stateid's sharing the same opaque but having
> the type it is looking for?

Stateid's have actually always been unique--they'd have to be, since
e.g. READ doesn't come with any indication of which type of stateid
you're being given. All find_stateid_by_type() does is fail when it
doesn't find something of the right type.

I did think at the time that find_stateid_by_type() was a confusing name
for that reason, but couldn't come up with a better idea. Maybe it
should be find_stateid_of_type() or find_stateid_if_type()....

--b.

2011-10-03 15:13:35

by Benny Halevy

[permalink] [raw]
Subject: Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

On 2011-10-03 16:57, J. Bruce Fields wrote:
> On Mon, Oct 03, 2011 at 04:43:40PM +0200, Benny Halevy wrote:
>> Bruce, it seems with this patch, doing si_opaque.so_id = current_stateid
>> makes all stateid's unique, regardless of their type.
>> Is find_stateid_by_type still needed?
>>
>> And if the opaque part of the stateid isn't unique,
>> shouldn't find_stateid_by_type go over the hash bucket by itself
>> to look for other stateid's sharing the same opaque but having
>> the type it is looking for?
>
> Stateid's have actually always been unique--they'd have to be, since
> e.g. READ doesn't come with any indication of which type of stateid
> you're being given. All find_stateid_by_type() does is fail when it
> doesn't find something of the right type.
>

So I'm still confused. That's what I thought.
So in what cases find_stateid that find_stateid_by_type calls
will find a stateid structure with a non-matching sc_type?

Benny

> I did think at the time that find_stateid_by_type() was a confusing name
> for that reason, but couldn't come up with a better idea. Maybe it
> should be find_stateid_of_type() or find_stateid_if_type()....
>
> --b.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2011-10-04 16:02:10

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

On Tue, Oct 04, 2011 at 05:52:38PM +0200, Benny Halevy wrote:
> OK, I'm going to use the common hash table also for the layout state
> which will have to use the same encoding linage.
>
> It's a non-trivial rewrite of the layout state mechanisms but I
> it seems to simplify the code overall and will be more efficient
> in terms of lookup complexity (hash table vs. linear list)

Note later patches change the stateid lookup a little further, to
per-client lookup based on the "idr" code. (I'm not actually sure what
idr uses underneath--looks like some kind of radix tree from a quick
check.)

I think the changes should all work for layout stateid's too, but let me
know if you run into any problems.

> I'm pretty hosed right now but I'd like to finish this
> before the Bakeathon so we can test the result there.

Great, thanks for keeping that code alive. I won't be able to make the
bakeathon but please bug me and I'll make a special effort to be
responsive to bugs reported from the bakeathon as I know you'll have
limited testing time....

--b.

2011-10-04 15:52:50

by Benny Halevy

[permalink] [raw]
Subject: Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

On 2011-10-03 17:38, J. Bruce Fields wrote:
> On Mon, Oct 03, 2011 at 05:13:24PM +0200, Benny Halevy wrote:
>> On 2011-10-03 16:57, J. Bruce Fields wrote:
>>> On Mon, Oct 03, 2011 at 04:43:40PM +0200, Benny Halevy wrote:
>>>> Bruce, it seems with this patch, doing si_opaque.so_id = current_stateid
>>>> makes all stateid's unique, regardless of their type.
>>>> Is find_stateid_by_type still needed?
>>>>
>>>> And if the opaque part of the stateid isn't unique,
>>>> shouldn't find_stateid_by_type go over the hash bucket by itself
>>>> to look for other stateid's sharing the same opaque but having
>>>> the type it is looking for?
>>>
>>> Stateid's have actually always been unique--they'd have to be, since
>>> e.g. READ doesn't come with any indication of which type of stateid
>>> you're being given. All find_stateid_by_type() does is fail when it
>>> doesn't find something of the right type.
>>>
>>
>> So I'm still confused. That's what I thought.
>> So in what cases find_stateid that find_stateid_by_type calls
>> will find a stateid structure with a non-matching sc_type?
>
> Suppose, for example, the server gets a DELEGRETURN, looks up the
> provided stateid, and finds an open stateid.
>
> At this point either the client is buggy, or else something very
> unlikely has happened. (E.g. a stateid was retired and then reused).
>
> So find_stateid_by_type() returns NULL which the caller will likely
> translate to something like BAD_STATEID.
>
> Other cases: open_confirm and close require an open stateid, ulock or
> lock with the !new_lock_owner case requires a lock stateid, etc.

OK, I'm going to use the common hash table also for the layout state
which will have to use the same encoding linage.

It's a non-trivial rewrite of the layout state mechanisms but I
it seems to simplify the code overall and will be more efficient
in terms of lookup complexity (hash table vs. linear list)

I'm pretty hosed right now but I'd like to finish this
before the Bakeathon so we can test the result there.

Benny

>
> --b.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2011-10-03 15:38:24

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

On Mon, Oct 03, 2011 at 05:13:24PM +0200, Benny Halevy wrote:
> On 2011-10-03 16:57, J. Bruce Fields wrote:
> > On Mon, Oct 03, 2011 at 04:43:40PM +0200, Benny Halevy wrote:
> >> Bruce, it seems with this patch, doing si_opaque.so_id = current_stateid
> >> makes all stateid's unique, regardless of their type.
> >> Is find_stateid_by_type still needed?
> >>
> >> And if the opaque part of the stateid isn't unique,
> >> shouldn't find_stateid_by_type go over the hash bucket by itself
> >> to look for other stateid's sharing the same opaque but having
> >> the type it is looking for?
> >
> > Stateid's have actually always been unique--they'd have to be, since
> > e.g. READ doesn't come with any indication of which type of stateid
> > you're being given. All find_stateid_by_type() does is fail when it
> > doesn't find something of the right type.
> >
>
> So I'm still confused. That's what I thought.
> So in what cases find_stateid that find_stateid_by_type calls
> will find a stateid structure with a non-matching sc_type?

Suppose, for example, the server gets a DELEGRETURN, looks up the
provided stateid, and finds an open stateid.

At this point either the client is buggy, or else something very
unlikely has happened. (E.g. a stateid was retired and then reused).

So find_stateid_by_type() returns NULL which the caller will likely
translate to something like BAD_STATEID.

Other cases: open_confirm and close require an open stateid, ulock or
lock with the !new_lock_owner case requires a lock stateid, etc.

--b.

2011-10-03 14:48:51

by Benny Halevy

[permalink] [raw]
Subject: Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter

Bruce, it seems with this patch, doing si_opaque.so_id = current_stateid
makes all stateid's unique, regardless of their type.
Is find_stateid_by_type still needed?

And if the opaque part of the stateid isn't unique,
shouldn't find_stateid_by_type go over the hash bucket by itself
to look for other stateid's sharing the same opaque but having
the type it is looking for?

Benny

On 2011-09-19 16:15, J. Bruce Fields wrote:
> Including the full clientid in the on-the-wire stateid allows more
> reliable detection of bad vs. expired stateid's, simplifies code, and
> ensures we won't reuse the opaque part of the stateid (as we currently
> do when the same openowner closes and reopens the same file).
>
> Signed-off-by: J. Bruce Fields <[email protected]>
> ---
> fs/nfsd/nfs4state.c | 58 +++++++++++---------------------------------------
> fs/nfsd/state.h | 18 ++++-----------
> 2 files changed, 18 insertions(+), 58 deletions(-)
>
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index fdd03f6..922f47d 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -49,9 +49,7 @@
> time_t nfsd4_lease = 90; /* default lease time */
> time_t nfsd4_grace = 90;
> static time_t boot_time;
> -static u32 current_ownerid = 1;
> -static u32 current_fileid = 1;
> -static u32 current_delegid = 1;
> +static u32 current_stateid = 1;
> static stateid_t zerostateid; /* bits all 0 */
> static stateid_t onestateid; /* bits all 1 */
> static u64 current_sessionid = 1;
> @@ -136,11 +134,6 @@ unsigned int max_delegations;
> #define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS)
> #define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1)
>
> -static unsigned int open_ownerid_hashval(const u32 id)
> -{
> - return id & OPEN_OWNER_HASH_MASK;
> -}
> -
> static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
> {
> unsigned int ret;
> @@ -150,7 +143,6 @@ static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *owner
> return ret & OPEN_OWNER_HASH_MASK;
> }
>
> -static struct list_head open_ownerid_hashtbl[OPEN_OWNER_HASH_SIZE];
> static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
>
> /* hash table for nfs4_file */
> @@ -255,9 +247,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
> dp->dl_file = fp;
> dp->dl_type = type;
> dp->dl_stid.sc_type = NFS4_DELEG_STID;
> - dp->dl_stid.sc_stateid.si_boot = boot_time;
> - dp->dl_stid.sc_stateid.si_stateownerid = current_delegid++;
> - dp->dl_stid.sc_stateid.si_fileid = 0;
> + dp->dl_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
> + dp->dl_stid.sc_stateid.si_opaque.so_id = current_stateid++;
> dp->dl_stid.sc_stateid.si_generation = 1;
> hash_stid(&dp->dl_stid);
> fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
> @@ -457,7 +448,6 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
> {
> struct nfs4_ol_stateid *stp;
>
> - list_del(&lo->lo_owner.so_idhash);
> list_del(&lo->lo_owner.so_strhash);
> list_del(&lo->lo_perstateid);
> while (!list_empty(&lo->lo_owner.so_stateids)) {
> @@ -502,7 +492,6 @@ static void unhash_openowner(struct nfs4_openowner *oo)
> {
> struct nfs4_ol_stateid *stp;
>
> - list_del(&oo->oo_owner.so_idhash);
> list_del(&oo->oo_owner.so_strhash);
> list_del(&oo->oo_perclient);
> while (!list_empty(&oo->oo_owner.so_stateids)) {
> @@ -1081,9 +1070,8 @@ static void gen_confirm(struct nfs4_client *clp)
> static int
> same_stateid(stateid_t *id_one, stateid_t *id_two)
> {
> - if (id_one->si_stateownerid != id_two->si_stateownerid)
> - return 0;
> - return id_one->si_fileid == id_two->si_fileid;
> + return 0 == memcmp(&id_one->si_opaque, &id_two->si_opaque,
> + sizeof(stateid_opaque_t));
> }
>
> static struct nfs4_stid *find_stateid(stateid_t *t)
> @@ -2198,7 +2186,6 @@ alloc_init_file(struct inode *ino)
> INIT_LIST_HEAD(&fp->fi_stateids);
> INIT_LIST_HEAD(&fp->fi_delegations);
> fp->fi_inode = igrab(ino);
> - fp->fi_id = current_fileid++;
> fp->fi_had_conflict = false;
> fp->fi_lease = NULL;
> memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
> @@ -2295,7 +2282,6 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
> sop->so_owner.len = owner->len;
>
> INIT_LIST_HEAD(&sop->so_stateids);
> - sop->so_id = current_ownerid++;
> sop->so_client = clp;
> init_nfs4_replay(&sop->so_replay);
> return sop;
> @@ -2303,10 +2289,6 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
>
> static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
> {
> - unsigned int idhashval;
> -
> - idhashval = open_ownerid_hashval(oo->oo_owner.so_id);
> - list_add(&oo->oo_owner.so_idhash, &open_ownerid_hashtbl[idhashval]);
> list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]);
> list_add(&oo->oo_perclient, &clp->cl_openowners);
> }
> @@ -2331,6 +2313,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
> static inline void
> init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
> struct nfs4_openowner *oo = open->op_openowner;
> + struct nfs4_client *clp = oo->oo_owner.so_client;
>
> INIT_LIST_HEAD(&stp->st_lockowners);
> list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
> @@ -2339,9 +2322,8 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd
> stp->st_stateowner = &oo->oo_owner;
> get_nfs4_file(fp);
> stp->st_file = fp;
> - stp->st_stid.sc_stateid.si_boot = boot_time;
> - stp->st_stid.sc_stateid.si_stateownerid = oo->oo_owner.so_id;
> - stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
> + stp->st_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
> + stp->st_stid.sc_stateid.si_opaque.so_id = current_stateid++;
> /* note will be incremented before first return to client: */
> stp->st_stid.sc_stateid.si_generation = 0;
> hash_stid(&stp->st_stid);
> @@ -3095,8 +3077,6 @@ nfs4_laundromat(void)
> test_val = u;
> break;
> }
> - dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
> - oo->oo_owner.so_id);
> release_openowner(oo);
> }
> if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
> @@ -3141,7 +3121,7 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
> static int
> STALE_STATEID(stateid_t *stateid)
> {
> - if (stateid->si_boot == boot_time)
> + if (stateid->si_opaque.so_clid.cl_boot == boot_time)
> return 0;
> dprintk("NFSD: stale stateid " STATEID_FMT "!\n",
> STATEID_VAL(stateid));
> @@ -3710,11 +3690,6 @@ last_byte_offset(u64 start, u64 len)
> return end > start ? end - 1: NFS4_MAX_UINT64;
> }
>
> -static unsigned int lockownerid_hashval(u32 id)
> -{
> - return id & LOCK_HASH_MASK;
> -}
> -
> static inline unsigned int
> lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
> struct xdr_netobj *ownername)
> @@ -3724,7 +3699,6 @@ lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
> & LOCK_HASH_MASK;
> }
>
> -static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
> static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
>
> /*
> @@ -3795,10 +3769,6 @@ find_lockowner_str(struct inode *inode, clientid_t *clid,
>
> static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
> {
> - unsigned int idhashval;
> -
> - idhashval = lockownerid_hashval(lo->lo_owner.so_id);
> - list_add(&lo->lo_owner.so_idhash, &lock_ownerid_hashtbl[idhashval]);
> list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]);
> list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
> }
> @@ -3831,6 +3801,7 @@ static struct nfs4_ol_stateid *
> alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
> {
> struct nfs4_ol_stateid *stp;
> + struct nfs4_client *clp = lo->lo_owner.so_client;
>
> stp = nfs4_alloc_stateid();
> if (stp == NULL)
> @@ -3841,9 +3812,8 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
> stp->st_stid.sc_type = NFS4_LOCK_STID;
> get_nfs4_file(fp);
> stp->st_file = fp;
> - stp->st_stid.sc_stateid.si_boot = boot_time;
> - stp->st_stid.sc_stateid.si_stateownerid = lo->lo_owner.so_id;
> - stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
> + stp->st_stid.sc_stateid.si_opaque.so_clid = clp->cl_clientid;
> + stp->st_stid.sc_stateid.si_opaque.so_id = current_stateid++;
> /* note will be incremented before first return to client: */
> stp->st_stid.sc_stateid.si_generation = 0;
> hash_stid(&stp->st_stid);
> @@ -4252,7 +4222,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
> * data structures. */
> INIT_LIST_HEAD(&matches);
> for (i = 0; i < LOCK_HASH_SIZE; i++) {
> - list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
> + list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) {
> if (!same_owner_str(sop, owner, clid))
> continue;
> list_for_each_entry(stp, &sop->so_stateids,
> @@ -4398,12 +4368,10 @@ nfs4_state_init(void)
> }
> for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
> INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
> - INIT_LIST_HEAD(&open_ownerid_hashtbl[i]);
> }
> for (i = 0; i < STATEID_HASH_SIZE; i++)
> INIT_LIST_HEAD(&stateid_hashtbl[i]);
> for (i = 0; i < LOCK_HASH_SIZE; i++) {
> - INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]);
> INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
> }
> memset(&onestateid, ~0, sizeof(stateid_t));
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index e807abb..d6aec4f 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -45,24 +45,20 @@ typedef struct {
> } clientid_t;
>
> typedef struct {
> - u32 so_boot;
> - u32 so_stateownerid;
> - u32 so_fileid;
> + clientid_t so_clid;
> + u32 so_id;
> } stateid_opaque_t;
>
> typedef struct {
> u32 si_generation;
> stateid_opaque_t si_opaque;
> } stateid_t;
> -#define si_boot si_opaque.so_boot
> -#define si_stateownerid si_opaque.so_stateownerid
> -#define si_fileid si_opaque.so_fileid
>
> #define STATEID_FMT "(%08x/%08x/%08x/%08x)"
> #define STATEID_VAL(s) \
> - (s)->si_boot, \
> - (s)->si_stateownerid, \
> - (s)->si_fileid, \
> + (s)->si_opaque.so_clid.cl_boot, \
> + (s)->si_opaque.so_clid.cl_id, \
> + (s)->si_opaque.so_id, \
> (s)->si_generation
>
> struct nfsd4_callback {
> @@ -353,11 +349,9 @@ struct nfs4_replay {
> */
>
> struct nfs4_stateowner {
> - struct list_head so_idhash; /* hash by so_id */
> struct list_head so_strhash; /* hash by op_name */
> struct list_head so_stateids;
> int so_is_open_owner; /* 1=openowner,0=lockowner */
> - u32 so_id;
> struct nfs4_client * so_client;
> /* after increment in ENCODE_SEQID_OP_TAIL, represents the next
> * sequence id expected from the client: */
> @@ -415,8 +409,6 @@ struct nfs4_file {
> struct file_lock *fi_lease;
> atomic_t fi_delegees;
> struct inode *fi_inode;
> - u32 fi_id; /* used with stateowner->so_id
> - * for stateid_hashtbl hash */
> bool fi_had_conflict;
> };
>

2011-11-08 22:59:09

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 2/3] nfsd4: share open and lock owner hash tables

From: "J. Bruce Fields" <[email protected]>

Now that they're used in the same way, it's a little simpler to put open
and lock owners in the same hash table, and I can't see a reason not to.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 71 +++++++++++++++++++++++----------------------------
1 files changed, 32 insertions(+), 39 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index eec9900..dcbe7f3 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -133,21 +133,21 @@ unsigned int max_delegations;
* Open owner state (share locks)
*/

-/* hash tables for open owners */
-#define OPEN_OWNER_HASH_BITS 8
-#define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS)
-#define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1)
+/* hash tables for lock and open owners */
+#define OWNER_HASH_BITS 8
+#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
+#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)

-static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
+static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
{
unsigned int ret;

ret = opaque_hashval(ownername->data, ownername->len);
ret += clientid;
- return ret & OPEN_OWNER_HASH_MASK;
+ return ret & OWNER_HASH_MASK;
}

-static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
+static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];

/* hash table for nfs4_file */
#define FILE_HASH_BITS 8
@@ -2373,7 +2373,7 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj

static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
{
- list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]);
+ list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
list_add(&oo->oo_perclient, &clp->cl_openowners);
}

@@ -2436,7 +2436,9 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
struct nfs4_stateowner *so;
struct nfs4_openowner *oo;

- list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) {
+ list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
+ if (!so->so_is_open_owner)
+ continue;
if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
oo = openowner(so);
renew_client(oo->oo_owner.so_client);
@@ -2580,7 +2582,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
if (open->op_file == NULL)
return nfserr_jukebox;

- strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner);
+ strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
oo = find_openstateowner_str(strhashval, open);
open->op_openowner = oo;
if (!oo) {
@@ -3718,13 +3720,7 @@ out:
}


-/*
- * Lock owner state (byte-range locks)
- */
#define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start))
-#define LOCK_HASH_BITS 8
-#define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS)
-#define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1)

static inline u64
end_offset(u64 start, u64 len)
@@ -3746,8 +3742,6 @@ last_byte_offset(u64 start, u64 len)
return end > start ? end - 1: NFS4_MAX_UINT64;
}

-static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
-
/*
* TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
* we can't properly handle lock requests that go beyond the (2^63 - 1)-th
@@ -3815,11 +3809,13 @@ static struct nfs4_lockowner *
find_lockowner_str(struct inode *inode, clientid_t *clid,
struct xdr_netobj *owner)
{
- unsigned int hashval = open_ownerstr_hashval(clid->cl_id, owner);
+ unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
struct nfs4_lockowner *lo;
struct nfs4_stateowner *op;

- list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
+ list_for_each_entry(op, &ownerstr_hashtbl[hashval], so_strhash) {
+ if (op->so_is_open_owner)
+ continue;
lo = lockowner(op);
if (same_lockowner_ino(lo, inode, clid, owner))
return lo;
@@ -3829,7 +3825,7 @@ find_lockowner_str(struct inode *inode, clientid_t *clid,

static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
{
- list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]);
+ list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
}

@@ -3838,7 +3834,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s
* Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
* occurred.
*
- * strhashval = open_ownerstr_hashval
+ * strhashval = ownerstr_hashval
*/

static struct nfs4_lockowner *
@@ -3913,7 +3909,7 @@ __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct n
struct nfs4_ol_stateid, st_perstateowner);
return nfs_ok;
}
- strhashval = open_ownerstr_hashval(cl->cl_clientid.cl_id,
+ strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
&lock->v.new.owner);
lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
if (lo == NULL)
@@ -4277,7 +4273,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
struct nfs4_ol_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner;
struct list_head matches;
- unsigned int hashval = open_ownerstr_hashval(clid->cl_id, owner);
+ unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
__be32 status;

dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
@@ -4294,7 +4290,9 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
status = nfserr_locks_held;
INIT_LIST_HEAD(&matches);

- list_for_each_entry(sop, &lock_ownerstr_hashtbl[hashval], so_strhash) {
+ list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) {
+ if (sop->so_is_open_owner)
+ continue;
if (!same_owner_str(sop, owner, clid))
continue;
list_for_each_entry(stp, &sop->so_stateids,
@@ -4444,16 +4442,16 @@ static void release_openowner_sop(struct nfs4_stateowner *sop)
release_openowner(openowner(sop));
}

-static int nfsd_release_n_owners(u64 num,
- struct list_head hashtbl[],
- unsigned int hashtbl_size,
+static int nfsd_release_n_owners(u64 num, bool is_open_owner
void (*release_sop)(struct nfs4_stateowner *))
{
int i, count = 0;
struct nfs4_stateowner *sop, *next;

- for (i = 0; i < hashtbl_size; i++) {
- list_for_each_entry_safe(sop, next, &hashtbl[i], so_strhash) {
+ for (i = 0; i < OWNER_HASH_SIZE; i++) {
+ list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) {
+ if (sop->so_is_open_owner != is_open_owner)
+ continue;
release_sop(sop);
if (++count == num)
return count;
@@ -4467,8 +4465,7 @@ void nfsd_forget_locks(u64 num)
int count;

nfs4_lock_state();
- count = nfsd_release_n_owners(num, lock_ownerstr_hashtbl,
- LOCK_HASH_SIZE, release_lockowner_sop);
+ count = nfsd_release_n_owners(num, false, release_lockowner_sop);
nfs4_unlock_state();

printk(KERN_INFO "NFSD: Forgot %d locks", count);
@@ -4479,8 +4476,7 @@ void nfsd_forget_openowners(u64 num)
int count;

nfs4_lock_state();
- count = nfsd_release_n_owners(num, open_ownerstr_hashtbl,
- OPEN_OWNER_HASH_SIZE, release_openowner_sop);
+ count = nfsd_release_n_owners(num, true, release_openowner_sop);
nfs4_unlock_state();

printk(KERN_INFO "NFSD: Forgot %d open owners", count);
@@ -4549,11 +4545,8 @@ nfs4_state_init(void)
for (i = 0; i < FILE_HASH_SIZE; i++) {
INIT_LIST_HEAD(&file_hashtbl[i]);
}
- for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
- }
- for (i = 0; i < LOCK_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
+ for (i = 0; i < OWNER_HASH_SIZE; i++) {
+ INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
}
memset(&onestateid, ~0, sizeof(stateid_t));
INIT_LIST_HEAD(&close_lru);
--
1.7.5.4


2011-11-08 22:57:54

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 00/25] nfsd4 state cleanup

On Wed, Sep 14, 2011 at 07:44:56AM -0400, J. Bruce Fields wrote:
> And then also still to do:
> - close replays: we keep around a stateid to handle close
> replays only in the case where it's the last stateid for an
> openowner, but that's not sufficient.
> - the data structures aren't really right for the things we need
> to do: e.g. release_lockowner currently does a linear search
> through all the lockowners!

OK, done, with the following patches, and that was the last thing on
this particular todo list.

I've also started a for-3.3 tree based on v3.2-rc1, including Bryan's
patches and some previous state code patches (not the following yet).

--b.

> - multiple client-to-lockowner locks for a given (owner, file)
> aren't handled right.
> - I need to look again at doing a better job of distinguishing
> the bad, expired, and stale cases for stateid's.
>
> I was hoping to have that ready for 3.2 but unfortunately keep running
> across small bugs or cleanup opportunities like these along the way;
> perhaps next week....

2011-11-08 22:59:09

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 1/3] nfsd4: hash lockowners to simplify RELEASE_LOCKOWNER

From: "J. Bruce Fields" <[email protected]>

Hash lockowners on just the owner string rather than on (owner, inode).
This makes the owner-string lookup needed for RELEASE_LOCKOWNER simpler
(currently it's doing at a linear search through the entire hash
table!). That may come at the expense of making (owner, inode) lookups
more expensive if a client reuses the same lockowner across multiple
files. We might add a separate lookup for that.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 42 ++++++++++++++----------------------------
1 files changed, 14 insertions(+), 28 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1d6812d..eec9900 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3746,15 +3746,6 @@ last_byte_offset(u64 start, u64 len)
return end > start ? end - 1: NFS4_MAX_UINT64;
}

-static inline unsigned int
-lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
- struct xdr_netobj *ownername)
-{
- return (file_hashval(inode) + cl_id
- + opaque_hashval(ownername->data, ownername->len))
- & LOCK_HASH_MASK;
-}
-
static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];

/*
@@ -3824,7 +3815,7 @@ static struct nfs4_lockowner *
find_lockowner_str(struct inode *inode, clientid_t *clid,
struct xdr_netobj *owner)
{
- unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner);
+ unsigned int hashval = open_ownerstr_hashval(clid->cl_id, owner);
struct nfs4_lockowner *lo;
struct nfs4_stateowner *op;

@@ -3847,7 +3838,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s
* Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
* occurred.
*
- * strhashval = lock_ownerstr_hashval
+ * strhashval = open_ownerstr_hashval
*/

static struct nfs4_lockowner *
@@ -3922,7 +3913,7 @@ __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct n
struct nfs4_ol_stateid, st_perstateowner);
return nfs_ok;
}
- strhashval = lock_ownerstr_hashval(fi->fi_inode, cl->cl_clientid.cl_id,
+ strhashval = open_ownerstr_hashval(cl->cl_clientid.cl_id,
&lock->v.new.owner);
lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
if (lo == NULL)
@@ -4286,7 +4277,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
struct nfs4_ol_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner;
struct list_head matches;
- int i;
+ unsigned int hashval = open_ownerstr_hashval(clid->cl_id, owner);
__be32 status;

dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
@@ -4301,22 +4292,17 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
nfs4_lock_state();

status = nfserr_locks_held;
- /* XXX: we're doing a linear search through all the lockowners.
- * Yipes! For now we'll just hope clients aren't really using
- * release_lockowner much, but eventually we have to fix these
- * data structures. */
INIT_LIST_HEAD(&matches);
- for (i = 0; i < LOCK_HASH_SIZE; i++) {
- list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) {
- if (!same_owner_str(sop, owner, clid))
- continue;
- list_for_each_entry(stp, &sop->so_stateids,
- st_perstateowner) {
- lo = lockowner(sop);
- if (check_for_locks(stp->st_file, lo))
- goto out;
- list_add(&lo->lo_list, &matches);
- }
+
+ list_for_each_entry(sop, &lock_ownerstr_hashtbl[hashval], so_strhash) {
+ if (!same_owner_str(sop, owner, clid))
+ continue;
+ list_for_each_entry(stp, &sop->so_stateids,
+ st_perstateowner) {
+ lo = lockowner(sop);
+ if (check_for_locks(stp->st_file, lo))
+ goto out;
+ list_add(&lo->lo_list, &matches);
}
}
/* Clients probably won't expect us to return with some (but not all)
--
1.7.5.4


2011-11-08 22:59:09

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 3/3] nfsd4: add a separate (lockowner, inode) lookup

From: "J. Bruce Fields" <[email protected]>

Address the possible performance regression mentioned in "nfsd4: hash
lockowners to simplify RELEASE_LOCKOWNER" by providing a separate
(lockowner, inode) hash.

Really, I doubt this matters much, but I think it's likely we'll change
these data structures here and I'd rather that the need for (owner,
inode) lookups be well-documented.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 29 +++++++++++++++++++++++------
fs/nfsd/state.h | 1 +
2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index dcbe7f3..d4bd698 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -514,6 +514,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)

list_del(&lo->lo_owner.so_strhash);
list_del(&lo->lo_perstateid);
+ list_del(&lo->lo_owner_ino_hash);
while (!list_empty(&lo->lo_owner.so_stateids)) {
stp = list_first_entry(&lo->lo_owner.so_stateids,
struct nfs4_ol_stateid, st_perstateowner);
@@ -3722,6 +3723,10 @@ out:

#define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start))

+#define LOCKOWNER_INO_HASH_BITS 8
+#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS)
+#define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1)
+
static inline u64
end_offset(u64 start, u64 len)
{
@@ -3742,6 +3747,15 @@ last_byte_offset(u64 start, u64 len)
return end > start ? end - 1: NFS4_MAX_UINT64;
}

+static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername)
+{
+ return (file_hashval(inode) + cl_id
+ + opaque_hashval(ownername->data, ownername->len))
+ & LOCKOWNER_INO_HASH_MASK;
+}
+
+static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE];
+
/*
* TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
* we can't properly handle lock requests that go beyond the (2^63 - 1)-th
@@ -3809,14 +3823,10 @@ static struct nfs4_lockowner *
find_lockowner_str(struct inode *inode, clientid_t *clid,
struct xdr_netobj *owner)
{
- unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
+ unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner);
struct nfs4_lockowner *lo;
- struct nfs4_stateowner *op;

- list_for_each_entry(op, &ownerstr_hashtbl[hashval], so_strhash) {
- if (op->so_is_open_owner)
- continue;
- lo = lockowner(op);
+ list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
if (same_lockowner_ino(lo, inode, clid, owner))
return lo;
}
@@ -3825,7 +3835,12 @@ find_lockowner_str(struct inode *inode, clientid_t *clid,

static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
{
+ struct inode *inode = open_stp->st_file->fi_inode;
+ unsigned int inohash = lockowner_ino_hashval(inode,
+ clp->cl_clientid.cl_id, &lo->lo_owner.so_owner);
+
list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
+ list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]);
list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
}

@@ -4548,6 +4563,8 @@ nfs4_state_init(void)
for (i = 0; i < OWNER_HASH_SIZE; i++) {
INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
}
+ for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]);
memset(&onestateid, ~0, sizeof(stateid_t));
INIT_LIST_HEAD(&close_lru);
INIT_LIST_HEAD(&client_lru);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index a3cf384..89c2cd8 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -366,6 +366,7 @@ struct nfs4_openowner {

struct nfs4_lockowner {
struct nfs4_stateowner lo_owner; /* must be first element */
+ struct list_head lo_owner_ino_hash; /* hash by owner,file */
struct list_head lo_perstateid; /* for lockowners only */
struct list_head lo_list; /* for temporary uses */
};
--
1.7.5.4