Mon Mar 20 00:30:03 2017 UTC ()
Make sure we hold alldevs_mtx for access to alldevs in deviter.

- Extend alldevs_mtx section in deviter_init.
- Assert ownership of alldevs_mtx in private functions:
  . deviter_reinit
  . deviter_next1
  . deviter_next2
- Acquire alldevs_mtx in deviter_next.

(alldevs_mtx is not relevant to the struct deviter object, which is
private to the caller who must guarantee exclusive access to it.)


(riastradh)
diff -r1.247 -r1.248 src/sys/kern/subr_autoconf.c

cvs diff -r1.247 -r1.248 src/sys/kern/subr_autoconf.c (expand / switch to unified diff)

--- src/sys/kern/subr_autoconf.c 2016/07/19 07:44:03 1.247
+++ src/sys/kern/subr_autoconf.c 2017/03/20 00:30:03 1.248
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: subr_autoconf.c,v 1.247 2016/07/19 07:44:03 msaitoh Exp $ */ 1/* $NetBSD: subr_autoconf.c,v 1.248 2017/03/20 00:30:03 riastradh Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1996, 2000 Christopher G. Demetriou 4 * Copyright (c) 1996, 2000 Christopher G. Demetriou
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -67,27 +67,27 @@ @@ -67,27 +67,27 @@
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * SUCH DAMAGE. 72 * SUCH DAMAGE.
73 * 73 *
74 * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL) 74 * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL)
75 * 75 *
76 * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94 76 * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
77 */ 77 */
78 78
79#include <sys/cdefs.h> 79#include <sys/cdefs.h>
80__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.247 2016/07/19 07:44:03 msaitoh Exp $"); 80__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.248 2017/03/20 00:30:03 riastradh Exp $");
81 81
82#ifdef _KERNEL_OPT 82#ifdef _KERNEL_OPT
83#include "opt_ddb.h" 83#include "opt_ddb.h"
84#include "drvctl.h" 84#include "drvctl.h"
85#endif 85#endif
86 86
87#include <sys/param.h> 87#include <sys/param.h>
88#include <sys/device.h> 88#include <sys/device.h>
89#include <sys/disklabel.h> 89#include <sys/disklabel.h>
90#include <sys/conf.h> 90#include <sys/conf.h>
91#include <sys/kauth.h> 91#include <sys/kauth.h>
92#include <sys/kmem.h> 92#include <sys/kmem.h>
93#include <sys/systm.h> 93#include <sys/systm.h>
@@ -2771,136 +2771,147 @@ deviter_visits(const deviter_t *di, devi @@ -2771,136 +2771,147 @@ deviter_visits(const deviter_t *di, devi
2771 * Device iteration does not return device_t's in any particular 2771 * Device iteration does not return device_t's in any particular
2772 * order. An iterator will never return the same device_t twice. 2772 * order. An iterator will never return the same device_t twice.
2773 * Device iteration is guaranteed to complete---i.e., if deviter_next(di) 2773 * Device iteration is guaranteed to complete---i.e., if deviter_next(di)
2774 * is called repeatedly on the same `di', it will eventually return 2774 * is called repeatedly on the same `di', it will eventually return
2775 * NULL. It is ok to attach/detach devices during device iteration. 2775 * NULL. It is ok to attach/detach devices during device iteration.
2776 */ 2776 */
2777void 2777void
2778deviter_init(deviter_t *di, deviter_flags_t flags) 2778deviter_init(deviter_t *di, deviter_flags_t flags)
2779{ 2779{
2780 device_t dv; 2780 device_t dv;
2781 2781
2782 memset(di, 0, sizeof(*di)); 2782 memset(di, 0, sizeof(*di));
2783 2783
2784 mutex_enter(&alldevs_mtx); 
2785 if ((flags & DEVITER_F_SHUTDOWN) != 0) 2784 if ((flags & DEVITER_F_SHUTDOWN) != 0)
2786 flags |= DEVITER_F_RW; 2785 flags |= DEVITER_F_RW;
2787 2786
 2787 mutex_enter(&alldevs_mtx);
2788 if ((flags & DEVITER_F_RW) != 0) 2788 if ((flags & DEVITER_F_RW) != 0)
2789 alldevs_nwrite++; 2789 alldevs_nwrite++;
2790 else 2790 else
2791 alldevs_nread++; 2791 alldevs_nread++;
2792 di->di_gen = alldevs_gen++; 2792 di->di_gen = alldevs_gen++;
2793 mutex_exit(&alldevs_mtx); 
2794 
2795 di->di_flags = flags; 2793 di->di_flags = flags;
2796 2794
2797 switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) { 2795 switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
2798 case DEVITER_F_LEAVES_FIRST: 2796 case DEVITER_F_LEAVES_FIRST:
2799 TAILQ_FOREACH(dv, &alldevs, dv_list) { 2797 TAILQ_FOREACH(dv, &alldevs, dv_list) {
2800 if (!deviter_visits(di, dv)) 2798 if (!deviter_visits(di, dv))
2801 continue; 2799 continue;
2802 di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth); 2800 di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth);
2803 } 2801 }
2804 break; 2802 break;
2805 case DEVITER_F_ROOT_FIRST: 2803 case DEVITER_F_ROOT_FIRST:
2806 TAILQ_FOREACH(dv, &alldevs, dv_list) { 2804 TAILQ_FOREACH(dv, &alldevs, dv_list) {
2807 if (!deviter_visits(di, dv)) 2805 if (!deviter_visits(di, dv))
2808 continue; 2806 continue;
2809 di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth); 2807 di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth);
2810 } 2808 }
2811 break; 2809 break;
2812 default: 2810 default:
2813 break; 2811 break;
2814 } 2812 }
2815 2813
2816 deviter_reinit(di); 2814 deviter_reinit(di);
 2815 mutex_exit(&alldevs_mtx);
2817} 2816}
2818 2817
2819static void 2818static void
2820deviter_reinit(deviter_t *di) 2819deviter_reinit(deviter_t *di)
2821{ 2820{
 2821
 2822 KASSERT(mutex_owned(&alldevs_mtx));
2822 if ((di->di_flags & DEVITER_F_RW) != 0) 2823 if ((di->di_flags & DEVITER_F_RW) != 0)
2823 di->di_prev = TAILQ_LAST(&alldevs, devicelist); 2824 di->di_prev = TAILQ_LAST(&alldevs, devicelist);
2824 else 2825 else
2825 di->di_prev = TAILQ_FIRST(&alldevs); 2826 di->di_prev = TAILQ_FIRST(&alldevs);
2826} 2827}
2827 2828
2828device_t 2829device_t
2829deviter_first(deviter_t *di, deviter_flags_t flags) 2830deviter_first(deviter_t *di, deviter_flags_t flags)
2830{ 2831{
 2832
2831 deviter_init(di, flags); 2833 deviter_init(di, flags);
2832 return deviter_next(di); 2834 return deviter_next(di);
2833} 2835}
2834 2836
2835static device_t 2837static device_t
2836deviter_next2(deviter_t *di) 2838deviter_next2(deviter_t *di)
2837{ 2839{
2838 device_t dv; 2840 device_t dv;
2839 2841
 2842 KASSERT(mutex_owned(&alldevs_mtx));
 2843
2840 dv = di->di_prev; 2844 dv = di->di_prev;
2841 2845
2842 if (dv == NULL) 2846 if (dv == NULL)
2843 return NULL; 2847 return NULL;
2844 2848
2845 if ((di->di_flags & DEVITER_F_RW) != 0) 2849 if ((di->di_flags & DEVITER_F_RW) != 0)
2846 di->di_prev = TAILQ_PREV(dv, devicelist, dv_list); 2850 di->di_prev = TAILQ_PREV(dv, devicelist, dv_list);
2847 else 2851 else
2848 di->di_prev = TAILQ_NEXT(dv, dv_list); 2852 di->di_prev = TAILQ_NEXT(dv, dv_list);
2849 2853
2850 return dv; 2854 return dv;
2851} 2855}
2852 2856
2853static device_t 2857static device_t
2854deviter_next1(deviter_t *di) 2858deviter_next1(deviter_t *di)
2855{ 2859{
2856 device_t dv; 2860 device_t dv;
2857 2861
 2862 KASSERT(mutex_owned(&alldevs_mtx));
 2863
2858 do { 2864 do {
2859 dv = deviter_next2(di); 2865 dv = deviter_next2(di);
2860 } while (dv != NULL && !deviter_visits(di, dv)); 2866 } while (dv != NULL && !deviter_visits(di, dv));
2861 2867
2862 return dv; 2868 return dv;
2863} 2869}
2864 2870
2865device_t 2871device_t
2866deviter_next(deviter_t *di) 2872deviter_next(deviter_t *di)
2867{ 2873{
2868 device_t dv = NULL; 2874 device_t dv = NULL;
2869 2875
 2876 mutex_enter(&alldevs_mtx);
2870 switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) { 2877 switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
2871 case 0: 2878 case 0:
2872 return deviter_next1(di); 2879 dv = deviter_next1(di);
 2880 break;
2873 case DEVITER_F_LEAVES_FIRST: 2881 case DEVITER_F_LEAVES_FIRST:
2874 while (di->di_curdepth >= 0) { 2882 while (di->di_curdepth >= 0) {
2875 if ((dv = deviter_next1(di)) == NULL) { 2883 if ((dv = deviter_next1(di)) == NULL) {
2876 di->di_curdepth--; 2884 di->di_curdepth--;
2877 deviter_reinit(di); 2885 deviter_reinit(di);
2878 } else if (dv->dv_depth == di->di_curdepth) 2886 } else if (dv->dv_depth == di->di_curdepth)
2879 break; 2887 break;
2880 } 2888 }
2881 return dv; 2889 break;
2882 case DEVITER_F_ROOT_FIRST: 2890 case DEVITER_F_ROOT_FIRST:
2883 while (di->di_curdepth <= di->di_maxdepth) { 2891 while (di->di_curdepth <= di->di_maxdepth) {
2884 if ((dv = deviter_next1(di)) == NULL) { 2892 if ((dv = deviter_next1(di)) == NULL) {
2885 di->di_curdepth++; 2893 di->di_curdepth++;
2886 deviter_reinit(di); 2894 deviter_reinit(di);
2887 } else if (dv->dv_depth == di->di_curdepth) 2895 } else if (dv->dv_depth == di->di_curdepth)
2888 break; 2896 break;
2889 } 2897 }
2890 return dv; 2898 break;
2891 default: 2899 default:
2892 return NULL; 2900 break;
2893 } 2901 }
 2902 mutex_exit(&alldevs_mtx);
 2903
 2904 return dv;
2894} 2905}
2895 2906
2896void 2907void
2897deviter_release(deviter_t *di) 2908deviter_release(deviter_t *di)
2898{ 2909{
2899 bool rw = (di->di_flags & DEVITER_F_RW) != 0; 2910 bool rw = (di->di_flags & DEVITER_F_RW) != 0;
2900 2911
2901 mutex_enter(&alldevs_mtx); 2912 mutex_enter(&alldevs_mtx);
2902 if (rw) 2913 if (rw)
2903 --alldevs_nwrite; 2914 --alldevs_nwrite;
2904 else 2915 else
2905 --alldevs_nread; 2916 --alldevs_nread;
2906 /* XXX wake a garbage-collection thread */ 2917 /* XXX wake a garbage-collection thread */