Change it so that only openstateids hold persistent references to openowners. References can still be held by compounds in progress. With this, we can get rid of NFS4_OO_NEW. It's possible that we will create a new openowner in the process of doing the open, but something later fails. In the meantime, another task could find that openowner and start using it on a successful open. If that occurs we don't necessarily want to tear it down, just put the reference that the failing compound holds. Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxxxxxxx> --- fs/nfsd/nfs4state.c | 71 +++++++++++++++++++++++------------------------------ fs/nfsd/state.h | 1 - 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b658fd481c4e..d97f3d3743f3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -882,7 +882,7 @@ static void nfs4_free_generic_stateid(struct nfs4_stid *stid) struct nfs4_ol_stateid *stp = openlockstateid(stid); release_all_access(stp); - if (stp->st_stateowner && stid->sc_type == NFS4_LOCK_STID) + if (stp->st_stateowner) nfs4_put_stateowner(stp->st_stateowner); nfs4_free_stid(stateid_slab, stid); } @@ -979,8 +979,9 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo) struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; if (s) { - put_generic_stateid(s); + list_del_init(&oo->oo_close_lru); oo->oo_last_closed_stid = NULL; + put_generic_stateid(s); } } @@ -999,7 +1000,6 @@ static void release_openowner(struct nfs4_openowner *oo) { unhash_openowner(oo); release_openowner_stateids(oo); - list_del(&oo->oo_close_lru); release_last_closed_stateid(oo); nfs4_put_stateowner(&oo->oo_owner); } @@ -1472,6 +1472,7 @@ destroy_client(struct nfs4_client *clp) } while (!list_empty(&clp->cl_openowners)) { oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); + atomic_inc(&oo->oo_owner.so_count); release_openowner(oo); } nfsd4_shutdown_callback(clp); @@ -3003,7 +3004,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, oo->oo_owner.so_unhash = nfs4_unhash_openowner; oo->oo_owner.so_is_open_owner = 1; oo->oo_owner.so_seqid = open->op_seqid; - oo->oo_flags = NFS4_OO_NEW; + oo->oo_flags = 0; if (nfsd4_has_session(cstate)) oo->oo_flags |= NFS4_OO_CONFIRMED; oo->oo_time = 0; @@ -3020,6 +3021,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, stp->st_stid.sc_type = NFS4_OPEN_STID; INIT_LIST_HEAD(&stp->st_locks); stp->st_stateowner = &oo->oo_owner; + atomic_inc(&stp->st_stateowner->so_count); get_nfs4_file(fp); stp->st_stid.sc_file = fp; stp->st_access_bmap = 0; @@ -3035,13 +3037,27 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, spin_unlock(&oo->oo_owner.so_client->cl_lock); } +/* + * In the 4.0 case we need to keep the owners around a little while to handle + * CLOSE replay. We still do need to release any file access that is held by + * them before returning however. + */ static void -move_to_close_lru(struct nfs4_openowner *oo, struct net *net) +move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) { - struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct nfs4_openowner *oo = openowner(s->st_stateowner); + struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, + nfsd_net_id); dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); + release_all_access(s); + if (s->st_stid.sc_file) { + put_nfs4_file(s->st_stid.sc_file); + s->st_stid.sc_file = NULL; + } + release_last_closed_stateid(oo); + oo->oo_last_closed_stid = s; list_move_tail(&oo->oo_close_lru, &nn->close_lru); oo->oo_time = get_seconds(); } @@ -3072,6 +3088,7 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, if ((bool)clp->cl_minorversion != sessions) return NULL; renew_client(oo->oo_owner.so_client); + atomic_inc(&oo->oo_owner.so_count); return oo; } } @@ -3839,19 +3856,10 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, struct nfsd4_open *open, __be32 status) { if (open->op_openowner) { - struct nfs4_openowner *oo = open->op_openowner; - - if (!list_empty(&oo->oo_owner.so_stateids)) - list_del_init(&oo->oo_close_lru); - if (oo->oo_flags & NFS4_OO_NEW) { - if (status) { - release_openowner(oo); - open->op_openowner = NULL; - } else - oo->oo_flags &= ~NFS4_OO_NEW; - } - if (open->op_openowner) - nfsd4_cstate_assign_replay(cstate, &oo->oo_owner); + struct nfs4_stateowner *so = &open->op_openowner->oo_owner; + + nfsd4_cstate_assign_replay(cstate, so); + nfs4_put_stateowner(so); } if (open->op_file) nfsd4_free_file(open->op_file); @@ -3965,7 +3973,7 @@ nfs4_laundromat(struct nfsd_net *nn) new_timeo = min(new_timeo, t); break; } - release_openowner(oo); + release_last_closed_stateid(oo); } new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); nfs4_unlock_state(); @@ -4528,31 +4536,14 @@ out: static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) { struct nfs4_client *clp = s->st_stid.sc_client; - struct nfs4_openowner *oo = openowner(s->st_stateowner); s->st_stid.sc_type = NFS4_CLOSED_STID; unhash_open_stateid(s); - if (clp->cl_minorversion) { - if (list_empty(&oo->oo_owner.so_stateids)) - release_openowner(oo); + if (clp->cl_minorversion) put_generic_stateid(s); - } else { - if (s->st_stid.sc_file) { - put_nfs4_file(s->st_stid.sc_file); - s->st_stid.sc_file = NULL; - } - oo->oo_last_closed_stid = s; - /* - * In the 4.0 case we need to keep the owners around a - * little while to handle CLOSE replay. We still do need - * to release any file access that is held by them - * before returning however. - */ - release_all_access(s); - if (list_empty(&oo->oo_owner.so_stateids)) - move_to_close_lru(oo, clp->net); - } + else + move_to_close_lru(s, clp->net); } /* diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index f6639fb5a56f..9e9e45278b40 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -364,7 +364,6 @@ struct nfs4_openowner { 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_NEW 4 unsigned char oo_flags; }; -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html