Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Feb 2006 18:51:19 GMT
From:      John Baldwin <jhb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 91332 for review
Message-ID:  <200602071851.k17IpJL1099819@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=91332

Change 91332 by jhb@jhb_slimer on 2006/02/07 18:51:00

	Loopback.

Affected files ...

.. //depot/projects/smpng/sys/kern/kern_acct.c#40 integrate

Differences ...

==== //depot/projects/smpng/sys/kern/kern_acct.c#40 (text+ko) ====

@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/kern/kern_acct.c,v 1.78 2006/02/03 16:37:55 jhb Exp $");
+__FBSDID("$FreeBSD: src/sys/kern/kern_acct.c,v 1.79 2006/02/07 16:04:03 jhb Exp $");
 
 #include "opt_mac.h"
 
@@ -51,6 +51,7 @@
 #include <sys/acct.h>
 #include <sys/fcntl.h>
 #include <sys/kernel.h>
+#include <sys/kthread.h>
 #include <sys/lock.h>
 #include <sys/mac.h>
 #include <sys/mount.h>
@@ -58,6 +59,7 @@
 #include <sys/namei.h>
 #include <sys/proc.h>
 #include <sys/resourcevar.h>
+#include <sys/sched.h>
 #include <sys/sx.h>
 #include <sys/sysctl.h>
 #include <sys/sysent.h>
@@ -83,12 +85,9 @@
  * was provided by UCB with the 4.4BSD-Lite release
  */
 static comp_t	encode_comp_t(u_long, u_long);
-static void	acctwatch(void *);
-
-/*
- * Accounting callout used for periodic scheduling of acctwatch.
- */
-static struct	callout acctwatch_callout;
+static void	acctwatch(void);
+static void	acct_thread(void *);
+static int	acct_disable(struct thread *);
 
 /*
  * Accounting vnode pointer, saved vnode pointer, and flags for each.
@@ -104,6 +103,14 @@
 SX_SYSINIT(acct, &acct_sx, "acct_sx");
 
 /*
+ * State of the accounting kthread.
+ */
+static int		 acct_state;
+
+#define	ACCT_RUNNING	1	/* Accounting kthread is running. */
+#define	ACCT_EXITREQ	2	/* Accounting kthread should exit. */
+
+/*
  * Values associated with enabling and disabling accounting
  */
 static int acctsuspend = 2;	/* stop accounting when < 2% free space left */
@@ -188,16 +195,13 @@
 	 * enabled.
 	 */
 	acct_suspended = 0;
-	if (acct_vp != NULL) {
-		callout_stop(&acctwatch_callout);
-		error = vn_close(acct_vp, acct_flags, acct_cred, td);
-		crfree(acct_cred);
-		acct_vp = NULL;
-		acct_cred = NULL;
-		acct_flags = 0;
-		log(LOG_NOTICE, "Accounting disabled\n");
-	}
+	if (acct_vp != NULL)
+		error = acct_disable(td);
 	if (uap->path == NULL) {
+		if (acct_state & ACCT_RUNNING) {
+			acct_state |= ACCT_EXITREQ;
+			wakeup(&acct_state);
+		}
 		sx_xunlock(&acct_sx);
 		goto done;
 	}
@@ -209,16 +213,54 @@
 	acct_vp = nd.ni_vp;
 	acct_cred = crhold(td->td_ucred);
 	acct_flags = flags;
-	callout_init(&acctwatch_callout, CALLOUT_MPSAFE);
+	if (acct_state & ACCT_RUNNING)
+		acct_state &= ~ACCT_EXITREQ;
+	else {
+		/*
+		 * Try to start up an accounting kthread.  We may start more
+		 * than one, but if so the extras will commit suicide as
+		 * soon as they start up.
+		 */
+		error = kthread_create(acct_thread, NULL, NULL, 0, 0,
+		    "accounting");
+		if (error) {
+			(void) vn_close(acct_vp, acct_flags, acct_cred, td);
+			crfree(acct_cred);
+			acct_vp = NULL;
+			acct_cred = NULL;
+			acct_flags = 0;
+			sx_xunlock(&acct_sx);
+			log(LOG_NOTICE, "Unable to start accounting thread\n");
+			goto done;
+		}
+	}
 	sx_xunlock(&acct_sx);
 	log(LOG_NOTICE, "Accounting enabled\n");
-	acctwatch(NULL);
 done:
 	mtx_unlock(&Giant);
 	return (error);
 }
 
 /*
+ * Disable currently in-progress accounting by closing the vnode, dropping
+ * our reference to the credential, and clearing the vnode's flags.
+ */
+static int
+acct_disable(struct thread *td)
+{
+	int error;
+
+	sx_assert(&acct_sx, SX_XLOCKED);
+	error = vn_close(acct_vp, acct_flags, acct_cred, td);
+	crfree(acct_cred);
+	acct_vp = NULL;
+	acct_cred = NULL;
+	acct_flags = 0;
+	log(LOG_NOTICE, "Accounting disabled\n");
+	return (error);
+}
+
+/*
  * Write out process accounting information, on process exit.
  * Data to be written out is specified in Leffler, et al.
  * and are enumerated below.  (They're also noted in the system
@@ -376,31 +418,41 @@
  */
 /* ARGSUSED */
 static void
-acctwatch(void *a)
+acctwatch(void)
 {
 	struct statfs sb;
 	int vfslocked;
 
-	sx_xlock(&acct_sx);
+	sx_assert(&acct_sx, SX_XLOCKED);
+
+	/*
+	 * If accounting was disabled before our kthread was scheduled,
+	 * then acct_vp might be NULL.  If so, just ask our kthread to
+	 * exit and return.
+	 */
+	if (acct_vp == NULL) {
+		acct_state |= ACCT_EXITREQ;
+		return;
+	}
+
+	/*
+	 * If our vnode is no longer valid, tear it down and signal the
+	 * accounting thread to die.
+	 */
 	vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount);
 	if (acct_vp->v_type == VBAD) {
-		(void) vn_close(acct_vp, acct_flags, acct_cred, NULL);
+		(void) acct_disable(NULL);
 		VFS_UNLOCK_GIANT(vfslocked);
-		crfree(acct_cred);
-		acct_vp = NULL;
-		acct_cred = NULL;
-		acct_flags = 0;
-		sx_xunlock(&acct_sx);
-		log(LOG_NOTICE, "Accounting disabled\n");
+		acct_state |= ACCT_EXITREQ;
 		return;
 	}
+
 	/*
 	 * Stopping here is better than continuing, maybe it will be VBAD
 	 * next time around.
 	 */
 	if (VFS_STATFS(acct_vp->v_mount, &sb, curthread) < 0) {
 		VFS_UNLOCK_GIANT(vfslocked);
-		sx_xunlock(&acct_sx);
 		return;
 	}
 	VFS_UNLOCK_GIANT(vfslocked);
@@ -417,6 +469,54 @@
 			log(LOG_NOTICE, "Accounting suspended\n");
 		}
 	}
-	callout_reset(&acctwatch_callout, acctchkfreq * hz, acctwatch, NULL);
+}
+
+/*
+ * The main loop for the dedicated kernel thread that periodically calls
+ * acctwatch().
+ */
+static void
+acct_thread(void *dummy)
+{
+	u_char pri;
+
+	/* This is a low-priority kernel thread. */
+	pri = PRI_MAX_KERN;
+	mtx_lock_spin(&sched_lock);
+	sched_prio(curthread, pri);
+	mtx_unlock_spin(&sched_lock);
+
+	/* If another accounting kthread is already running, just die. */
+	sx_xlock(&acct_sx);
+	if (acct_state & ACCT_RUNNING) {
+		sx_xunlock(&acct_sx);
+		kthread_exit(0);
+	}
+	acct_state |= ACCT_RUNNING;
+
+	/* Loop until we are asked to exit. */
+	while (!(acct_state & ACCT_EXITREQ)) {
+
+		/* Perform our periodic checks. */
+		acctwatch();
+
+		/*
+		 * We check this flag again before sleeping since the
+		 * acctwatch() might have shut down accounting and asked us
+		 * to exit.
+		 */
+		if (!(acct_state & ACCT_EXITREQ)) {
+			sx_xunlock(&acct_sx);
+			tsleep(&acct_state, pri, "-", acctchkfreq * hz);
+			sx_xlock(&acct_sx);
+		}
+	}
+
+	/*
+	 * Acknowledge the exit request and shutdown.  We clear both the
+	 * exit request and running flags.
+	 */
+	acct_state = 0;
 	sx_xunlock(&acct_sx);
+	kthread_exit(0);
 }



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