physio: deal with unaligned buffers/small maxphys/overlapped buffers.
fix PR/32224 from Matthias Scheler. (uvm_vslock needs to be redesigned for threaded applications. but it's a different problem.)
This commit is contained in:
parent
24c43e28bb
commit
0a40fe5a5e
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: kern_physio.c,v 1.67 2005/12/04 23:34:00 yamt Exp $ */
|
/* $NetBSD: kern_physio.c,v 1.68 2005/12/13 12:29:32 yamt Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1982, 1986, 1990, 1993
|
* Copyright (c) 1982, 1986, 1990, 1993
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: kern_physio.c,v 1.67 2005/12/04 23:34:00 yamt Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: kern_physio.c,v 1.68 2005/12/13 12:29:32 yamt Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
|
@ -255,7 +255,6 @@ physio(void (*strategy)(struct buf *), struct buf *obp, dev_t dev, int flags,
|
||||||
int i, s;
|
int i, s;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int error2;
|
int error2;
|
||||||
size_t todo;
|
|
||||||
struct buf *bp = NULL;
|
struct buf *bp = NULL;
|
||||||
struct buf *mbp;
|
struct buf *mbp;
|
||||||
int concurrency = PHYSIO_CONCURRENCY - 1;
|
int concurrency = PHYSIO_CONCURRENCY - 1;
|
||||||
|
@ -295,14 +294,19 @@ physio(void (*strategy)(struct buf *), struct buf *obp, dev_t dev, int flags,
|
||||||
PHOLD(l);
|
PHOLD(l);
|
||||||
|
|
||||||
for (i = 0; i < uio->uio_iovcnt; i++) {
|
for (i = 0; i < uio->uio_iovcnt; i++) {
|
||||||
|
boolean_t sync = TRUE;
|
||||||
|
|
||||||
iovp = &uio->uio_iov[i];
|
iovp = &uio->uio_iov[i];
|
||||||
while (iovp->iov_len > 0) {
|
while (iovp->iov_len > 0) {
|
||||||
|
size_t todo;
|
||||||
|
|
||||||
simple_lock(&mbp->b_interlock);
|
simple_lock(&mbp->b_interlock);
|
||||||
if ((mbp->b_flags & B_ERROR) != 0) {
|
if ((mbp->b_flags & B_ERROR) != 0) {
|
||||||
error = mbp->b_error;
|
error = mbp->b_error;
|
||||||
goto done_locked;
|
goto done_locked;
|
||||||
}
|
}
|
||||||
error = physio_wait(mbp, concurrency, "physio1");
|
error = physio_wait(mbp, sync ? 0 : concurrency,
|
||||||
|
"physio1");
|
||||||
if (error) {
|
if (error) {
|
||||||
goto done_locked;
|
goto done_locked;
|
||||||
}
|
}
|
||||||
|
@ -347,13 +351,37 @@ physio(void (*strategy)(struct buf *), struct buf *obp, dev_t dev, int flags,
|
||||||
* for later comparison.
|
* for later comparison.
|
||||||
*/
|
*/
|
||||||
(*min_phys)(bp);
|
(*min_phys)(bp);
|
||||||
todo = bp->b_bufsize = bp->b_bcount;
|
|
||||||
#if defined(DIAGNOSTIC)
|
#if defined(DIAGNOSTIC)
|
||||||
if (todo > MAXPHYS)
|
if (bp->b_bcount > MAXPHYS)
|
||||||
panic("todo(%zu) > MAXPHYS; minphys broken",
|
panic("todo(%zu) > MAXPHYS; minphys broken",
|
||||||
todo);
|
bp->b_bcount);
|
||||||
#endif /* defined(DIAGNOSTIC) */
|
#endif /* defined(DIAGNOSTIC) */
|
||||||
|
|
||||||
|
sync = FALSE;
|
||||||
|
if (bp->b_bcount != iovp->iov_len) {
|
||||||
|
vaddr_t endp =
|
||||||
|
(vaddr_t)bp->b_data + bp->b_bcount;
|
||||||
|
vaddr_t alignedendp = trunc_page(endp);
|
||||||
|
|
||||||
|
if (alignedendp != endp) {
|
||||||
|
if (alignedendp > (vaddr_t)bp->b_data) {
|
||||||
|
bp->b_bcount = alignedendp -
|
||||||
|
(vaddr_t)bp->b_data;
|
||||||
|
} else {
|
||||||
|
simple_lock(&mbp->b_interlock);
|
||||||
|
error = physio_wait(mbp, 0,
|
||||||
|
"physio3");
|
||||||
|
if (error) {
|
||||||
|
goto done_locked;
|
||||||
|
}
|
||||||
|
simple_unlock(
|
||||||
|
&mbp->b_interlock);
|
||||||
|
sync = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
todo = bp->b_bufsize = bp->b_bcount;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [lock the part of the user address space involved
|
* [lock the part of the user address space involved
|
||||||
* in the transfer]
|
* in the transfer]
|
||||||
|
|
Loading…
Reference in New Issue