Author: kib
Date: Wed Mar 27 11:47:52 2013
New Revision: 248794
URL: http://svnweb.freebsd.org/changeset/base/248794

Log:
  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

Modified:
  head/sys/kern/vfs_aio.c

Modified: head/sys/kern/vfs_aio.c
==============================================================================
--- head/sys/kern/vfs_aio.c     Wed Mar 27 11:42:36 2013        (r248793)
+++ head/sys/kern/vfs_aio.c     Wed Mar 27 11:47:52 2013        (r248794)
@@ -1252,9 +1252,11 @@ aio_qphysio(struct proc *p, struct aiocb
        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 aiocb
        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 aiocb
        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 aiocb
        /*
         * 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 aiocb
        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);
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to