nfsd4 state cleanup
Subsystems (2)
cover 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(-)
Signature · 1 line
1.7.4.1
PATCH 1/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.
--- fs/nfsd/nfs4state.c | 25 ++++--------------------- fs/nfsd/nfs4xdr.c | 34 +++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 36 deletions(-)
fs/nfsd/nfs4state.c +4 -21
@@ -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;
fs/nfsd/nfs4xdr.c +19 -15
@@ -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_cif (!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_loelse 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_lif (!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, structif (!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, strucif (!nfserr)nfsd4_encode_stateid (resp, &od->od_stateid); -ENCODE_SEQID_OP_TAIL (od->od_stateowner); +encode_seqid_op_tail (resp, save, nfserr);return nfserr; }
Signature · 1 line
1.7.4.1
PATCH 2/25 nfsd4: cleanup seqid op stateowner usage
In reply to J. Bruce FieldsNow 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().
--- fs/nfsd/nfs4state.c | 57 +++++++++++++++++++++----------------------------- fs/nfsd/nfs4xdr.c | 5 ---- fs/nfsd/xdr4.h | 7 ------ 3 files changed, 24 insertions(+), 45 deletions(-)
fs/nfsd/nfs4state.c +24 -33
@@ -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 ;
fs/nfsd/nfs4xdr.c +0 -5
@@ -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;
fs/nfsd/xdr4.h +0 -7
@@ -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; };
Signature · 1 line
1.7.4.1
PATCH 3/25 nfsd4: extend state lock over seqid replay logic
In reply to J. Bruce FieldsThere 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.
--- fs/nfsd/nfs4proc.c | 5 +++-- fs/nfsd/nfs4state.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-)
fs/nfsd/nfs4proc.c +3 -2
@@ -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 ; }
fs/nfsd/nfs4state.c +8 -4
@@ -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; }
Signature · 1 line
1.7.4.1
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
Quoted 84 lines · J. Bruce Fields
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(-)fs/nfsd/nfs4proc.c +3
-2@@ -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 ; }fs/nfsd/nfs4state.c +8
-4@@ -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; }
Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic
Quoted 3 lines · Bryan Schumaker
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.
Quoted 129 lines
[ 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 datetimef =
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
Quoted 84 lines · J. Bruce Fields
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(-)fs/nfsd/nfs4proc.c +3
-2@@ -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 ; }fs/nfsd/nfs4state.c +8
-4@@ -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; }
Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic
In reply to Bryan SchumakerQuoted 1 line · Bryan Schumaker
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]>fs/nfsd/nfs4state.c +2 -1
@@ -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:
Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic
Quoted 4 lines · J. Bruce Fields
Quoted 1 line · Bryan Schumaker
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!
Quoted 61 lines
--b.
commit
8da87285a245c82d23183414cec7069f18721afdAuthor: J. Bruce Fields <[email protected]> Date: Tue Sep 27 21:42:29 2011 -0400nfsd4: 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]>fs/nfsd/nfs4state.c +2
-2@@ -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
Re: [PATCH 03/25] nfsd4: extend state lock over seqid replay logic
Quoted 7 lines · Bryan Schumaker
Quoted 4 lines · J. Bruce Fields
Quoted 1 line · Bryan Schumaker
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.
Quoted 62 lines
Quoted 61 lines
--b.
commit
8da87285a245c82d23183414cec7069f18721afdAuthor: J. Bruce Fields <[email protected]> Date: Tue Sep 27 21:42:29 2011 -0400nfsd4: 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]>fs/nfsd/nfs4state.c +2
-2@@ -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
PATCH 4/25 nfsd4: eliminate impossible open replay case
In reply to J. Bruce FieldsIf 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.
--- fs/nfsd/nfs4state.c | 14 ++------------ 1 files changed, 2 insertions(+), 12 deletions(-)
fs/nfsd/nfs4state.c +2 -12
@@ -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:
Signature · 1 line
1.7.4.1
PATCH 5/25 nfsd4: drop most stateowner refcounting
In reply to J. Bruce FieldsMaybe we'll bring it back some day, but we don't have much real use for it now.
--- 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(-)
fs/nfsd/nfs4proc.c +2 -4
@@ -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: */
fs/nfsd/nfs4state.c +12 -11
@@ -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 ; }
fs/nfsd/nfs4xdr.c +6 -5
@@ -2570,17 +2570,18 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fhstatic 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 */
fs/nfsd/state.h +1 -14
@@ -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 */
fs/nfsd/xdr4.h +1 -1
@@ -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;
Signature · 1 line
1.7.4.1
PATCH 6/25 nfsd4: eliminate unused lt_stateowner
In reply to J. Bruce FieldsThis is used only as a local variable.
--- fs/nfsd/nfs4state.c | 8 ++++---- fs/nfsd/xdr4.h | 1 - 2 files changed, 4 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c +4 -4
@@ -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 ;
fs/nfsd/xdr4.h +0 -1
@@ -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; };
Signature · 1 line
1.7.4.1
PATCH 7/25 nfsd4: share common seqid checks
In reply to J. Bruce Fields--- fs/nfsd/nfs4state.c | 41 +++++++++++++++++++++-------------------- 1 files changed, 21 insertions(+), 20 deletions(-)
fs/nfsd/nfs4state.c +21 -20
@@ -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
Signature · 1 line
1.7.4.1
PATCH 8/25 nfsd4: simplify check_open logic
In reply to J. Bruce FieldsSometimes the single-exit style is good, sometimes it's unnecessarily convoluted....
--- fs/nfsd/nfs4state.c | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c +2 -5
@@ -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 *
Signature · 1 line
1.7.4.1
PATCH 9/25 nfsd4: move double-confirm test to open_confirm
In reply to J. Bruce FieldsI don't see the point of having this check in nfs4_preprocess_seqid_op() when it's only needed by the one caller.
--- fs/nfsd/nfs4state.c | 12 +++++------- 1 files changed, 5 insertions(+), 7 deletions(-)
fs/nfsd/nfs4state.c +5 -7
@@ -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 ();
Signature · 1 line
1.7.4.1
PATCH 10/25 nfsd4: move CLOSE_STATE special case to caller
In reply to J. Bruce FieldsMove the CLOSE_STATE case into the unique caller that cares about it rather than putting it in preprocess_seqid_op.
--- fs/nfsd/nfs4state.c | 56 ++++++++++++++++++++++++-------------------------- fs/nfsd/state.h | 1 - 2 files changed, 27 insertions(+), 30 deletions(-)
fs/nfsd/nfs4state.c +27 -29
@@ -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;
fs/nfsd/state.h +0 -1
@@ -448,7 +448,6 @@ struct nfs4_stateid {#define LOCK_STATE 0x00000008#define RD_STATE 0x00000010#define WR_STATE 0x00000020 -#define CLOSE_STATE 0x00000040struct nfsd4_compound_state ;
Signature · 1 line
1.7.4.1
PATCH 11/25 nfsd4: split stateowners into open and lockowners
In reply to J. Bruce FieldsThe 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.
--- 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(-)
fs/nfsd/nfs4proc.c +9 -9
@@ -250,7 +250,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ofh_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, ¤t_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;
fs/nfsd/nfs4state.c +186 -181
836 lines not on this page · raw message
fs/nfsd/nfs4xdr.c +1 -1
@@ -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));
fs/nfsd/state.h +27 -6
@@ -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);
fs/nfsd/xdr4.h +1 -1
@@ -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
Signature · 1 line
1.7.4.1
PATCH 12/25 nfsd4: split out some free_generic_stateid code
In reply to J. Bruce FieldsWe'll use this elsewhere.
--- fs/nfsd/nfs4state.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
fs/nfsd/nfs4state.c +8 -1
@@ -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); }
Signature · 1 line
1.7.4.1
PATCH 13/25 nfsd4: rearrange to avoid a forward reference
In reply to J. Bruce Fields--- fs/nfsd/nfs4state.c | 53 +++++++++++++++++++++++++-------------------------- 1 files changed, 26 insertions(+), 27 deletions(-)
fs/nfsd/nfs4state.c +26 -27
@@ -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) {
Signature · 1 line
1.7.4.1
PATCH 14/25 nfsd4: split up find_stateid
In reply to J. Bruce FieldsMinor cleanup.
--- fs/nfsd/nfs4state.c | 34 +++++++++++++++++++++------------- 1 files changed, 21 insertions(+), 13 deletions(-)
fs/nfsd/nfs4state.c +21 -13
@@ -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;
Signature · 1 line
1.7.4.1
PATCH 15/25 nfsd4: split preprocess_seqid, cleanup
In reply to J. Bruce FieldsMove most of this into helper functions. Also move the non-CONFIRM case into caller, providing a helper function for that purpose.
--- fs/nfsd/nfs4state.c | 87 ++++++++++++++++++++++++++------------------------ fs/nfsd/state.h | 1 - 2 files changed, 45 insertions(+), 43 deletions(-)
fs/nfsd/nfs4state.c +45 -42
@@ -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);
fs/nfsd/state.h +0 -1
@@ -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
Signature · 1 line
1.7.4.1
PATCH 16/25 nfsd4: pass around typemask instead of flags
In reply to J. Bruce FieldsWe're only using those flags to choose lock or open stateid's at this point.
--- fs/nfsd/nfs4state.c | 18 ++++++++---------- fs/nfsd/state.h | 2 -- 2 files changed, 8 insertions(+), 12 deletions(-)
fs/nfsd/nfs4state.c +8 -10
@@ -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 *csstruct 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);
fs/nfsd/state.h +0 -2
@@ -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
Signature · 1 line
1.7.4.1
PATCH 17/25 nfsd4: rename init_stateid
In reply to J. Bruce FieldsNote this is actually open-stateid specific.
--- fs/nfsd/nfs4state.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
fs/nfsd/nfs4state.c +2 -2
@@ -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);
Signature · 1 line
1.7.4.1
PATCH 18/25 nfsd4: remove redundant stateid initialization
In reply to J. Bruce Fields--- fs/nfsd/nfs4state.c | 7 ------- 1 files changed, 0 insertions(+), 7 deletions(-)
fs/nfsd/nfs4state.c +0 -7
@@ -2318,10 +2318,7 @@ init_open_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_ostruct 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);
Signature · 1 line
1.7.4.1
PATCH 19/25 nfsd4: move some of nfs4_stateid into a separate structure
In reply to J. Bruce FieldsWe 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.
--- fs/nfsd/nfs4state.c | 174 +++++++++++++++++++++++++------------------------- fs/nfsd/state.h | 29 ++++++--- 2 files changed, 106 insertions(+), 97 deletions(-)
fs/nfsd/nfs4state.c +87 -87
@@ -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_statereturn 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 nfstruct 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, strreturn 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;
fs/nfsd/state.h +19 -10
@@ -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
Signature · 1 line
1.7.4.1
PATCH 20/25 nfsd4: add common dl_stid field to delegation
In reply to J. Bruce Fields--- fs/nfsd/nfs4callback.c | 2 +- fs/nfsd/nfs4state.c | 20 ++++++++++---------- fs/nfsd/state.h | 20 +++++++++++--------- 3 files changed, 22 insertions(+), 20 deletions(-)
fs/nfsd/nfs4callback.c +1 -1
@@ -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 */
fs/nfsd/nfs4state.c +10 -10
@@ -247,10 +247,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svget_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, ¤t_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; } }
fs/nfsd/state.h +11 -9
@@ -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;
Signature · 1 line
1.7.4.1
PATCH 21/25 nfsd4: share common stid-hashing helper function
In reply to J. Bruce Fields--- fs/nfsd/nfs4state.c | 15 +++++++++++---- 1 files changed, 11 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +11 -4
@@ -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, strstatic 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;
Signature · 1 line
1.7.4.1
PATCH 22/25 nfsd4: hash deleg stateid's like any other
In reply to J. Bruce FieldsIt's simpler to look up delegation stateid's in the same hash table as any other stateid.
--- fs/nfsd/nfs4state.c | 112 +++++++++++++++++++++------------------------------ fs/nfsd/state.h | 5 ++ 2 files changed, 51 insertions(+), 66 deletions(-)
fs/nfsd/nfs4state.c +46 -66
@@ -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 svget_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, ¤t_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
fs/nfsd/state.h +5 -0
@@ -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 */
Signature · 1 line
1.7.4.1
PATCH 23/25 nfsd4: fix test_stateid for delegation stateid's
In reply to J. Bruce FieldsTest_stateid should handle delegation stateid's as well.
--- fs/nfsd/nfs4state.c | 34 ++++++++++++++++------------------ 1 files changed, 16 insertions(+), 18 deletions(-)
fs/nfsd/nfs4state.c +16 -18
@@ -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; }/*
Signature · 1 line
1.7.4.1
PATCH 24/25 nfsd4: use deleg changes to cleanup preprocess_stateid_op
In reply to J. Bruce Fields--- fs/nfsd/nfs4state.c | 24 ++++++++++-------------- 1 files changed, 10 insertions(+), 14 deletions(-)
fs/nfsd/nfs4state.c +10 -14
@@ -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;
Signature · 1 line
1.7.4.1
PATCH 25/25 nfsd4: better stateid hashing
In reply to J. Bruce FieldsFirst, 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.)
--- fs/nfsd/nfs4state.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +4 -4
@@ -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;
Signature · 1 line
1.7.4.1
Quoted 11 lines · J. Bruce Fields
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.
Quoted 4 lines
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.
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.
--- fs/nfsd/nfs4proc.c | 4 ++-- fs/nfsd/nfs4state.c | 24 ++++++++++++------------ fs/nfsd/state.h | 3 ++- 3 files changed, 16 insertions(+), 15 deletions(-)
fs/nfsd/nfs4proc.c +2 -2
@@ -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;
fs/nfsd/nfs4state.c +12 -12
@@ -2322,7 +2322,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, strreturn 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 *cstatic 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 nfmemcpy (&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 *csif (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",
fs/nfsd/state.h +2 -1
@@ -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 {
Signature · 1 line
1.7.4.1
PATCH 2/5 nfsd4: match close replays on stateid, not open owner id
In reply to J. Bruce FieldsKeep 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.
--- fs/nfsd/nfs4state.c | 47 ++++++++++++++++++++++++++++++++++++++++------- fs/nfsd/nfs4xdr.c | 1 + fs/nfsd/state.h | 3 +++ 3 files changed, 44 insertions(+), 7 deletions(-)
fs/nfsd/nfs4state.c +40 -7
@@ -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
fs/nfsd/nfs4xdr.c +1 -0
@@ -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); } }
fs/nfsd/state.h +3 -0
@@ -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 2unsigned 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 */
Signature · 1 line
1.7.4.1
PATCH 3/5 nfsd4: simplify free_stateid
In reply to J. Bruce FieldsWe no longer need is_deleg_stateid, for example.
--- fs/nfsd/nfs4state.c | 66 +++++++++++--------------------------------------- 1 files changed, 15 insertions(+), 51 deletions(-)
fs/nfsd/nfs4state.c +15 -51
@@ -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_sessreturn 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)
Signature · 1 line
1.7.4.1
PATCH 4/5 nfsd4: construct stateid from clientid and counter
In reply to J. Bruce FieldsIncluding 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).
--- fs/nfsd/nfs4state.c | 58 +++++++++++--------------------------------------- fs/nfsd/state.h | 18 ++++----------- 2 files changed, 18 insertions(+), 58 deletions(-)
fs/nfsd/nfs4state.c +13 -45
@@ -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 *ownerreturn 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, ¤t_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_netobjstatic 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, strstatic 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));
fs/nfsd/state.h +5 -13
@@ -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_generationstruct 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; };
Signature · 1 line
1.7.4.1
Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter
Quoted 11 lines · J. Bruce Fields
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(-)
[ ... ]
fs/nfsd/state.h struct nfs4_replay { · line 351
Quoted 8 lines
fs/nfsd/state.h +0
-0@@ -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
Quoted 17 lines
fs/nfsd/state.h +0
-4-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; };
Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter
Quoted 20 lines · Bryan Schumaker
Quoted 11 lines · J. Bruce Fields
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(-)[ ... ]
Quoted 7 lines
fs/nfsd/state.h +0
-0@@ -353,11 +349,9 @@ struct nfs4_replay {*/
Quoted 3 lines
fs/nfsd/state.h struct nfs4_replay { · line 351
Quoted 1 line
fs/nfsd/state.h +0
-0struct nfs4_stateowner {The comment describing this struct should probably be updated since
so_idhashand 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.
fs/nfsd/state.h +8 -37
@@ -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;
Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter
In reply to J. Bruce FieldsBruce, 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
Quoted 279 lines · J. Bruce Fields
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(-)fs/nfsd/nfs4state.c +13
-45@@ -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 *ownerreturn 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, ¤t_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_netobjstatic 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, strstatic 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));fs/nfsd/state.h +5
-13@@ -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_generationstruct 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; };
Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter
Quoted 8 lines · Benny Halevy
Bruce, it seems with this patch, doing si_opaque.so_id =
current_stateidmakes all stateid's unique, regardless of their type.
Isfind_stateid_by_typestill needed?And if the opaque part of the stateid isn't unique, shouldn't
find_stateid_by_typego 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.
Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter
Quoted 10 lines · J. Bruce Fields
Quoted 8 lines · Benny Halevy
Bruce, it seems with this patch, doing si_opaque.so_id =
current_stateidmakes all stateid's unique, regardless of their type.
Isfind_stateid_by_typestill needed?And if the opaque part of the stateid isn't unique, shouldn't
find_stateid_by_typego over the hash bucket by itself to look for other stateid's sharing the same opaque but having the type it is looking for?
Quoted 5 lines
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
Quoted 9 lines
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 befind_stateid_of_type()orfind_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
Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter
Quoted 17 lines · Benny Halevy
Quoted 10 lines · J. Bruce Fields
Quoted 8 lines · Benny Halevy
Bruce, it seems with this patch, doing si_opaque.so_id =
current_stateidmakes all stateid's unique, regardless of their type.
Isfind_stateid_by_typestill needed?And if the opaque part of the stateid isn't unique, shouldn't
find_stateid_by_typego over the hash bucket by itself to look for other stateid's sharing the same opaque but having the type it is looking for?Quoted 5 lines
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.
Quoted 3 lines
So I'm still confused. That's what I thought.
So in what casesfind_stateidthatfind_stateid_by_typecalls will find a stateid structure with a non-matchingsc_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.
Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter
Quoted 25 lines · J. Bruce Fields
Quoted 17 lines · Benny Halevy
Quoted 10 lines · J. Bruce Fields
Quoted 8 lines · Benny Halevy
Bruce, it seems with this patch, doing si_opaque.so_id =
current_stateidmakes all stateid's unique, regardless of their type.
Isfind_stateid_by_typestill needed?And if the opaque part of the stateid isn't unique, shouldn't
find_stateid_by_typego over the hash bucket by itself to look for other stateid's sharing the same opaque but having the type it is looking for?Quoted 5 lines
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.Quoted 3 lines
So I'm still confused. That's what I thought.
So in what casesfind_stateidthatfind_stateid_by_typecalls will find a stateid structure with a non-matchingsc_type?Suppose, for example, the server gets a DELEGRETURN, looks up the provided stateid, and finds an open stateid.
Quoted 8 lines
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 likeBAD_STATEID.Other cases:
open_confirmand 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
Quoted 6 lines
--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
Re: [PATCH 4/5] nfsd4: construct stateid from clientid and counter
Quoted 6 lines · Benny Halevy
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.
Quoted 2 lines
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.
PATCH 5/5 nfsd4: hash closed stateid's like any other
In reply to J. Bruce FieldsLook 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.
--- fs/nfsd/nfs4state.c | 101 +++++++++++++++++++++++++++------------------------ fs/nfsd/state.h | 4 ++- 2 files changed, 56 insertions(+), 49 deletions(-)
fs/nfsd/nfs4state.c +53 -48
@@ -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
fs/nfsd/state.h +3 -1
@@ -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; };
Signature · 1 line
1.7.4.1
Quoted 12 lines · bfields
Quoted 11 lines · J. Bruce Fields
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.
Quoted 6 lines
Quoted 4 lines
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.
Quoted 10 lines · J. Bruce Fields
Quoted 7 lines · bfields
Quoted 4 lines · J. Bruce Fields
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.
Quoted 2 lines · J. Bruce Fields
- 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.
PATCH 1/4 nfsd4: move client * to nfs4_stateid, add init_stid helper
This will be convenient.
--- fs/nfsd/nfs4callback.c | 8 ++++---- fs/nfsd/nfs4state.c | 48 ++++++++++++++++++++++++++---------------------- fs/nfsd/state.h | 2 +- 3 files changed, 31 insertions(+), 27 deletions(-)
fs/nfsd/nfs4callback.c +4 -4
@@ -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;
fs/nfsd/nfs4state.c +26 -22
114 lines not on this page · raw message
fs/nfsd/state.h +1 -1
@@ -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;
Signature · 1 line
1.7.4.1
PATCH 2/4 nfsd4: use idr for stateid's
In reply to J. Bruce FieldsThe idr system is designed exactly for generating id and looking up integer id's. Thanks to Trond for pointing it out.
--- fs/nfsd/nfs4state.c | 124 ++++++++++++++++++++++++++++++--------------------- fs/nfsd/state.h | 1 - 2 files changed, 73 insertions(+), 52 deletions(-)
fs/nfsd/nfs4state.c +73 -51
@@ -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, strreturn 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]); }
fs/nfsd/state.h +0 -1
@@ -79,7 +79,6 @@ struct nfs4_stid {/* For an open stateid kept around *only* to process close replays: */ #define NFS4_CLOSED_STID 8unsigned char sc_type; -struct list_head sc_hash;stateid_t sc_stateid;struct nfs4_client *sc_client; };
Signature · 1 line
1.7.4.1
PATCH 3/4 nfsd4: assume test_stateid always has session
In reply to J. Bruce FieldsTest_stateid is 4.1-only and only allowed after a sequence operation, so this check is unnecessary.
--- 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(-)
fs/nfsd/nfs4state.c +3 -3
@@ -3256,7 +3256,7 @@ static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_sessreturn 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; }
fs/nfsd/nfs4xdr.c +1 -1
@@ -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;
fs/nfsd/state.h +1 -1
@@ -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 */
fs/nfsd/xdr4.h +0 -1
@@ -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; };
Signature · 1 line
1.7.4.1
PATCH 4/4 nfsd4: look up stateid's per clientid
In reply to J. Bruce FieldsUse 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.
--- fs/nfsd/nfs4state.c | 112 ++++++++++++++++++++++---------------------------- fs/nfsd/nfs4xdr.c | 3 +- fs/nfsd/state.h | 4 +- 3 files changed, 54 insertions(+), 65 deletions(-)
fs/nfsd/nfs4state.c +49 -63
@@ -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 nfif (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_sessreturn 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]); }
fs/nfsd/nfs4xdr.c +2 -1
@@ -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;
fs/nfsd/state.h +3 -1
@@ -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 */
Signature · 1 line
1.7.4.1
Quoted 7 lines · J. Bruce Fields
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_lockownercurrently 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.
Quoted 8 lines
- 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....
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.
--- fs/nfsd/nfs4state.c | 42 ++++++++++++++---------------------------- 1 files changed, 14 insertions(+), 28 deletions(-)
fs/nfsd/nfs4state.c +14 -28
@@ -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)
Signature · 1 line
1.7.5.4
PATCH 2/3 nfsd4: share open and lock owner hash tables
In reply to J. Bruce FieldsFrom: "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.
--- fs/nfsd/nfs4state.c | 71 +++++++++++++++++++++++---------------------------- 1 files changed, 32 insertions(+), 39 deletions(-)
fs/nfsd/nfs4state.c +32 -39
@@ -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_netobjstatic 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);
Signature · 1 line
1.7.5.4
PATCH 3/3 nfsd4: add a separate (lockowner, inode) lookup
In reply to J. Bruce FieldsFrom: "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.
--- fs/nfsd/nfs4state.c | 29 +++++++++++++++++++++++------ fs/nfsd/state.h | 1 + 2 files changed, 24 insertions(+), 6 deletions(-)
fs/nfsd/nfs4state.c +23 -6
@@ -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);
fs/nfsd/state.h +1 -0
@@ -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 */ };
Signature · 1 line
1.7.5.4