Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/pgoyette-localcount]: src/sys/kern Fix some locking sequences. Thanks t...
details: https://anonhg.NetBSD.org/src/rev/2223415e77c1
branches: pgoyette-localcount
changeset: 852795:2223415e77c1
user: pgoyette <pgoyette%NetBSD.org@localhost>
date: Sat Jul 16 22:35:34 2016 +0000
description:
Fix some locking sequences. Thanks to ristradh@ for the review!
diffstat:
sys/kern/subr_devsw.c | 112 +++++++++++++++++++++++++++++++++++--------------
1 files changed, 79 insertions(+), 33 deletions(-)
diffs (237 lines):
diff -r 0d44b0951cfc -r 2223415e77c1 sys/kern/subr_devsw.c
--- a/sys/kern/subr_devsw.c Sat Jul 16 22:06:42 2016 +0000
+++ b/sys/kern/subr_devsw.c Sat Jul 16 22:35:34 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_devsw.c,v 1.34.2.1 2016/07/16 07:54:13 pgoyette Exp $ */
+/* $NetBSD: subr_devsw.c,v 1.34.2.2 2016/07/16 22:35:34 pgoyette Exp $ */
/*-
* Copyright (c) 2001, 2002, 2007, 2008 The NetBSD Foundation, Inc.
@@ -69,7 +69,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_devsw.c,v 1.34.2.1 2016/07/16 07:54:13 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_devsw.c,v 1.34.2.2 2016/07/16 22:35:34 pgoyette Exp $");
#ifdef _KERNEL_OPT
#include "opt_dtrace.h"
@@ -85,8 +85,10 @@
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/sdt.h>
+#include <sys/atomic.h>
#include <sys/condvar.h>
#include <sys/localcount.h>
+#include <sys/pserialize.h>
#ifdef DEVSW_DEBUG
#define DPRINTF(x) printf x
@@ -139,6 +141,13 @@
mutex_enter(&device_lock);
+ if (bdev != NULL) {
+ KASSERT(bdev->d_localcount != NULL);
+ KASSERT(bdev->d_localcount != cdev->d_localcount);
+ }
+ if (cdev != NULL)
+ KASSERT(cdev->d_localcount != NULL);
+
for (i = 0 ; i < max_devsw_convs ; i++) {
conv = &devsw_conv[i];
if (conv->d_name == NULL || strcmp(devname, conv->d_name) != 0)
@@ -164,13 +173,14 @@
goto fail;
}
+ /* use membar_producer() to ensure visibility of the xdevsw */
if (bdev != NULL) {
- KASSERT(bdev->d_localcount != NULL);
localcount_init(bdev->d_localcount);
+ membar_producer();
bdevsw[*bmajor] = bdev;
}
- KASSERT(cdev->d_localcount != NULL);
localcount_init(cdev->d_localcount);
+ membar_producer();
cdevsw[*cmajor] = cdev;
mutex_exit(&device_lock);
@@ -278,6 +288,9 @@
if (bdevsw[*devmajor] != NULL)
return (EEXIST);
+ /* ensure visibility of the bdevsw */
+ membar_producer();
+
bdevsw[*devmajor] = devsw;
KASSERT(devsw->d_localcount != NULL);
localcount_init(devsw->d_localcount);
@@ -327,6 +340,9 @@
if (cdevsw[*devmajor] != NULL)
return (EEXIST);
+ /* ensure visibility of the bdevsw */
+ membar_producer();
+
cdevsw[*devmajor] = devsw;
KASSERT(devsw->d_localcount != NULL);
localcount_init(devsw->d_localcount);
@@ -335,16 +351,15 @@
}
/*
- * First, look up both bdev and cdev indices, and confirm that the
- * localcount pointer(s) exist. Then drain any existing references,
- * deactivate the localcount(s). Finally, remove the {b,c}devsw[]
- * entries.
+ * First, look up both bdev and cdev indices, and remove the
+ * {b,c]devsw[] entries so no new references can be taken. Then
+ * drain any existing references.
*/
static void
devsw_detach_locked(const struct bdevsw *bdev, const struct cdevsw *cdev)
{
- int i, j;
+ int i, j, s;
KASSERT(mutex_owned(&device_lock));
@@ -370,24 +385,21 @@
break;
}
}
- if (i < max_bdevsws) {
+ if (i < max_bdevsws)
+ bdevsw[i] = NULL;
+ if (j < max_cdevsws )
+ cdevsw[j] = NULL;
+
+ s = pserialize_read_enter();
+ if (i < max_bdevsws && bdev->d_localcount != NULL) {
localcount_drain(bdev->d_localcount, &device_cv, &device_lock);
localcount_fini(bdev->d_localcount);
- bdevsw[i] = NULL;
}
- if (j < max_cdevsws ) {
- /*
- * Take care not to drain/fini the d_localcount if the same
- * one was used for both cdev and bdev!
- */
- if (i >= max_bdevsws ||
- bdev->d_localcount != cdev->d_localcount) {
- localcount_drain(cdev->d_localcount, &device_cv,
- &device_lock);
- localcount_fini(cdev->d_localcount);
- }
- cdevsw[j] = NULL;
+ if (j < max_cdevsws && cdev->d_localcount != NULL ) {
+ localcount_drain(cdev->d_localcount, &device_cv, &device_lock);
+ localcount_fini(cdev->d_localcount);
}
+ pserialize_read_exit(s);
}
int
@@ -423,6 +435,8 @@
bdevsw_lookup_acquire(dev_t dev)
{
devmajor_t bmajor;
+ const struct bdevsw *bdev = NULL;
+ int s;
if (dev == NODEV)
return (NULL);
@@ -430,20 +444,35 @@
if (bmajor < 0 || bmajor >= max_bdevsws)
return (NULL);
+ /* Prevent any concurrent attempts to detach the device */
+ mutex_enter(&device_lock);
+
+ /* Start a read transaction to block localcount_drain() */
+ s = pserialize_read_enter();
+
+ /* Get the struct bdevsw pointer */
+ bdev = bdevsw[bmajor];
+ if (bdev == NULL)
+ goto out;
+
+ /* Wait for the content of the struct bdevsw to become visible */
+ membar_datadep_consumer();
+
+ /* If the devsw is not statically linked, acquire a reference */
if (bdevsw[bmajor]->d_localcount != NULL)
localcount_acquire(bdevsw[bmajor]->d_localcount);
- return (bdevsw[bmajor]);
+out: pserialize_read_exit(s);
+ mutex_exit(&device_lock);
+
+ return bdev;
}
void
bdevsw_release(const struct bdevsw *bd)
{
- devmajor_t bmaj;
- bmaj = bdevsw_lookup_major(bd);
-
- KASSERTMSG(bmaj != NODEVMAJOR, "%s: no bmajor to release!", __func__);
+ KASSERT(bd != NULL);
if (bd->d_localcount != NULL)
localcount_release(bd->d_localcount, &device_cv, &device_lock);
}
@@ -471,6 +500,8 @@
cdevsw_lookup_acquire(dev_t dev)
{
devmajor_t cmajor;
+ const struct cdevsw *cdev = NULL;
+ int s;
if (dev == NODEV)
return (NULL);
@@ -478,20 +509,35 @@
if (cmajor < 0 || cmajor >= max_cdevsws)
return (NULL);
+ /* Prevent any concurrent attempts to detach the device */
+ mutex_enter(&device_lock);
+
+ /* Start a read transaction to block localcount_drain() */
+ s = pserialize_read_enter();
+
+ /* Get the struct bdevsw pointer */
+ cdev = cdevsw[cmajor];
+ if (cdev == NULL)
+ goto out;
+
+ /* Wait for the content of the struct bdevsw to become visible */
+ membar_datadep_consumer();
+
+ /* If the devsw is not statically linked, acquire a reference */
if (cdevsw[cmajor]->d_localcount != NULL)
localcount_acquire(cdevsw[cmajor]->d_localcount);
- return (cdevsw[cmajor]);
+out: pserialize_read_exit(s);
+ mutex_exit(&device_lock);
+
+ return cdev;
}
void
cdevsw_release(const struct cdevsw *cd)
{
- devmajor_t cmaj;
- cmaj = cdevsw_lookup_major(cd);
-
- KASSERTMSG(cmaj != NODEVMAJOR, "%s: no cmajor to release!", __func__);
+ KASSERT(cd != NULL);
if (cd->d_localcount != NULL)
localcount_release(cd->d_localcount, &device_cv, &device_lock);
}
Home |
Main Index |
Thread Index |
Old Index