Subject: Re: Why disk capacity check for the directory where accounting file
To: None <tech-kern@NetBSD.ORG>
From: enami tsugutomo <enami@ba2.so-net.or.jp>
List: tech-kern
Date: 06/28/1997 16:41:22
enami tsugutomo <enami@ba2.so-net.or.jp> writes:

> I changed the patch to keep credential when accounting file opend and
> use it when writing to it.

Now, I'm using following patch so that accounting file i/o is done in
upper half of kernel.  With this patch, my diskless machine
successfully writes accounting file via nfs.  But the tendency of hang
upon reboot increases (probably same reason reported in current-users)

enami.

Index: sys/acct.h
===================================================================
RCS file: /a/cvsroot/NetBSD/src/sys/sys/acct.h,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 acct.h
--- acct.h	1997/01/24 13:23:37	1.1.1.2
+++ acct.h	1997/06/22 03:42:39
@@ -80,6 +80,7 @@
 struct vnode	*acctp;
 
 int	acct_process __P((struct proc *p));
+void	acctwatch __P((void));
 #endif
 
 #endif /* !_SYS_ACCT_H_ */
Index: kern/kern_acct.c
===================================================================
RCS file: /a/cvsroot/NetBSD/src/sys/kern/kern_acct.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 kern_acct.c
--- kern_acct.c	1996/11/16 10:56:14	1.1.1.2
+++ kern_acct.c	1997/06/28 07:24:16
@@ -74,8 +74,10 @@
  * The former's operation is described in Leffler, et al., and the latter
  * was provided by UCB with the 4.4BSD-Lite release
  */
+int	check_diskspace __P((void));
 comp_t	encode_comp_t __P((u_long, u_long));
-void	acctwatch __P((void *));
+void	schedule_acctwatch __P((void));
+void	wakeup_acctwatch __P((void *));
 
 /*
  * Accounting vnode pointer, and saved vnode pointer.
@@ -84,6 +86,11 @@
 struct	vnode *savacctp;
 
 /*
+ * Credential of accounting file owner.   Used when accounting file i/o.
+ */
+struct	ucred *acct_ucred;
+
+/*
  * Values associated with enabling and disabling accounting
  */
 int	acctsuspend = 2;	/* stop accounting when < 2% free space left */
@@ -128,23 +135,37 @@
 
 	/*
 	 * If accounting was previously enabled, kill the old space-watcher,
-	 * close the file, and (if no new file was specified, leave).
+	 * close the file, free credential for accounting file i/o,
+	 * and (if no new file was specified, leave).
 	 */
 	if (acctp != NULLVP || savacctp != NULLVP) {
-		untimeout(acctwatch, NULL);
+		untimeout(wakeup_acctwatch, NULL);
 		error = vn_close((acctp != NULLVP ? acctp : savacctp), FWRITE,
 		    p->p_ucred, p);
+#ifdef ACCT_DEBUG
+		log(LOG_NOTICE, "Previous accounting file is closed: %p\n",
+		    acctp ? acctp : savacctp);
+#endif
 		acctp = savacctp = NULLVP;
 	}
+	if (acct_ucred) {
+		crfree(acct_ucred);
+		acct_ucred = 0;
+	}
 	if (SCARG(uap, path) == NULL)
 		return (error);
 
 	/*
-	 * Save the new accounting file vnode, and schedule the new
-	 * free space watcher.
+	 * Save the new accounting file vnode and credential,
+	 * and schedule the new free space watcher.
 	 */
 	acctp = nd.ni_vp;
-	acctwatch(NULL);
+	acct_ucred = p->p_ucred;
+	crhold(acct_ucred);
+#ifdef ACCT_DEBUG
+	log(LOG_NOTICE, "Accounting file is opend: %p\n", acctp);
+#endif
+	schedule_acctwatch();
 	return (error);
 }
 
@@ -163,6 +184,7 @@
 	struct timeval ut, st, tmp;
 	int s, t;
 	struct vnode *vp;
+	int error;
 
 	/* If accounting isn't enabled, don't bother */
 	vp = acctp;
@@ -217,9 +239,15 @@
 	 * Now, just write the accounting information to the file.
 	 */
 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
-	return (vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct),
-	    (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, p->p_ucred,
-	    (int *)0, p));
+	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct),
+	    (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, acct_ucred,
+	    (int *)0, p);
+
+#ifdef ACCT_DEBUG
+	if (error)
+		log(LOG_NOTICE, "Accounting file write error: %d\n", error);
+#endif
+	return (error);
 }
 
 /*
@@ -266,11 +294,11 @@
  * should be turned on or off.  Beware the case where the vnode
  * has been vgone()'d out from underneath us, e.g. when the file
  * system containing the accounting file has been forcibly unmounted.
+ *
+ * Returns non-zero if accounting file is closed.
  */
-/* ARGSUSED */
-void
-acctwatch(a)
-	void *a;
+int
+check_diskspace()
 {
 	struct statfs sb;
 
@@ -278,7 +306,11 @@
 		if (savacctp->v_type == VBAD) {
 			(void) vn_close(savacctp, FWRITE, NOCRED, NULL);
 			savacctp = NULLVP;
-			return;
+#ifdef ACCT_DEBUG
+			log(LOG_NOTICE,
+			    "Accounting stopped: savacctp is bad\n");
+#endif
+			return (1);
 		}
 		(void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
@@ -290,7 +322,10 @@
 		if (acctp->v_type == VBAD) {
 			(void) vn_close(acctp, FWRITE, NOCRED, NULL);
 			acctp = NULLVP;
-			return;
+#ifdef ACCT_DEBUG
+			log(LOG_NOTICE, "Accounting stopped; acctp is bad\n");
+#endif
+			return (1);
 		}
 		(void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
 		if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
@@ -298,7 +333,46 @@
 			acctp = NULLVP;
 			log(LOG_NOTICE, "Accounting suspended\n");
 		}
-	} else
-		return;
-	timeout(acctwatch, NULL, acctchkfreq * hz);
+	} else {
+#ifdef ACCT_DEBUG
+		log(LOG_NOTICE, "Accounting already stopped\n");
+#endif
+		return (1);
+	}
+
+	return (0);
+}
+
+void
+acctwatch()
+{
+
+	(void) spl0();
+
+	while(1) {
+		tsleep(acctwatch, PZERO, "acctwatch", 0);
+
+		/*
+		 * Check disk free space, and then if accounting file is
+		 * not closed, schedule free space watcher again.
+		 */
+		if (check_diskspace() == 0)
+			schedule_acctwatch();
+	}
+}
+
+void
+schedule_acctwatch()
+{
+
+	timeout(wakeup_acctwatch, NULL, acctchkfreq * hz);
+}
+
+/* ARGSUSED */
+void
+wakeup_acctwatch(a)
+	void *a;
+{
+
+	wakeup(acctwatch);
 }
Index: kern/init_main.c
===================================================================
RCS file: /a/cvsroot/NetBSD/src/sys/kern/init_main.c,v
retrieving revision 1.1.1.11
diff -u -r1.1.1.11 init_main.c
--- init_main.c	1997/06/15 03:10:38	1.1.1.11
+++ init_main.c	1997/06/22 03:45:17
@@ -76,6 +76,7 @@
 #include <sys/domain.h>
 #include <sys/mbuf.h>
 #include <sys/namei.h>
+#include <sys/acct.h>
 
 #include <sys/syscall.h>
 #include <sys/syscallargs.h>
@@ -115,6 +116,7 @@
 static void check_console __P((struct proc *p));
 static void start_init __P((struct proc *));
 static void start_pagedaemon __P((struct proc *));
+static void start_acctwatch __P((struct proc *));
 void main __P((void *));
 
 #ifdef cpu_set_init_frame
@@ -385,6 +387,20 @@
 	cpu_set_kpc(pfind(2), start_pagedaemon);
 #endif
 
+	/* Create process 3 (account disk space watcher). */
+	if (sys_fork(p, NULL, rval))
+		panic("fork acctwatch");
+#ifdef cpu_set_init_frame			/* XXX should go away */
+	if (rval[1]) {
+		/*
+		 * Now in process 3.
+		 */
+		start_acctwatch(curproc);
+	}
+#else
+	cpu_set_kpc(pfind(3), start_acctwatch);
+#endif
+
 	/* The scheduler is an infinite loop. */
 	scheduler();
 	/* NOTREACHED */
@@ -554,5 +570,19 @@
 	p->p_flag |= P_INMEM | P_SYSTEM;	/* XXX */
 	bcopy("pagedaemon", curproc->p_comm, sizeof ("pagedaemon"));
 	vm_pageout();
+	/* NOTREACHED */
+}
+
+static void
+start_acctwatch(p)
+	struct proc *p;
+{
+
+	/*
+	 * Now in process 3.
+	 */
+	p->p_flag |= P_INMEM | P_SYSTEM;	/* XXX */
+	bcopy("acctwatch", curproc->p_comm, sizeof ("acctwatch"));
+	acctwatch();
 	/* NOTREACHED */
 }