diff options
author | Justin T. Gibbs <gibbs@FreeBSD.org> | 2011-06-13 21:21:02 +0000 |
---|---|---|
committer | Justin T. Gibbs <gibbs@FreeBSD.org> | 2011-06-13 21:21:02 +0000 |
commit | 27c959cf05617ed3cf56777f26f07fb0a5ebf67b (patch) | |
tree | a3425da958868cb6bcf024e812b8ec92b6758ef0 /sys/kern | |
parent | 454a02b3728543503f2f30771a867148a27f71b3 (diff) | |
download | src-27c959cf05617ed3cf56777f26f07fb0a5ebf67b.tar.gz src-27c959cf05617ed3cf56777f26f07fb0a5ebf67b.zip |
Fix a couple of race conditions in devstat(9) initialization.
In devstat_new_entry(), there is no need to initialize the queue
and the mutex in this function. There are ways to do static
initialization on both, so use STAILQ_HEAD_INITIALIZER and
MTX_SYSINIT to initialize the queue and the mutex.
In devstat_alloc(), use an atomic test and set routine to guard
making our entry in /dev. Using just a plain static variable
creates a race condition on multiprocessor machines. If you
attempt to create a second entry in devfs, the kernel will panic.
Submitted by: kdm
Reviewed by: gibbs
Sponsored by: Spectra Logic Corporation
MFC after: 1 week.
Notes
Notes:
svn path=/head/; revision=223061
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/subr_devstat.c | 12 |
1 files changed, 3 insertions, 9 deletions
diff --git a/sys/kern/subr_devstat.c b/sys/kern/subr_devstat.c index 24963d56959e..402051fb8a83 100644 --- a/sys/kern/subr_devstat.c +++ b/sys/kern/subr_devstat.c @@ -49,8 +49,9 @@ static long devstat_generation = 1; static int devstat_version = DEVSTAT_VERSION; static int devstat_current_devnumber; static struct mtx devstat_mutex; +MTX_SYSINIT(devstat_mutex, &devstat_mutex, "devstat", MTX_DEF); -static struct devstatlist device_statq; +static struct devstatlist device_statq = STAILQ_HEAD_INITIALIZER(device_statq); static struct devstat *devstat_alloc(void); static void devstat_free(struct devstat *); static void devstat_add_entry(struct devstat *ds, const void *dev_name, @@ -70,13 +71,7 @@ devstat_new_entry(const void *dev_name, devstat_priority priority) { struct devstat *ds; - static int once; - if (!once) { - STAILQ_INIT(&device_statq); - mtx_init(&devstat_mutex, "devstat", NULL, MTX_DEF); - once = 1; - } mtx_assert(&devstat_mutex, MA_NOTOWNED); ds = devstat_alloc(); @@ -475,10 +470,9 @@ devstat_alloc(void) static int once; mtx_assert(&devstat_mutex, MA_NOTOWNED); - if (!once) { + if (!once && atomic_cmpset_int(&once, 0, 1)) { make_dev_credf(MAKEDEV_ETERNAL, &devstat_cdevsw, 0, NULL, UID_ROOT, GID_WHEEL, 0400, DEVSTAT_DEVICE_NAME); - once = 1; } spp2 = NULL; mtx_lock(&devstat_mutex); |