Diff below avoids a lock ordering issue between the SCHED_LOCK() and
printf(9)'s mutex.  This problem has been reported multiple times in
drm(4) code where debug printfs are placed between sleep_setup() and
sleep_finish().

The problem is easily fixed. logwakeup() must not be called while
holding the mutex.  This function can end up in wakeup_n() which will
grab the SCHED_LOCK().

While here ensure that the mutex is always when TOCONS is specified.
This was not the case in the error path of log(9) and addlog(9).

Ok?

Index: kern/subr_prf.c
===================================================================
RCS file: /cvs/src/sys/kern/subr_prf.c,v
retrieving revision 1.94
diff -u -p -r1.94 subr_prf.c
--- kern/subr_prf.c     20 Mar 2018 15:45:32 -0000      1.94
+++ kern/subr_prf.c     9 Apr 2018 11:35:11 -0000
@@ -89,8 +89,7 @@
 int     kprintf(const char *, int, void *, char *, va_list);
 void    kputchar(int, int, struct tty *);
 
-struct mutex kprintf_mutex =
-    MUTEX_INITIALIZER_FLAGS(IPL_HIGH, "kprintf", MTX_NOWITNESS);
+struct mutex kprintf_mutex = MUTEX_INITIALIZER(IPL_HIGH);
 
 /*
  * globals
@@ -264,7 +263,9 @@ log(int level, const char *fmt, ...)
        splx(s);
        if (!log_open) {
                va_start(ap, fmt);
+               mtx_enter(&kprintf_mutex);
                kprintf(fmt, TOCONS, NULL, NULL, ap);
+               mtx_leave(&kprintf_mutex);
                va_end(ap);
        }
        logwakeup();            /* wake up anyone waiting for log msgs */
@@ -304,7 +305,9 @@ addlog(const char *fmt, ...)
        splx(s);
        if (!log_open) {
                va_start(ap, fmt);
+               mtx_enter(&kprintf_mutex);
                kprintf(fmt, TOCONS, NULL, NULL, ap);
+               mtx_leave(&kprintf_mutex);
                va_end(ap);
        }
        logwakeup();
@@ -502,15 +505,15 @@ printf(const char *fmt, ...)
        va_list ap;
        int retval;
 
-       mtx_enter(&kprintf_mutex);
 
        va_start(ap, fmt);
+       mtx_enter(&kprintf_mutex);
        retval = kprintf(fmt, TOCONS | TOLOG, NULL, NULL, ap);
+       mtx_leave(&kprintf_mutex);
        va_end(ap);
        if (!panicstr)
                logwakeup();
 
-       mtx_leave(&kprintf_mutex);
 
        return(retval);
 }
@@ -526,12 +529,11 @@ vprintf(const char *fmt, va_list ap)
        int retval;
 
        mtx_enter(&kprintf_mutex);
-
        retval = kprintf(fmt, TOCONS | TOLOG, NULL, NULL, ap);
+       mtx_leave(&kprintf_mutex);
        if (!panicstr)
                logwakeup();
 
-       mtx_leave(&kprintf_mutex);
 
        return (retval);
 }
@@ -686,6 +688,9 @@ kprintf(const char *fmt0, int oflags, vo
        char *xdigs = NULL;     /* digits for [xX] conversion */
        char buf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX] */
        char *tailp = NULL;     /* tail pointer for snprintf */
+
+       if (oflags & TOCONS)
+               MUTEX_ASSERT_LOCKED(&kprintf_mutex);
 
        if ((oflags & TOBUFONLY) && (vp != NULL))
                tailp = *(char **)vp;

Reply via email to