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); } /*