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
This commit is contained in:
Konstantin Belousov 2013-03-27 11:47:52 +00:00
parent d1e99f43ed
commit f3215a60fd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=248794

View File

@ -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 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
aiocbe->bp = NULL;
AIO_UNLOCK(ki);
relpbuf(bp, NULL);
unref:
dev_relthread(dev, ref);
return (error);
}