patch-2.4.9 linux/net/sunrpc/auth.c

Next file: linux/net/sunrpc/auth_null.c
Previous file: linux/net/sched/sch_tbf.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.8/linux/net/sunrpc/auth.c linux/net/sunrpc/auth.c
@@ -81,42 +81,61 @@
 	auth->au_nextgc = jiffies + (auth->au_expire >> 1);
 }
 
+/*
+ * Destroy an unreferenced credential
+ */
 static inline void
-rpcauth_crdestroy(struct rpc_auth *auth, struct rpc_cred *cred)
+rpcauth_crdestroy(struct rpc_cred *cred)
 {
 #ifdef RPC_DEBUG
 	if (cred->cr_magic != RPCAUTH_CRED_MAGIC)
 		BUG();
 	cred->cr_magic = 0;
+	if (atomic_read(&cred->cr_count) || cred->cr_auth)
+		BUG();
 #endif
-	if (auth->au_ops->crdestroy)
-		auth->au_ops->crdestroy(cred);
-	else
-		rpc_free(cred);
+	cred->cr_ops->crdestroy(cred);
 }
 
 /*
- * Clear the RPC credential cache
+ * Destroy a list of credentials
+ */
+static inline
+void rpcauth_destroy_credlist(struct rpc_cred *head)
+{
+	struct rpc_cred *cred;
+
+	while ((cred = head) != NULL) {
+		head = cred->cr_next;
+		rpcauth_crdestroy(cred);
+	}
+}
+
+/*
+ * Clear the RPC credential cache, and delete those credentials
+ * that are not referenced.
  */
 void
 rpcauth_free_credcache(struct rpc_auth *auth)
 {
-	struct rpc_cred	**q, *cred;
-	void		(*destroy)(struct rpc_cred *);
+	struct rpc_cred	**q, *cred, *free = NULL;
 	int		i;
 
-	if (!(destroy = auth->au_ops->crdestroy))
-		destroy = (void (*)(struct rpc_cred *)) rpc_free;
-
 	spin_lock(&rpc_credcache_lock);
 	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
 		q = &auth->au_credcache[i];
 		while ((cred = *q) != NULL) {
 			*q = cred->cr_next;
-			destroy(cred);
+			cred->cr_auth = NULL;
+			if (atomic_read(&cred->cr_count) == 0) {
+				cred->cr_next = free;
+				free = cred;
+			} else
+				cred->cr_next = NULL;
 		}
 	}
 	spin_unlock(&rpc_credcache_lock);
+	rpcauth_destroy_credlist(free);
 }
 
 /*
@@ -133,9 +152,10 @@
 	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
 		q = &auth->au_credcache[i];
 		while ((cred = *q) != NULL) {
-			if (!cred->cr_count &&
+			if (!atomic_read(&cred->cr_count) &&
 			    time_before(cred->cr_expire, jiffies)) {
 				*q = cred->cr_next;
+				cred->cr_auth = NULL;
 				cred->cr_next = free;
 				free = cred;
 				continue;
@@ -144,10 +164,7 @@
 		}
 	}
 	spin_unlock(&rpc_credcache_lock);
-	while ((cred = free) != NULL) {
-		free = cred->cr_next;
-		rpcauth_crdestroy(auth, cred);
-	}
+	rpcauth_destroy_credlist(free);
 	auth->au_nextgc = jiffies + auth->au_expire;
 }
 
@@ -163,8 +180,8 @@
 	spin_lock(&rpc_credcache_lock);
 	cred->cr_next = auth->au_credcache[nr];
 	auth->au_credcache[nr] = cred;
-	cred->cr_count++;
-	cred->cr_expire = jiffies + auth->au_expire;
+	cred->cr_auth = auth;
+	get_rpccred(cred);
 	spin_unlock(&rpc_credcache_lock);
 }
 
@@ -187,7 +204,7 @@
 	q = &auth->au_credcache[nr];
 	while ((cred = *q) != NULL) {
 		if (!(cred->cr_flags & RPCAUTH_CRED_DEAD) &&
-		    auth->au_ops->crmatch(cred, taskflags)) {
+		    cred->cr_ops->crmatch(cred, taskflags)) {
 			*q = cred->cr_next;
 			break;
 		}
@@ -213,23 +230,23 @@
  * Remove cred handle from cache
  */
 static void
-rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
+rpcauth_remove_credcache(struct rpc_cred *cred)
 {
+	struct rpc_auth *auth = cred->cr_auth;
 	struct rpc_cred	**q, *cr;
 	int		nr;
 
 	nr = (cred->cr_uid & RPC_CREDCACHE_MASK);
-	spin_lock(&rpc_credcache_lock);
 	q = &auth->au_credcache[nr];
 	while ((cr = *q) != NULL) {
 		if (cred == cr) {
 			*q = cred->cr_next;
 			cred->cr_next = NULL;
+			cred->cr_auth = NULL;
 			break;
 		}
 		q = &cred->cr_next;
 	}
-	spin_unlock(&rpc_credcache_lock);
 }
 
 struct rpc_cred *
@@ -258,7 +275,7 @@
 {
 	dprintk("RPC:     matching %s cred %d\n",
 		auth->au_ops->au_name, taskflags);
-	return auth->au_ops->crmatch(cred, taskflags);
+	return cred->cr_ops->crmatch(cred, taskflags);
 }
 
 void
@@ -266,26 +283,25 @@
 {
 	dprintk("RPC: %4d holding %s cred %p\n",
 		task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
-	if (task->tk_msg.rpc_cred) {
-		spin_lock(&rpc_credcache_lock);
-		task->tk_msg.rpc_cred->cr_count++;
-		task->tk_msg.rpc_cred->cr_expire = jiffies + task->tk_auth->au_expire;
-		spin_unlock(&rpc_credcache_lock);
-	}
+	if (task->tk_msg.rpc_cred)
+		get_rpccred(task->tk_msg.rpc_cred);
 }
 
 void
-rpcauth_releasecred(struct rpc_auth *auth, struct rpc_cred *cred)
+put_rpccred(struct rpc_cred *cred)
 {
-	spin_lock(&rpc_credcache_lock);
-	if (cred != NULL && cred->cr_count > 0) {
-		if (!--cred->cr_count && (cred->cr_flags & RPCAUTH_CRED_DEAD)) {
-			spin_unlock(&rpc_credcache_lock);
-			rpcauth_remove_credcache(auth, cred);
-			rpcauth_crdestroy(auth, cred);
-			return;
-		}
+	if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
+		return;
+
+	if (cred->cr_auth && cred->cr_flags & RPCAUTH_CRED_DEAD)
+		rpcauth_remove_credcache(cred);
+
+	if (!cred->cr_auth) {
+		spin_unlock(&rpc_credcache_lock);
+		rpcauth_crdestroy(cred);
+		return;
 	}
+	cred->cr_expire = jiffies + cred->cr_auth->au_expire;
 	spin_unlock(&rpc_credcache_lock);
 }
 
@@ -298,7 +314,7 @@
 	dprintk("RPC: %4d releasing %s cred %p\n",
 		task->tk_pid, auth->au_ops->au_name, cred);
 
-	rpcauth_releasecred(auth, cred);
+	put_rpccred(cred);
 	task->tk_msg.rpc_cred = NULL;
 }
 
@@ -306,10 +322,11 @@
 rpcauth_marshcred(struct rpc_task *task, u32 *p)
 {
 	struct rpc_auth	*auth = task->tk_auth;
+	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
 
 	dprintk("RPC: %4d marshaling %s cred %p\n",
-		task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
-	return auth->au_ops->crmarshal(task, p,
+		task->tk_pid, auth->au_ops->au_name, cred);
+	return cred->cr_ops->crmarshal(task, p,
 				task->tk_flags & RPC_CALL_REALUID);
 }
 
@@ -317,20 +334,22 @@
 rpcauth_checkverf(struct rpc_task *task, u32 *p)
 {
 	struct rpc_auth	*auth = task->tk_auth;
+	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
 
 	dprintk("RPC: %4d validating %s cred %p\n",
-		task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
-	return auth->au_ops->crvalidate(task, p);
+		task->tk_pid, auth->au_ops->au_name, cred);
+	return cred->cr_ops->crvalidate(task, p);
 }
 
 int
 rpcauth_refreshcred(struct rpc_task *task)
 {
 	struct rpc_auth	*auth = task->tk_auth;
+	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
 
 	dprintk("RPC: %4d refreshing %s cred %p\n",
-		task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
-	task->tk_status = auth->au_ops->crrefresh(task);
+		task->tk_pid, auth->au_ops->au_name, cred);
+	task->tk_status = cred->cr_ops->crrefresh(task);
 	return task->tk_status;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)