Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 15 Jun 2003 14:06:50 +0100
From:      Ian Dowse <iedowse@maths.tcd.ie>
To:        freebsd-arch@freebsd.org
Subject:   Message buffer and printf reentrancy patch
Message-ID:  <200306151406.aa36218@salmon.maths.tcd.ie>

next in thread | raw e-mail | index | archive | help

Below is a patch that makes the implementation of the kernel message
buffer mostly reentrant and more generic, and stops printf() ever
calling directly into the tty code. This should fix panics that can
occur via tputchar() when using xconsole, and generally make the
use of printf() in the kernel a bit safer. Many of the ideas here
were suggested by Bruce Evans.

A summary of the changes:
 - Use atomic operations to update the message buffer pointers.
 - Use a kind of sequence number for the pointers instead of just
   the offset into the buffer, as this avoids the need for the read
   code to touch the write pointer or the write code to touch the
   read pointer.
 - Change the interface to the message buffer functions so that
   the internals are not exposed to the callers, and pass in the
   message buffer structure pointer to all functions.
 - Put the new message buffer code in a new file subr_msgbuf.c.

 - Add a new message buffer `consmsgbuf' that is used to pass
   kernel messages to the TIOCCONS tty.
 - Allocate the buffer space for this when the console is redirected
   with TIOCCONS, and free it after the console is detached.
 - Use a timeout routine to send the messages to the tty.

 - Disable the virtual tty console while DDB is active.

I'd like to commit this in a few days. Any objections, comments or
suggestions?

Ian


Index: sbin/dmesg/dmesg.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sbin/dmesg/dmesg.c,v
retrieving revision 1.19
diff -u -r1.19 dmesg.c
--- sbin/dmesg/dmesg.c	2 May 2003 07:08:52 -0000	1.19
+++ sbin/dmesg/dmesg.c	18 May 2003 13:03:16 -0000
@@ -137,9 +137,7 @@
 			errx(1, "kvm_read: %s", kvm_geterr(kd));
 		kvm_close(kd);
 		buflen = cur.msg_size;
-		bufpos = cur.msg_bufx;
-		if (bufpos >= buflen)
-			bufpos = 0;
+		bufpos = MSGBUF_SEQ_TO_POS(&cur, cur.msg_wseq);
 	}
 
 	/*
Index: sys/sys/msgbuf.h
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/sys/msgbuf.h,v
retrieving revision 1.20
diff -u -r1.20 msgbuf.h
--- sys/sys/msgbuf.h	28 Mar 2003 02:50:10 -0000	1.20
+++ sys/sys/msgbuf.h	15 Jun 2003 12:00:45 -0000
@@ -41,16 +41,32 @@
 #define	MSG_MAGIC	0x063062
 	u_int	msg_magic;
 	int	msg_size;		/* size of buffer area */
-	int	msg_bufx;		/* write pointer */
-	int	msg_bufr;		/* read pointer */
+	int	msg_wseq;		/* write sequence number */
+	int	msg_rseq;		/* read sequence number */
+	int	msg_seqmod;		/* range for sequence numbers */
 	char	*msg_ptr;		/* pointer to buffer */
 	u_int	msg_cksum;		/* checksum of contents */
 };
 
+#define MSGBUF_SEQNORM(mbp, seq) ((seq) % (mbp)->msg_seqmod + ((seq) < 0 ? \
+    (mbp)->msg_seqmod : 0))
+#define MSGBUF_SEQ_TO_POS(mbp, seq) ((int)((u_int)(seq) % \
+    (u_int)(mbp)->msg_size))
+#define MSGBUF_SEQSUB(mbp, seq1, seq2) (MSGBUF_SEQNORM(mbp, (seq1) - (seq2)))
+
 #ifdef _KERNEL
 extern int	msgbuftrigger;
 extern struct	msgbuf *msgbufp;
 void	msgbufinit(void *ptr, int size);
+void	msgbuf_addchar(struct msgbuf *mbp, int c);
+void	msgbuf_clear(struct msgbuf *mbp);
+void	msgbuf_copy(struct msgbuf *src, struct msgbuf *dst);
+int	msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen);
+int	msgbuf_getchar(struct msgbuf *mbp);
+int	msgbuf_getcount(struct msgbuf *mbp);
+void	msgbuf_init(struct msgbuf *mbp, void *ptr, int size);
+void	msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size);
+int	msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, int *seqp);
 
 #if !defined(MSGBUF_SIZE)
 #define	MSGBUF_SIZE	32768
Index: sys/sys/tty.h
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/sys/tty.h,v
retrieving revision 1.71
diff -u -r1.71 tty.h
--- sys/sys/tty.h	5 Mar 2003 08:17:10 -0000	1.71
+++ sys/sys/tty.h	15 Jun 2003 01:27:23 -0000
@@ -265,6 +265,7 @@
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_TTYS);
 #endif
+extern	struct msgbuf consmsgbuf; /* Message buffer for constty. */
 extern	struct tty *constty;	/* Temporary virtual console. */
 extern long tk_cancc;
 extern long tk_nin;
@@ -275,6 +276,8 @@
 void	 catq(struct clist *from, struct clist *to);
 void	 clist_alloc_cblocks(struct clist *q, int ccmax, int ccres);
 void	 clist_free_cblocks(struct clist *q);
+void	 constty_set(struct tty *tp);
+void	 constty_clear(void);
 int	 getc(struct clist *q);
 void	 ndflush(struct clist *q, int cc);
 char	*nextc(struct clist *q, char *cp, int *c);
Index: sys/kern/tty.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/kern/tty.c,v
retrieving revision 1.202
diff -u -r1.202 tty.c
--- sys/kern/tty.c	11 Jun 2003 00:56:58 -0000	1.202
+++ sys/kern/tty.c	15 Jun 2003 10:31:53 -0000
@@ -261,7 +261,7 @@
 	funsetown(&tp->t_sigio);
 	s = spltty();
 	if (constty == tp)
-		constty = NULL;
+		constty_clear();
 
 	ttyflush(tp, FREAD | FWRITE);
 	clist_free_cblocks(&tp->t_canq);
@@ -871,9 +871,9 @@
 			if (error)
 				return (error);
 
-			constty = tp;
+			constty_set(tp);
 		} else if (tp == constty)
-			constty = NULL;
+			constty_clear();
 		break;
 	case TIOCDRAIN:			/* wait till output drained */
 		error = ttywait(tp);
Index: sys/kern/tty_cons.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/kern/tty_cons.c,v
retrieving revision 1.111
diff -u -r1.111 tty_cons.c
--- sys/kern/tty_cons.c	11 Jun 2003 00:56:58 -0000	1.111
+++ sys/kern/tty_cons.c	15 Jun 2003 01:15:23 -0000
@@ -50,6 +50,7 @@
 #include <sys/fcntl.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
+#include <sys/msgbuf.h>
 #include <sys/namei.h>
 #include <sys/proc.h>
 #include <sys/queue.h>
@@ -117,11 +118,16 @@
 static int cn_mute;
 static int openflag;			/* how /dev/console was opened */
 static int cn_is_open;
+static char *consbuf;			/* buffer used by `consmsgbuf' */
+static struct callout conscallout;	/* callout for outputting to constty */
+struct msgbuf consmsgbuf;		/* message buffer for console tty */
 static u_char console_pausing;		/* pause after each line during probe */
 static char *console_pausestr=
 "<pause; press any key to proceed to next line or '.' to end pause mode>";
+struct tty *constty;			/* pointer to console "window" tty */
 
 void	cndebug(char *);
+static void constty_timeout(void *arg);
 
 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 SET_DECLARE(cons_set, struct consdev);
@@ -587,6 +593,70 @@
 		}
 	if (on)
 		refcount++;
+}
+
+static int consmsgbuf_size = 8192;
+SYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0,
+    "");
+
+/*
+ * Redirect console output to a tty.
+ */
+void
+constty_set(struct tty *tp)
+{
+	int size;
+
+	KASSERT(tp != NULL, ("constty_set: NULL tp"));
+	if (consbuf == NULL) {
+		size = consmsgbuf_size;
+		consbuf = malloc(size, M_TTYS, M_WAITOK);
+		msgbuf_init(&consmsgbuf, consbuf, size);
+		callout_init(&conscallout, 0);
+	}
+	constty = tp;
+	constty_timeout(NULL);
+}
+
+/*
+ * Disable console redirection to a tty.
+ */
+void
+constty_clear(void)
+{
+	int c;
+
+	constty = NULL;
+	if (consbuf == NULL)
+		return;
+	callout_stop(&conscallout);
+	while ((c = msgbuf_getchar(&consmsgbuf)) != -1)
+		cnputc(c);
+	free(consbuf, M_TTYS);
+	consbuf = NULL;
+}
+
+/* Times per second to check for pending console tty messages. */
+static int constty_wakeups_per_second = 5;
+SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW,
+    &constty_wakeups_per_second, 0, "");
+
+static void
+constty_timeout(void *arg)
+{
+	int c;
+
+	while (constty != NULL && (c = msgbuf_getchar(&consmsgbuf)) != -1) {
+		if (tputchar(c, constty) < 0)
+			constty = NULL;
+	}
+	if (constty != NULL) {
+		callout_reset(&conscallout, hz / constty_wakeups_per_second,
+		    constty_timeout, NULL);
+	} else {
+		/* Deallocate the constty buffer memory. */
+		constty_clear();
+	}
 }
 
 static void
Index: sys/kern/subr_msgbuf.c
===================================================================
RCS file: sys/kern/subr_msgbuf.c
diff -N sys/kern/subr_msgbuf.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/kern/subr_msgbuf.c	15 Jun 2003 12:05:37 -0000
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2003 Ian Dowse.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Generic message buffer support routines.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/msgbuf.h>
+
+/* Read/write sequence numbers are modulo a multiple of the buffer size. */
+#define SEQMOD(size) ((size) * 16)
+
+static u_int msgbuf_cksum(struct msgbuf *mbp);
+
+/*
+ * Initialize a message buffer of the specified size at the specified
+ * location. This also zeros the buffer area.
+ */
+void
+msgbuf_init(struct msgbuf *mbp, void *ptr, int size)
+{
+
+	mbp->msg_ptr = ptr;
+	mbp->msg_size = size;
+	mbp->msg_seqmod = SEQMOD(size);
+	msgbuf_clear(mbp);
+	mbp->msg_magic = MSG_MAGIC;
+}
+
+/*
+ * Reinitialize a message buffer, retaining its previous contents if
+ * the size and checksum are correct. If the old contents cannot be
+ * recovered, the message buffer is cleared.
+ */
+void
+msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size)
+{
+	u_int cksum;
+
+	if (mbp->msg_magic != MSG_MAGIC || mbp->msg_size != size) {
+		msgbuf_init(mbp, ptr, size);
+		return;
+	}
+	mbp->msg_seqmod = SEQMOD(size);
+	mbp->msg_wseq = MSGBUF_SEQNORM(mbp, mbp->msg_wseq);
+	mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq);
+        mbp->msg_ptr = ptr;
+	cksum = msgbuf_cksum(mbp);
+	if (cksum != mbp->msg_cksum) {
+		printf("msgbuf cksum mismatch (read %x, calc %x)\n",
+		    mbp->msg_cksum, cksum);
+		msgbuf_clear(mbp);
+	}
+}
+
+/*
+ * Clear the message buffer.
+ */
+void
+msgbuf_clear(struct msgbuf *mbp)
+{
+
+	bzero(mbp->msg_ptr, mbp->msg_size);
+	mbp->msg_wseq = 0;
+	mbp->msg_rseq = 0;
+	mbp->msg_cksum = 0;
+}
+
+/*
+ * Get a count of the number of unread characters in the message buffer.
+ */
+int
+msgbuf_getcount(struct msgbuf *mbp)
+{
+	int len;
+
+	len = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_rseq);
+	if (len < 0 || len > mbp->msg_size)
+		len = mbp->msg_size;
+	return (len);
+}
+
+/*
+ * Append a character to a message buffer.  This function can be
+ * considered fully reentrant so long as the number of concurrent
+ * callers is less than the number of characters in the buffer.
+ * However, the message buffer is only guaranteed to be consistent
+ * for reading when there are no callers in this function.
+ */
+void
+msgbuf_addchar(struct msgbuf *mbp, int c)
+{
+	int new_seq, pos, seq;
+
+	do {
+		seq = mbp->msg_wseq;
+		new_seq = MSGBUF_SEQNORM(mbp, seq + 1);
+	} while (atomic_cmpset_rel_int(&mbp->msg_wseq, seq, new_seq) == 0);
+	pos = MSGBUF_SEQ_TO_POS(mbp, seq);
+	atomic_add_int(&mbp->msg_cksum, (u_int)(u_char)c -
+	    (u_int)(u_char)mbp->msg_ptr[pos]);
+	mbp->msg_ptr[pos] = c;
+}
+
+/*
+ * Read and mark as read a character from a message buffer.
+ * Returns the character, or -1 if no characters are available.
+ */
+int
+msgbuf_getchar(struct msgbuf *mbp)
+{
+	int c, len, wseq;
+
+	wseq = mbp->msg_wseq;
+	len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
+	if (len == 0)
+		return (-1);
+	if (len < 0 || len > mbp->msg_size)
+		mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
+	c = (u_char)mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq)];
+	mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + 1);
+	return (c);
+}
+
+/*
+ * Read and mark as read a number of characters from a message buffer.
+ * Returns the number of characters that were placed in `buf'.
+ */
+int
+msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen)
+{
+	int len, pos, wseq;
+
+	wseq = mbp->msg_wseq;
+	len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
+	if (len == 0)
+		return (0);
+	if (len < 0 || len > mbp->msg_size) {
+		mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
+		len = mbp->msg_size;
+	}
+	pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq);
+	len = imin(len, mbp->msg_size - pos);
+	len = imin(len, buflen);
+
+	bcopy(&mbp->msg_ptr[pos], buf, len);
+	mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + len);
+	return (len);
+}
+
+/*
+ * Peek at the full contents of a message buffer without marking any
+ * data as read. `seqp' should point to an integer that
+ * msgbuf_peekbytes() can use to retain state between calls so that
+ * the whole message buffer can be read in multiple short reads.
+ * To initialise this variable to the start of the message buffer,
+ * call msgbuf_peekbytes() with a NULL `buf' parameter.
+ *
+ * Returns the number of characters that were placed in `buf'.
+ */
+int
+msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, int *seqp)
+{
+	int len, pos, wseq;
+
+	if (buf == NULL) {
+		/* Just initialise *seqp. */
+		*seqp = MSGBUF_SEQNORM(mbp, mbp->msg_wseq - mbp->msg_size);
+		return (0);
+	}
+
+	wseq = mbp->msg_wseq;
+	len = MSGBUF_SEQSUB(mbp, wseq, *seqp);
+	if (len == 0)
+		return (0);
+	if (len < 0 || len > mbp->msg_size) {
+		*seqp = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
+		len = mbp->msg_size;
+	}
+	pos = MSGBUF_SEQ_TO_POS(mbp, *seqp);
+	len = imin(len, mbp->msg_size - pos);
+	len = imin(len, buflen);
+	bcopy(&mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, *seqp)], buf, len);
+	*seqp = MSGBUF_SEQNORM(mbp, *seqp + len);
+	return (len);
+}
+
+/*
+ * Compute the checksum for the complete message buffer contents.
+ */
+static u_int
+msgbuf_cksum(struct msgbuf *mbp)
+{
+	u_int sum;
+	int i;
+
+	sum = 0;
+	for (i = 0; i < mbp->msg_size; i++)
+		sum += (u_char)mbp->msg_ptr[i];
+	return (sum);
+}
+
+/*
+ * Copy from one message buffer to another.
+ */
+void
+msgbuf_copy(struct msgbuf *src, struct msgbuf *dst)
+{
+	int c;
+
+	while ((c = msgbuf_getchar(src)) >= 0)
+		msgbuf_addchar(dst, c);
+}
Index: sys/kern/subr_log.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/kern/subr_log.c,v
retrieving revision 1.56
diff -u -r1.56 subr_log.c
--- sys/kern/subr_log.c	11 Jun 2003 00:56:57 -0000	1.56
+++ sys/kern/subr_log.c	14 Jun 2003 14:59:09 -0000
@@ -122,11 +122,12 @@
 static	int
 logread(dev_t dev, struct uio *uio, int flag)
 {
+	char buf[128];
 	struct msgbuf *mbp = msgbufp;
 	int error = 0, l, s;
 
 	s = splhigh();
-	while (mbp->msg_bufr == mbp->msg_bufx) {
+	while (msgbuf_getcount(mbp) == 0) {
 		if (flag & IO_NDELAY) {
 			splx(s);
 			return (EWOULDBLOCK);
@@ -141,19 +142,13 @@
 	logsoftc.sc_state &= ~LOG_RDWAIT;
 
 	while (uio->uio_resid > 0) {
-		l = mbp->msg_bufx - mbp->msg_bufr;
-		if (l < 0)
-			l = mbp->msg_size - mbp->msg_bufr;
-		l = imin(l, uio->uio_resid);
+		l = imin(sizeof(buf), uio->uio_resid);
+		l = msgbuf_getbytes(mbp, buf, l);
 		if (l == 0)
 			break;
-		error = uiomove((char *)msgbufp->msg_ptr + mbp->msg_bufr,
-		    l, uio);
+		error = uiomove(buf, l, uio);
 		if (error)
 			break;
-		mbp->msg_bufr += l;
-		if (mbp->msg_bufr >= mbp->msg_size)
-			mbp->msg_bufr = 0;
 	}
 	return (error);
 }
@@ -168,7 +163,7 @@
 	s = splhigh();
 
 	if (events & (POLLIN | POLLRDNORM)) {
-		if (msgbufp->msg_bufr != msgbufp->msg_bufx)
+		if (msgbuf_getcount(msgbufp) > 0)
 			revents |= events & (POLLIN | POLLRDNORM);
 		else
 			selrecord(td, &logsoftc.sc_selp);
@@ -204,18 +199,12 @@
 static	int
 logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct thread *td)
 {
-	int l, s;
 
 	switch (com) {
 
 	/* return number of characters immediately available */
 	case FIONREAD:
-		s = splhigh();
-		l = msgbufp->msg_bufx - msgbufp->msg_bufr;
-		splx(s);
-		if (l < 0)
-			l += msgbufp->msg_size;
-		*(int *)data = l;
+		*(int *)data = msgbuf_getcount(msgbufp);
 		break;
 
 	case FIONBIO:
Index: sys/kern/subr_prf.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/kern/subr_prf.c,v
retrieving revision 1.102
diff -u -r1.102 subr_prf.c
--- sys/kern/subr_prf.c	11 Jun 2003 00:56:57 -0000	1.102
+++ sys/kern/subr_prf.c	15 Jun 2003 01:14:14 -0000
@@ -89,12 +89,7 @@
 
 extern	int log_open;
 
-struct	tty *constty;			/* pointer to console "window" tty */
-
-static void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
 static void  msglogchar(int c, int pri);
-static void  msgaddchar(int c, void *dummy);
-static u_int msgbufcksum(char *cp, size_t size, u_int cksum);
 static void  putchar(int ch, void *arg);
 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len);
 static void  snprintf_func(int ch, void *arg);
@@ -337,21 +332,28 @@
 putchar(int c, void *arg)
 {
 	struct putchar_arg *ap = (struct putchar_arg*) arg;
-	int flags = ap->flags;
 	struct tty *tp = ap->tty;
+	int consdirect, flags = ap->flags;
+
+	consdirect = ((flags & TOCONS) && constty == NULL) || !msgbufmapped;
+	/* Don't use the tty code after a panic or while in ddb. */
 	if (panicstr)
-		constty = NULL;
-	if ((flags & TOCONS) && tp == NULL && constty) {
-		tp = constty;
-		flags |= TOTTY;
-	}
-	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
-	    (flags & TOCONS) && tp == constty)
-		constty = NULL;
+		consdirect = 1;
+#ifdef DDB
+	if (db_active)
+		consdirect = 1;
+#endif
+	if (consdirect) {
+		if (c != '\0')
+			cnputc(c);
+	} else {
+		if ((flags & TOTTY) && tp != NULL)
+			tputchar(c, tp);
+		if ((flags & TOCONS) && constty != NULL)
+			msgbuf_addchar(&consmsgbuf, c);
+	}
 	if ((flags & TOLOG))
 		msglogchar(c, ap->pri);
-	if ((flags & TOCONS) && constty == NULL && c != '\0')
-		(*v_putc)(c);
 }
 
 /*
@@ -788,16 +790,16 @@
 		return;
 	if (pri != -1 && pri != lastpri) {
 		if (dangling) {
-			msgaddchar('\n', NULL);
+			msgbuf_addchar(msgbufp, '\n');
 			dangling = 0;
 		}
-		msgaddchar('<', NULL);
+		msgbuf_addchar(msgbufp, '<');
 		for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL); *p;)
-			msgaddchar(*p--, NULL);
-		msgaddchar('>', NULL);
+			msgbuf_addchar(msgbufp, *p--);
+		msgbuf_addchar(msgbufp, '>');
 		lastpri = pri;
 	}
-	msgaddchar(c, NULL);
+	msgbuf_addchar(msgbufp, c);
 	if (c == '\n') {
 		dangling = 0;
 		lastpri = -1;
@@ -806,41 +808,6 @@
 	}
 }
 
-/*
- * Put char in log buffer
- */
-static void
-msgaddchar(int c, void *dummy)
-{
-	struct msgbuf *mbp;
-
-	if (!msgbufmapped)
-		return;
-	mbp = msgbufp;
-	mbp->msg_cksum += (u_char)c - (u_char)mbp->msg_ptr[mbp->msg_bufx];
-	mbp->msg_ptr[mbp->msg_bufx++] = c;
-	if (mbp->msg_bufx >= mbp->msg_size)
-		mbp->msg_bufx = 0;
-	/* If the buffer is full, keep the most recent data. */
-	if (mbp->msg_bufr == mbp->msg_bufx) {
-		if (++mbp->msg_bufr >= mbp->msg_size)
-			mbp->msg_bufr = 0;
-	}
-}
-
-static void
-msgbufcopy(struct msgbuf *oldp)
-{
-	int pos;
-
-	pos = oldp->msg_bufr;
-	while (pos != oldp->msg_bufx) {
-		msglogchar(oldp->msg_ptr[pos], -1);
-		if (++pos >= oldp->msg_size)
-			pos = 0;
-	}
-}
-
 void
 msgbufinit(void *ptr, int size)
 {
@@ -849,39 +816,14 @@
 
 	size -= sizeof(*msgbufp);
 	cp = (char *)ptr;
-	msgbufp = (struct msgbuf *) (cp + size);
-	if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_size != size ||
-	    msgbufp->msg_bufx >= size || msgbufp->msg_bufx < 0 ||
-	    msgbufp->msg_bufr >= size || msgbufp->msg_bufr < 0 ||
-	    msgbufcksum(cp, size, msgbufp->msg_cksum) != msgbufp->msg_cksum) {
-		bzero(cp, size);
-		bzero(msgbufp, sizeof(*msgbufp));
-		msgbufp->msg_magic = MSG_MAGIC;
-		msgbufp->msg_size = size;
-	}
-	msgbufp->msg_ptr = cp;
+	msgbufp = (struct msgbuf *)(cp + size);
+	msgbuf_reinit(msgbufp, cp, size);
 	if (msgbufmapped && oldp != msgbufp)
-		msgbufcopy(oldp);
+		msgbuf_copy(oldp, msgbufp);
 	msgbufmapped = 1;
 	oldp = msgbufp;
 }
 
-static u_int
-msgbufcksum(char *cp, size_t size, u_int cksum)
-{
-	u_int sum;
-	int i;
-
-	sum = 0;
-	for (i = 0; i < size; i++)
-		sum += (u_char)cp[i];
-	if (sum != cksum)
-		printf("msgbuf cksum mismatch (read %x, calc %x)\n", cksum,
-		    sum);
-
-	return (sum);
-}
-
 SYSCTL_DECL(_security_bsd);
 
 static int unprivileged_read_msgbuf = 1;
@@ -893,7 +835,8 @@
 static int
 sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
 {
-	int error;
+	char buf[128];
+	int error, len, seq;
 
 	if (!unprivileged_read_msgbuf) {
 		error = suser(req->td);
@@ -901,25 +844,20 @@
 			return (error);
 	}
 
-	/*
-	 * Unwind the buffer, so that it's linear (possibly starting with
-	 * some initial nulls).
-	 */
-	error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr + msgbufp->msg_bufx,
-	    msgbufp->msg_size - msgbufp->msg_bufx, req);
-	if (error)
-		return (error);
-	if (msgbufp->msg_bufx > 0) {
-		error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr,
-		    msgbufp->msg_bufx, req);
+	/* Read the whole buffer, one chunk at a time. */
+	msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
+	while ((len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq)) > 0) {
+		error = sysctl_handle_opaque(oidp, buf, len, req);
+		if (error)
+			return (error);
 	}
-	return (error);
+	return (0);
 }
 
 SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
     0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
 
-static int msgbuf_clear;
+static int msgbuf_clearflag;
 
 static int
 sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
@@ -927,17 +865,14 @@
 	int error;
 	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
 	if (!error && req->newptr) {
-		/* Clear the buffer and reset write pointer */
-		bzero(msgbufp->msg_ptr, msgbufp->msg_size);
-		msgbufp->msg_bufr = msgbufp->msg_bufx = 0;
-		msgbufp->msg_cksum = 0;
-		msgbuf_clear = 0;
+		msgbuf_clear(msgbufp);
+		msgbuf_clearflag = 0;
 	}
 	return (error);
 }
 
 SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
-    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clear, 0,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clearflag, 0,
     sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
 
 #ifdef DDB
@@ -951,11 +886,11 @@
 		return;
 	}
 	db_printf("msgbufp = %p\n", msgbufp);
-	db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p, cksum= %d\n",
-	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
-	    msgbufp->msg_bufx, msgbufp->msg_ptr, msgbufp->msg_cksum);
+	db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n",
+	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq,
+	    msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum);
 	for (i = 0; i < msgbufp->msg_size; i++) {
-		j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
+		j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq);
 		db_printf("%c", msgbufp->msg_ptr[j]);
 	}
 	db_printf("\n");
Index: sys/conf/files
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/conf/files,v
retrieving revision 1.792
diff -u -r1.792 files
--- sys/conf/files	13 Jun 2003 12:08:09 -0000	1.792
+++ sys/conf/files	14 Jun 2003 14:57:22 -0000
@@ -1084,6 +1084,7 @@
 kern/subr_mbuf.c	standard
 kern/subr_mchain.c	optional libmchain
 kern/subr_module.c	standard
+kern/subr_msgbuf.c	standard
 kern/subr_param.c	standard
 kern/subr_pcpu.c	standard
 kern/subr_power.c	standard



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