From 0a40fe5a5e2e58e8ae34ddb021b5fb8c8b469d9b Mon Sep 17 00:00:00 2001 From: yamt Date: Tue, 13 Dec 2005 12:29:32 +0000 Subject: [PATCH] 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.) --- sys/kern/kern_physio.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/sys/kern/kern_physio.c b/sys/kern/kern_physio.c index 5fb49d6dbf0b..44f645934366 100644 --- a/sys/kern/kern_physio.c +++ b/sys/kern/kern_physio.c @@ -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 @@ -71,7 +71,7 @@ */ #include -__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 #include @@ -255,7 +255,6 @@ physio(void (*strategy)(struct buf *), struct buf *obp, dev_t dev, int flags, int i, s; int error = 0; int error2; - size_t todo; struct buf *bp = NULL; struct buf *mbp; int concurrency = PHYSIO_CONCURRENCY - 1; @@ -295,14 +294,19 @@ physio(void (*strategy)(struct buf *), struct buf *obp, dev_t dev, int flags, PHOLD(l); for (i = 0; i < uio->uio_iovcnt; i++) { + boolean_t sync = TRUE; + iovp = &uio->uio_iov[i]; while (iovp->iov_len > 0) { + size_t todo; + simple_lock(&mbp->b_interlock); if ((mbp->b_flags & B_ERROR) != 0) { error = mbp->b_error; goto done_locked; } - error = physio_wait(mbp, concurrency, "physio1"); + error = physio_wait(mbp, sync ? 0 : concurrency, + "physio1"); if (error) { goto done_locked; } @@ -347,13 +351,37 @@ physio(void (*strategy)(struct buf *), struct buf *obp, dev_t dev, int flags, * for later comparison. */ (*min_phys)(bp); - todo = bp->b_bufsize = bp->b_bcount; #if defined(DIAGNOSTIC) - if (todo > MAXPHYS) + if (bp->b_bcount > MAXPHYS) panic("todo(%zu) > MAXPHYS; minphys broken", - todo); + bp->b_bcount); #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 * in the transfer]