summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_aio.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-03-27 11:47:52 +0000
committerkib <kib@FreeBSD.org>2013-03-27 11:47:52 +0000
commitc45e5da903f8140c2f15402b2424837677b648aa (patch)
treef96042ef528289a58a359ca052c0dab4f7c6e940 /sys/kern/vfs_aio.c
parent448e7c12908c8a8680ec5f93934de43b8ad1a06f (diff)
downloadFreeBSD-src-c45e5da903f8140c2f15402b2424837677b648aa.zip
FreeBSD-src-c45e5da903f8140c2f15402b2424837677b648aa.tar.gz
Fix a race with the vnode reclamation in the aio_qphysio(). Obtain
the thread reference on the vp->v_rdev and use the returned struct cdev *dev instead of using vp->v_rdev. Call dev_strategy_csw() instead of dev_strategy(), since we now own the reference. Since the csw was already calculated, test d_flags to avoid mapping the buffer if the driver supports unmapped requests [*]. Suggested by: kan [*] Reviewed by: kan (previous version) Sponsored by: The FreeBSD Foundation MFC after: 2 weeks
Diffstat (limited to 'sys/kern/vfs_aio.c')
-rw-r--r--sys/kern/vfs_aio.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index 4facd97..3ef1085 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -1252,9 +1252,11 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
struct file *fp;
struct buf *bp;
struct vnode *vp;
+ struct cdevsw *csw;
+ struct cdev *dev;
struct kaioinfo *ki;
struct aioliojob *lj;
- int error;
+ int error, ref;
cb = &aiocbe->uaiocb;
fp = aiocbe->fd_file;
@@ -1282,9 +1284,6 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
if (cb->aio_nbytes % vp->v_bufobj.bo_bsize)
return (-1);
- if (cb->aio_nbytes > vp->v_rdev->si_iosize_max)
- return (-1);
-
if (cb->aio_nbytes >
MAXPHYS - (((vm_offset_t) cb->aio_buf) & PAGE_MASK))
return (-1);
@@ -1293,6 +1292,15 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
if (ki->kaio_buffer_count >= ki->kaio_ballowed_count)
return (-1);
+ ref = 0;
+ csw = devvn_refthread(vp, &dev, &ref);
+ if (csw == NULL)
+ return (ENXIO);
+ if (cb->aio_nbytes > dev->si_iosize_max) {
+ error = -1;
+ goto unref;
+ }
+
/* Create and build a buffer header for a transfer. */
bp = (struct buf *)getpbuf(NULL);
BUF_KERNPROC(bp);
@@ -1323,7 +1331,7 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
/*
* Bring buffer into kernel space.
*/
- if (vmapbuf(bp, 1) < 0) {
+ if (vmapbuf(bp, (csw->d_flags & D_UNMAPPED_IO) == 0) < 0) {
error = EFAULT;
goto doerror;
}
@@ -1345,7 +1353,8 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
TASK_INIT(&aiocbe->biotask, 0, biohelper, aiocbe);
/* Perform transfer. */
- dev_strategy(vp->v_rdev, bp);
+ dev_strategy_csw(dev, csw, bp);
+ dev_relthread(dev, ref);
return (0);
doerror:
@@ -1357,6 +1366,8 @@ doerror:
aiocbe->bp = NULL;
AIO_UNLOCK(ki);
relpbuf(bp, NULL);
+unref:
+ dev_relthread(dev, ref);
return (error);
}
OpenPOWER on IntegriCloud