summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2013-03-26 01:17:06 +0000
committerkan <kan@FreeBSD.org>2013-03-26 01:17:06 +0000
commit49a21b7c2ed9406dd08968495779c6ccfb4a58a5 (patch)
tree97acd52c556902a1cf5531fa13b5cc13c206e064
parent5304ecc65d409e90546f56cdb991b203f74e8d38 (diff)
downloadFreeBSD-src-49a21b7c2ed9406dd08968495779c6ccfb4a58a5.zip
FreeBSD-src-49a21b7c2ed9406dd08968495779c6ccfb4a58a5.tar.gz
Do not pass unmapped buffers to drivers that cannot handle them
In physio, check if device can handle unmapped IO and pass an appropriately mapped buffer to the driver strategy routine. The only driver in the tree that can handle unmapped buffers is one exposed by GEOM, so mark it as such with the new flag in the driver cdevsw structure. This fixes insta-panics on hosts, running dconschat, as /dev/fwmem is an example of the driver that makes use of physio routine, but bypasses the g_down thread, where the buffer gets mapped normally. Discussed with: kib (earlier version)
-rw-r--r--sys/geom/geom_dev.c2
-rw-r--r--sys/kern/kern_physio.c14
-rw-r--r--sys/sys/conf.h1
3 files changed, 14 insertions, 3 deletions
diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c
index 0a74ee1..81dfd9f 100644
--- a/sys/geom/geom_dev.c
+++ b/sys/geom/geom_dev.c
@@ -78,7 +78,7 @@ static struct cdevsw g_dev_cdevsw = {
.d_ioctl = g_dev_ioctl,
.d_strategy = g_dev_strategy,
.d_name = "g_dev",
- .d_flags = D_DISK | D_TRACKCLOSE,
+ .d_flags = D_DISK | D_TRACKCLOSE | D_UNMAPPED_IO,
};
static g_taste_t g_dev_taste;
diff --git a/sys/kern/kern_physio.c b/sys/kern/kern_physio.c
index 922ebb6..1eb5b8f 100644
--- a/sys/kern/kern_physio.c
+++ b/sys/kern/kern_physio.c
@@ -91,11 +91,21 @@ physio(struct cdev *dev, struct uio *uio, int ioflag)
bp->b_blkno = btodb(bp->b_offset);
- if (uio->uio_segflg == UIO_USERSPACE)
- if (vmapbuf(bp, 0) < 0) {
+ if (uio->uio_segflg == UIO_USERSPACE) {
+ struct cdevsw *csw;
+ int mapped;
+
+ csw = dev->si_devsw;
+ if (csw != NULL &&
+ (csw->d_flags & D_UNMAPPED_IO) != 0)
+ mapped = 0;
+ else
+ mapped = 1;
+ if (vmapbuf(bp, mapped) < 0) {
error = EFAULT;
goto doerror;
}
+ }
dev_strategy(dev, bp);
if (uio->uio_rw == UIO_READ)
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index e818722..8d53839 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -167,6 +167,7 @@ typedef int dumper_t(
#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */
#define D_NEEDGIANT 0x00400000 /* driver want Giant */
#define D_NEEDMINOR 0x00800000 /* driver uses clone_create() */
+#define D_UNMAPPED_IO 0x01000000 /* d_strategy can accept unmapped IO */
/*
* Version numbers.
OpenPOWER on IntegriCloud