Module Name:    src
Committed By:   jdolecek
Date:           Thu Feb 20 21:14:23 UTC 2020

Modified Files:
        src/sys/kern: subr_autoconf.c

Log Message:
protect deferred lists' manipulation by config_misc_lock, same as
config_pending semaphore itself; right now this also covers
DVF_ATTACH_INPROGRESS flag


To generate a diff of this commit:
cvs rdiff -u -r1.265 -r1.266 src/sys/kern/subr_autoconf.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/subr_autoconf.c
diff -u src/sys/kern/subr_autoconf.c:1.265 src/sys/kern/subr_autoconf.c:1.266
--- src/sys/kern/subr_autoconf.c:1.265	Sat Dec  1 02:08:16 2018
+++ src/sys/kern/subr_autoconf.c	Thu Feb 20 21:14:23 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_autoconf.c,v 1.265 2018/12/01 02:08:16 msaitoh Exp $ */
+/* $NetBSD: subr_autoconf.c,v 1.266 2020/02/20 21:14:23 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1996, 2000 Christopher G. Demetriou
@@ -77,7 +77,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.265 2018/12/01 02:08:16 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.266 2020/02/20 21:14:23 jdolecek Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -443,16 +443,23 @@ config_interrupts_thread(void *cookie)
 {
 	struct deferred_config *dc;
 
+	mutex_enter(&config_misc_lock);
 	while ((dc = TAILQ_FIRST(&interrupt_config_queue)) != NULL) {
 		TAILQ_REMOVE(&interrupt_config_queue, dc, dc_queue);
+		mutex_exit(&config_misc_lock);
+
 		(*dc->dc_func)(dc->dc_dev);
-		dc->dc_dev->dv_flags &= ~DVF_ATTACH_INPROGRESS;
 		if (!device_pmf_is_registered(dc->dc_dev))
 			aprint_debug_dev(dc->dc_dev,
 			    "WARNING: power management not supported\n");
 		config_pending_decr(dc->dc_dev);
 		kmem_free(dc, sizeof(*dc));
+
+		mutex_enter(&config_misc_lock);
+		dc->dc_dev->dv_flags &= ~DVF_ATTACH_INPROGRESS;
 	}
+	mutex_exit(&config_misc_lock);
+
 	kthread_exit(0);
 }
 
@@ -462,7 +469,7 @@ config_create_interruptthreads(void)
 	int i;
 
 	for (i = 0; i < interrupt_config_threads; i++) {
-		(void)kthread_create(PRI_NONE, 0, NULL,
+		(void)kthread_create(PRI_NONE, 0/*XXXSMP */, NULL,
 		    config_interrupts_thread, NULL, NULL, "configintr");
 	}
 }
@@ -472,11 +479,18 @@ config_mountroot_thread(void *cookie)
 {
 	struct deferred_config *dc;
 
+	mutex_enter(&config_misc_lock);
 	while ((dc = TAILQ_FIRST(&mountroot_config_queue)) != NULL) {
 		TAILQ_REMOVE(&mountroot_config_queue, dc, dc_queue);
+		mutex_exit(&config_misc_lock);
+
 		(*dc->dc_func)(dc->dc_dev);
 		kmem_free(dc, sizeof(*dc));
+
+		mutex_enter(&config_misc_lock);
 	}
+	mutex_exit(&config_misc_lock);
+
 	kthread_exit(0);
 }
 
@@ -495,8 +509,8 @@ config_create_mountrootthreads(void)
 	KASSERT(mountroot_config_lwpids);
 	for (i = 0; i < mountroot_config_threads; i++) {
 		mountroot_config_lwpids[i] = 0;
-		(void)kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL,
-				     config_mountroot_thread, NULL,
+		(void)kthread_create(PRI_NONE, KTHREAD_MUSTJOIN/* XXXSMP */,
+				     NULL, config_mountroot_thread, NULL,
 				     &mountroot_config_lwpids[i],
 				     "configroot");
 	}
@@ -1958,18 +1972,22 @@ config_defer(device_t dev, void (*func)(
 	if (dev->dv_parent == NULL)
 		panic("config_defer: can't defer config of a root device");
 
+	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
+
+	config_pending_incr(dev);
+
+	mutex_enter(&config_misc_lock);
 #ifdef DIAGNOSTIC
-	TAILQ_FOREACH(dc, &deferred_config_queue, dc_queue) {
-		if (dc->dc_dev == dev)
+	struct deferred_config *odc;
+	TAILQ_FOREACH(odc, &deferred_config_queue, dc_queue) {
+		if (odc->dc_dev == dev)
 			panic("config_defer: deferred twice");
 	}
 #endif
-
-	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
 	dc->dc_dev = dev;
 	dc->dc_func = func;
 	TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
-	config_pending_incr(dev);
+	mutex_exit(&config_misc_lock);
 }
 
 /*
@@ -1989,19 +2007,23 @@ config_interrupts(device_t dev, void (*f
 		return;
 	}
 
+	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
+
+	config_pending_incr(dev);
+
+	mutex_enter(&config_misc_lock);
 #ifdef DIAGNOSTIC
-	TAILQ_FOREACH(dc, &interrupt_config_queue, dc_queue) {
-		if (dc->dc_dev == dev)
+	struct deferred_config *odc;
+	TAILQ_FOREACH(odc, &interrupt_config_queue, dc_queue) {
+		if (odc->dc_dev == dev)
 			panic("config_interrupts: deferred twice");
 	}
 #endif
-
-	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
 	dc->dc_dev = dev;
 	dc->dc_func = func;
 	TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
-	config_pending_incr(dev);
 	dev->dv_flags |= DVF_ATTACH_INPROGRESS;
+	mutex_exit(&config_misc_lock);
 }
 
 /*
@@ -2021,17 +2043,21 @@ config_mountroot(device_t dev, void (*fu
 		return;
 	}
 
+	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
+
+	mutex_enter(&config_misc_lock);
 #ifdef DIAGNOSTIC
-	TAILQ_FOREACH(dc, &mountroot_config_queue, dc_queue) {
-		if (dc->dc_dev == dev)
+	struct deferred_config *odc;
+	TAILQ_FOREACH(odc, &mountroot_config_queue, dc_queue) {
+		if (odc->dc_dev == dev)
 			panic("%s: deferred twice", __func__);
 	}
 #endif
 
-	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
 	dc->dc_dev = dev;
 	dc->dc_func = func;
 	TAILQ_INSERT_TAIL(&mountroot_config_queue, dc, dc_queue);
+	mutex_exit(&config_misc_lock);
 }
 
 /*
@@ -2040,17 +2066,27 @@ config_mountroot(device_t dev, void (*fu
 static void
 config_process_deferred(struct deferred_config_head *queue, device_t parent)
 {
-	struct deferred_config *dc, *ndc;
+	struct deferred_config *dc;
 
-	for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
-		ndc = TAILQ_NEXT(dc, dc_queue);
+	mutex_enter(&config_misc_lock);
+	dc = TAILQ_FIRST(queue);
+	while (dc) {
 		if (parent == NULL || dc->dc_dev->dv_parent == parent) {
 			TAILQ_REMOVE(queue, dc, dc_queue);
+			mutex_exit(&config_misc_lock);
+
 			(*dc->dc_func)(dc->dc_dev);
 			config_pending_decr(dc->dc_dev);
 			kmem_free(dc, sizeof(*dc));
+
+			mutex_enter(&config_misc_lock);
+			/* Restart, queue might have changed */
+			dc = TAILQ_FIRST(queue);
+		} else {
+			dc = TAILQ_NEXT(dc, dc_queue);
 		}
 	}
+	mutex_exit(&config_misc_lock);
 }
 
 /*

Reply via email to