All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benny Halevy <bhalevy@panasas.com>
To: "J. Bruce Fields" <bfields@citi.umich.edu>
Cc: linux-nfs@vger.kernel.org
Subject: Re: [RFC 3/3] nfsd4: do not expire nfs41 clients while in use
Date: Tue, 04 May 2010 08:39:56 +0300	[thread overview]
Message-ID: <4BDFB32C.7080107@panasas.com> (raw)
In-Reply-To: <1272904313-27145-1-git-send-email-bhalevy@panasas.com>

Benny Halevy wrote:
> Add a cl_use_count atomic counter to struct nfs4_client.
> Hold a use count while the client is in use by a compound that begins
> with SEQUENCE.
> Renew the client when the comound completes.
> The laundromat skips clients that have a positive use count.
> Otherwise, the laundromat marks the client as expired by setting
> cl_use_count to -1.
> 
> Note that we don't want to use the state lock to synchronize with nfsd4_sequence
> as we want to diminish the state lock scope.
> An alternative to using atomic_cmpxchg is to grab the sessionid_lock spin lock
> while accessing cl_use_count, but that would cause some contention in the
> laundromat if it needs to lock and unlock it for every client.
> 
> Signed-off-by: Benny Halevy <bhalevy@panasas.com>
> ---
>  fs/nfsd/nfs4state.c |   40 ++++++++++++++++++++++++++++++++++------
>  fs/nfsd/nfs4xdr.c   |    2 ++
>  fs/nfsd/state.h     |    9 +++++++++
>  3 files changed, 45 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 50b75af..c95ddca 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -647,6 +647,14 @@ renew_client(struct nfs4_client *clp)
>  	clp->cl_time = get_seconds();
>  }
>  
> +void
> +renew_nfs4_client(struct nfs4_client *clp)
> +{
> +	nfs4_lock_state();
> +	renew_client(clp);
> +	nfs4_unlock_state();
> +}
> +
>  /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
>  static int
>  STALE_CLIENTID(clientid_t *clid)
> @@ -715,6 +723,24 @@ put_nfs4_client(struct nfs4_client *clp)
>  		free_client(clp);
>  }
>  
> +/*
> + * atomically mark client as used, as long as it's not already expired.
> + * return 0 on success, or a negative value if client already expired.
> + */
> +int
> +use_nfs4_client(struct nfs4_client *clp)
> +{
> +	int orig;
> +
> +	do {
> +		orig = atomic_read(&clp->cl_use_count);
> +		if (orig < 0)
> +			return orig;
> +	} while (atomic_cmpxchg(&clp->cl_use_count, orig, orig + 1) != orig);
> +
> +	return 0;
> +}
> +
>  static void
>  expire_client(struct nfs4_client *clp)
>  {
> @@ -840,6 +866,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
>  
>  	memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
>  	atomic_set(&clp->cl_count, 1);
> +	atomic_set(&clp->cl_use_count, 0);
>  	atomic_set(&clp->cl_cb_conn.cb_set, 0);
>  	INIT_LIST_HEAD(&clp->cl_idhash);
>  	INIT_LIST_HEAD(&clp->cl_strhash);
> @@ -1423,6 +1450,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
>  	if (!session)
>  		goto out;
>  
> +	/* keep the client from expiring */
> +	if (use_nfs4_client(cstate->session->se_client) < 0)
> +		goto out;
> +
>  	status = nfserr_badslot;
>  	if (seq->slotid >= session->se_fchannel.maxreqs)
>  		goto out;
> @@ -1463,12 +1494,6 @@ out:
>  		get_nfs4_client(cstate->session->se_client);
>  	}
>  	spin_unlock(&sessionid_lock);
> -	/* Renew the clientid on success and on replay */
> -	if (cstate->session) {
> -		nfs4_lock_state();
> -		renew_client(session->se_client);
> -		nfs4_unlock_state();
> -	}
>  	dprintk("%s: return %d\n", __func__, ntohl(status));
>  	return status;
>  }
> @@ -2575,6 +2600,9 @@ nfs4_laundromat(void)
>  		nfsd4_end_grace();
>  	list_for_each_safe(pos, next, &client_lru) {
>  		clp = list_entry(pos, struct nfs4_client, cl_lru);
> +		/* skip client if in use (cl_use_count is greater than zero) */
> +		if (atomic_cmpxchg(&clp->cl_use_count, 0, -1) > 0)
> +			continue;

I'll move that check after the time comparison
since there's no need for the atomic instruction if the client's
time out hasn't expired yet.

Benny

>  		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
>  			t = clp->cl_time - cutoff;
>  			if (clientid_val > t)
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index aed733c..0f0b857 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -3313,6 +3313,8 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
>  			dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
>  			cs->slot->sl_inuse = false;
>  		}
> +		renew_nfs4_client(cs->session->se_client);
> +		unuse_nfs4_client(cs->session->se_client);
>  		put_nfs4_client(cs->session->se_client);
>  		nfsd4_put_session(cs->session);
>  	}
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index e3c002e..806d9b8 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -214,6 +214,7 @@ struct nfs4_client {
>  	nfs4_verifier		cl_confirm;	/* generated by server */
>  	struct nfs4_cb_conn	cl_cb_conn;     /* callback info */
>  	atomic_t		cl_count;	/* ref count */
> +	atomic_t		cl_use_count;	/* session use count */
>  	u32			cl_firststate;	/* recovery dir creation */
>  
>  	/* for nfs41 */
> @@ -237,6 +238,12 @@ get_nfs4_client(struct nfs4_client *clp)
>  	atomic_inc(&clp->cl_count);
>  }
>  
> +static inline void
> +unuse_nfs4_client(struct nfs4_client *clp)
> +{
> +	atomic_dec(&clp->cl_use_count);
> +}
> +
>  /* struct nfs4_client_reset
>   * one per old client. Populates reset_str_hashtbl. Filled from conf_id_hashtbl
>   * upon lease reset, or from upcall to state_daemon (to read in state
> @@ -384,6 +391,8 @@ extern void nfs4_unlock_state(void);
>  extern int nfs4_in_grace(void);
>  extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
>  extern void put_nfs4_client(struct nfs4_client *clp);
> +extern int use_nfs4_client(struct nfs4_client *clp);
> +extern void renew_nfs4_client(struct nfs4_client *clp);
>  extern void nfs4_free_stateowner(struct kref *kref);
>  extern int set_callback_cred(void);
>  extern void nfsd4_probe_callback(struct nfs4_client *clp);


      reply	other threads:[~2010-05-04  5:40 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-03 16:13 [RFC 0/3] nfsd41: do not expire client while in use by current compound Benny Halevy
2010-05-03 16:31 ` [RFC 1/3] nfsd4: use local variable in nfs4svc_encode_compoundres Benny Halevy
2010-05-03 22:37   `  J. Bruce Fields
2010-05-03 16:31 ` [RFC 2/3] nfsd4: hold a reference on nfs4_client when it is used by a session Benny Halevy
2010-05-03 22:36   `  J. Bruce Fields
2010-05-04  1:12     `  J. Bruce Fields
2010-05-04  7:11       ` Benny Halevy
2010-05-04 15:40         ` J. Bruce Fields
2010-05-04 17:45         ` J. Bruce Fields
2010-05-04 21:40           ` Benny Halevy
2010-05-03 16:31 ` [RFC 3/3] nfsd4: do not expire nfs41 clients while in use Benny Halevy
2010-05-04  5:39   ` Benny Halevy [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4BDFB32C.7080107@panasas.com \
    --to=bhalevy@panasas.com \
    --cc=bfields@citi.umich.edu \
    --cc=linux-nfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.