[PATCH] use kref for nfsd nfs4_client

Benny Halevy bhalevy at ns1.bhalevy.com
Mon May 7 09:36:49 EDT 2007


---
 fs/nfsd/nfs4callback.c     |    8 +------
 fs/nfsd/nfs4state.c        |   50 +++++++++++++++++++++++++++++--------------
 include/linux/nfsd/state.h |    3 +-
 3 files changed, 36 insertions(+), 25 deletions(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index cd88b1e..c2f4732 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -520,9 +520,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
 
 	cb->cb_client = clnt;
 
-	/* the task holds a reference to the nfs4_client struct */
-	atomic_inc(&clp->cl_count);
-
 	msg.rpc_cred = nfsd4_lookupcred(clp,0);
 	if (IS_ERR(msg.rpc_cred))
 		goto out_rpciod;
@@ -536,7 +533,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
 	return;
 
 out_rpciod:
-	atomic_dec(&clp->cl_count);
 	rpciod_down();
 	cb->cb_client = NULL;
 out_clnt:
@@ -558,12 +554,10 @@ nfs4_cb_null(struct rpc_task *task, void *dummy)
 	if (task->tk_status < 0) {
 		dprintk("NFSD: callback establishment to client %.*s failed\n",
 			(int)clp->cl_name.len, clp->cl_name.data);
-		goto out;
+		return;
 	}
 	atomic_set(&cb->cb_set, 1);
 	dprintk("NFSD: callback set to client %u.%u.%u.%u\n", NIPQUAD(addr));
-out:
-	put_nfs4_client(clp);
 }
 
 static const struct rpc_call_ops nfs4_cb_null_ops = {
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e33faa9..d1355b2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -535,20 +535,28 @@ alloc_client(struct xdr_netobj name)
 	return clp;
 }
 
-static inline void
-free_client(struct nfs4_client *clp)
+static inline struct nfs4_client *
+get_nfs4_client(struct nfs4_client *clp)
 {
+	kref_get(&clp->cl_ref);
+	return clp;
+}
+
+static void
+free_nfs4_client(struct kref *kref)
+{
+	struct nfs4_client *clp = container_of(kref, struct nfs4_client, cl_ref);
 	if (clp->cl_cred.cr_group_info)
 		put_group_info(clp->cl_cred.cr_group_info);
 	kfree(clp->cl_name.data);
 	kfree(clp);
 }
 
-void
+static inline void
 put_nfs4_client(struct nfs4_client *clp)
 {
-	if (atomic_dec_and_test(&clp->cl_count))
-		free_client(clp);
+	if (clp)
+		kref_put(&clp->cl_ref, free_nfs4_client);
 }
 
 static void
@@ -573,8 +581,8 @@ expire_client(struct nfs4_client *clp)
 	struct nfs41_session  *ses;
 	struct list_head reaplist;
 
-	dprintk("NFSD: expire_client cl_count %d\n",
-	                    atomic_read(&clp->cl_count));
+	dprintk("NFSD: expire_client refcount %d\n",
+	                    atomic_read(&clp->cl_ref.refcount));
 
 	shutdown_callback_client(clp);
 
@@ -632,7 +640,7 @@ create_client(struct xdr_netobj name, char *recdir) {
 	if (!(clp = alloc_client(name)))
 		goto out;
 	memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
-	atomic_set(&clp->cl_count, 1);
+	kref_init(&clp->cl_ref);
 	atomic_set(&clp->cl_callback.cb_set, 0);
 	INIT_LIST_HEAD(&clp->cl_idhash);
 	INIT_LIST_HEAD(&clp->cl_strhash);
@@ -751,7 +759,7 @@ find_confirmed_client(clientid_t *clid)
 
 	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
 		if (cmp_clid(&clp->cl_clientid, clid))
-			return clp;
+			return get_nfs4_client(clp);
 	}
 	return NULL;
 }
@@ -764,7 +772,7 @@ find_unconfirmed_client(clientid_t *clid)
 
 	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
 		if (cmp_clid(&clp->cl_clientid, clid))
-			return clp;
+			return get_nfs4_client(clp);
 	}
 	return NULL;
 }
@@ -776,7 +784,7 @@ find_confirmed_client_by_str(const char *dname, unsigned int hashval)
 
 	list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
 		if (same_name(clp->cl_recdir, dname))
-			return clp;
+			return get_nfs4_client(clp);
 	}
 	return NULL;
 }
@@ -788,7 +796,7 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
 
 	list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
 		if (same_name(clp->cl_recdir, dname))
-			return clp;
+			return get_nfs4_client(clp);
 	}
 	return NULL;
 }
@@ -929,7 +937,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
 	};
 	nfs4_verifier		clverifier = setclid->se_verf;
 	unsigned int 		strhashval;
-	struct nfs4_client	*conf, *unconf, *new;
+	struct nfs4_client	*conf = NULL, *unconf = NULL, *new;
 	int 			status;
 	char                    dname[HEXDIR_LEN];
 	
@@ -1073,6 +1081,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
 	status = nfs_ok;
 out:
 	nfs4_unlock_state();
+	put_nfs4_client(conf);
+	put_nfs4_client(unconf);
 	return status;
 }
 
@@ -1083,7 +1093,7 @@ void nfsd4_setup_callback_channel(void)
 
 int nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_exchange_id *clid)
 {
-        struct nfs4_client *unconf, *conf, *new;
+        struct nfs4_client *unconf = NULL, *conf = NULL, *new;
         int status;
         unsigned int            strhashval;
         char                    dname[HEXDIR_LEN];
@@ -1175,7 +1185,8 @@ out_copy:
 
 out:
         nfs4_unlock_state();
-
+	put_nfs4_client(conf);
+	put_nfs4_client(conf);
         dprintk("nfsd4_exchange_id returns %d\n", status);
         return status;
 }
@@ -1267,9 +1278,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
 			if (conf) {
 				nfsd4_remove_clid_dir(conf);
 				expire_client(conf);
+				put_nfs4_client(conf);
 			}
 			move_to_confirmed(unconf);
 			conf = unconf;
+			unconf = NULL;
 			status = nfs_ok;
 		}
 	} else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm)))
@@ -1290,6 +1303,8 @@ out:
 	if (!status)
 		nfsd4_probe_callback(conf);
 	nfs4_unlock_state();
+	put_nfs4_client(conf);
+	put_nfs4_client(unconf);
 	return status;
 }
 
@@ -1343,7 +1358,6 @@ int nfsd4_create_session(struct svc_rqst *rqstp, struct nfsd4_create_session *se
 			dprintk("Got a create_session replay!\n");
 			goto out_replay;
 		}
-
         }
         else if (unconf) {
 		if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred) || (ip_addr != unconf->cl_addr)) {
@@ -1359,7 +1373,9 @@ int nfsd4_create_session(struct svc_rqst *rqstp, struct nfsd4_create_session *se
 		unconf->cl_seqid++;
 		move_to_confirmed(unconf);
 		nfsd4_probe_callback(unconf);
+		put_nfs4_client(conf);
 		conf = unconf;
+		unconf = NULL;
 	}
 	status = alloc_init_session(conf, session);
 
@@ -1375,6 +1391,8 @@ out_replay:
 
 out:
 	nfs4_unlock_state();
+	put_nfs4_client(conf);
+	put_nfs4_client(unconf);
 	dprintk("%s returns %d %d\n", __FUNCTION__, status, ntohl(status));
 	return status;
 }
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 92feae0..c23ae98 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -193,6 +193,7 @@ struct current_session {
  *	  when we expire the nfs4_client
  */
 struct nfs4_client {
+	struct kref		cl_ref;
 	struct list_head	cl_idhash; 	/* hash by cl_clientid.id */
 	struct list_head	cl_strhash; 	/* hash by cl_name */
 	struct list_head	cl_openowners;
@@ -211,7 +212,6 @@ struct nfs4_client {
 	clientid_t		cl_clientid;	/* generated by server */
 	nfs4_verifier		cl_confirm;	/* generated by server */
 	struct nfs4_callback	cl_callback;    /* callback info */
-	atomic_t		cl_count;	/* ref count */
 	u32			cl_firststate;	/* recovery dir creation */
 		/* NFSv4.1 create_session slot */
 	u32			cl_seqid;	/* seqid for create_session */
@@ -428,7 +428,6 @@ extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
 extern int nfs4_in_grace(void);
 extern int nfs4_check_open_reclaim(clientid_t *clid);
-extern void put_nfs4_client(struct nfs4_client *clp);
 extern void nfs4_free_stateowner(struct kref *kref);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
-- 
1.5.1


--------------020708040806060706050708--


More information about the pNFS mailing list