Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Feb 2002 13:56:33 -0800 (PST)
From:      Matthew Dillon <dillon@apollo.backplane.com>
To:        John Baldwin <jhb@FreeBSD.ORG>
Cc:        Terry Lambert <tlambert2@mindspring.com>, Julian Elischer <julian@elischer.org>, bde@FreeBSD.ORG, current@FreeBSD.ORG, Alfred Perlstein <bright@mu.org>
Subject:   tentitive ucred mutex cleanup patch, MATT's version (was Re: ucred holding patch, BDE version)
Message-ID:  <200202162156.g1GLuX639707@apollo.backplane.com>
References:   <XFMail.020211231302.jhb@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
    Please review this patch.  I haven't looked at BDE's patch but this was
    so simple I decided to just go do it.

    There are many situations where the allocation of a system structure can 
    be safely done with Giant, but deallocation occurs dangerously deep
    in the call stack.  For these situations I believe it makes sense to
    have a recycle queue (maybe even a global recycle queue) to handle
    freeing the refcount->0 structures at a later time (like in the allocation
    code where we might already need Giant).  At least until MALLOC/FREE are
    really made MP safe.

    In anycase, here is the patch.  It is VERY simple and it also cuts the
    size of the ucred structure down by a huge amount.

    As a bonus, here are the gettimeofday() loop test results with this
    code and the gettimeofday() giant removal:

CURRENT, gettimeofday() SMP patch, ucred patch:

    1 TG running: 	396365 calls/sec
    2 TGs running:	322000 calls/sec each.

    Now with my gdb -k on /dev/mem I note that the contention is occuring
    in userret(), where Giant is being obtained for the signal processing.
    If we could optimize that I'll bet the call rate would go above 400K calls
    per second with two running.

						-Matt

Index: sys/ucred.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/ucred.h,v
retrieving revision 1.26
diff -u -r1.26 ucred.h
--- sys/ucred.h	11 Oct 2001 23:38:17 -0000	1.26
+++ sys/ucred.h	16 Feb 2002 21:36:58 -0000
@@ -60,8 +60,9 @@
 	struct	uidinfo *cr_uidinfo;	/* per euid resource consumption */
 	struct	uidinfo *cr_ruidinfo;	/* per ruid resource consumption */
 	struct	prison *cr_prison;	/* jail(4) */
-#define	cr_endcopy cr_mtx
-	struct	mtx cr_mtx;		/* protect refcount */
+#define	cr_endcopy cr_mtxp
+	struct	mtx *cr_mtxp;		/* protect refcount */
+	struct	ucred *cr_freenext;	/* next on free list */
 };
 #define cr_gid cr_groups[0]
 #define NOCRED ((struct ucred *)0)	/* no credential available */
Index: kern/kern_prot.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_prot.c,v
retrieving revision 1.133
diff -u -r1.133 kern_prot.c
--- kern/kern_prot.c	16 Jan 2002 06:55:30 -0000	1.133
+++ kern/kern_prot.c	16 Feb 2002 21:42:17 -0000
@@ -72,6 +72,9 @@
 	int	dummy;
 };
 #endif
+
+static struct ucred *ucred_free_list;
+
 /*
  * MPSAFE
  */
@@ -1582,11 +1585,40 @@
 struct ucred *
 crget()
 {
-	register struct ucred *cr;
+	struct ucred *cr;
+
+	GIANT_REQUIRED;
+
+	mtx_pool_lock(&ucred_free_list);
+	if (ucred_free_list) {
+		cr = ucred_free_list;
+		ucred_free_list = cr->cr_freenext;
+		cr->cr_freenext = NULL;
+		mtx_pool_unlock(&ucred_free_list);
 
-	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
+		/*
+		 * Cleanup previous user of this recycled ucred
+		 *
+		 * Some callers of crget(), such as nfs_statfs(),
+		 * allocate a temporary credential, but don't
+		 * allocate a uidinfo structure.
+		 */
+		if (cr->cr_uidinfo != NULL)
+			uifree(cr->cr_uidinfo);
+		if (cr->cr_ruidinfo != NULL)
+			uifree(cr->cr_ruidinfo);
+		/*
+		 * Free a prison, if any.
+		 */
+		if (jailed(cr))
+			prison_free(cr->cr_prison);
+	} else {
+		mtx_pool_unlock(&ucred_free_list);
+		MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
+	}
+	bzero(cr, sizeof(struct ucred));
 	cr->cr_ref = 1;
-	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
+	cr->cr_mtxp = mtx_pool_find(cr);
 	return (cr);
 }
 
@@ -1598,42 +1630,36 @@
 	struct ucred *cr;
 {
 
-	mtx_lock(&cr->cr_mtx);
+	mtx_lock(cr->cr_mtxp);
 	cr->cr_ref++;
-	mtx_unlock(&cr->cr_mtx);
+	mtx_unlock(cr->cr_mtxp);
 	return (cr);
 }
 
 /*
  * Free a cred structure.
  * Throws away space when ref count gets to 0.
+ *
+ * XXX we should not have to obtain the mutex lock if cr_ref is 1, since
+ * we are the last user.
  */
 void
 crfree(cr)
 	struct ucred *cr;
 {
+	struct mtx *mtxp = cr->cr_mtxp;
 
-	mtx_lock(&cr->cr_mtx);
+	mtx_lock(mtxp);
 	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
 	if (--cr->cr_ref == 0) {
-		mtx_destroy(&cr->cr_mtx);
-		/*
-		 * Some callers of crget(), such as nfs_statfs(),
-		 * allocate a temporary credential, but don't
-		 * allocate a uidinfo structure.
-		 */
-		if (cr->cr_uidinfo != NULL)
-			uifree(cr->cr_uidinfo);
-		if (cr->cr_ruidinfo != NULL)
-			uifree(cr->cr_ruidinfo);
-		/*
-		 * Free a prison, if any.
-		 */
-		if (jailed(cr))
-			prison_free(cr->cr_prison);
-		FREE((caddr_t)cr, M_CRED);
-	} else
-		mtx_unlock(&cr->cr_mtx);
+		mtx_unlock(mtxp);
+		mtx_pool_lock(&ucred_free_list);
+		cr->cr_freenext = ucred_free_list;
+		ucred_free_list = cr;
+		mtx_pool_unlock(&ucred_free_list);
+	} else {
+		mtx_unlock(mtxp);
+	}
 }
 
 /*
@@ -1645,9 +1671,9 @@
 {
 	int shared;
 
-	mtx_lock(&cr->cr_mtx);
+	mtx_lock(cr->cr_mtxp);
 	shared = (cr->cr_ref > 1);
-	mtx_unlock(&cr->cr_mtx);
+	mtx_unlock(cr->cr_mtxp);
 	return (shared);
 }
 
Index: i386/i386/trap.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/i386/trap.c,v
retrieving revision 1.211
diff -u -r1.211 trap.c
--- i386/i386/trap.c	10 Jan 2002 11:49:54 -0000	1.211
+++ i386/i386/trap.c	16 Feb 2002 21:46:05 -0000
@@ -1099,9 +1099,13 @@
 	 */
 	STOPEVENT(p, S_SCX, code);
 
+#if 0
 	mtx_lock(&Giant);
+#endif
 	crfree(td->td_ucred);
+#if 0
 	mtx_unlock(&Giant);
+#endif
 	td->td_ucred = NULL;
 #ifdef WITNESS
 	if (witness_list(td)) {

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200202162156.g1GLuX639707>