summaryrefslogtreecommitdiffstats
path: root/sys/dev/md/md.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-12-26 11:10:44 +0000
committerkib <kib@FreeBSD.org>2015-12-26 11:10:44 +0000
commit4091b74ce580d723c5bba13614d55ce3bbcbeef0 (patch)
tree80d7ab718754c828a2f0bf04d533c5480a00fb06 /sys/dev/md/md.c
parent55621219f54a49a3877e8da2ae39078ed442909f (diff)
downloadFreeBSD-src-4091b74ce580d723c5bba13614d55ce3bbcbeef0.zip
FreeBSD-src-4091b74ce580d723c5bba13614d55ce3bbcbeef0.tar.gz
MFC r292128:
In md(4) over vnode, correct handling of the unaligned unmapped io requests which page alignment + size is greater than MAXPHYS. Split request up to the size of io which fits into pbuf KVA with alignment, and retry if a part of the bio is left unprocessed.
Diffstat (limited to 'sys/dev/md/md.c')
-rw-r--r--sys/dev/md/md.c40
1 files changed, 27 insertions, 13 deletions
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 27ef8b3..693f000 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -825,8 +825,8 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
struct buf *pb;
bus_dma_segment_t *vlist;
struct thread *td;
- off_t len, zerosize;
- int ma_offs;
+ off_t iolen, len, zerosize;
+ int ma_offs, npages;
switch (bp->bio_cmd) {
case BIO_READ:
@@ -847,6 +847,7 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
pb = NULL;
piov = NULL;
ma_offs = bp->bio_ma_offset;
+ len = bp->bio_length;
/*
* VNODE I/O
@@ -879,7 +880,6 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
auio.uio_iovcnt = howmany(bp->bio_length, zerosize);
piov = malloc(sizeof(*piov) * auio.uio_iovcnt, M_MD, M_WAITOK);
auio.uio_iov = piov;
- len = bp->bio_length;
while (len > 0) {
piov->iov_base = __DECONST(void *, zero_region);
piov->iov_len = len;
@@ -893,7 +893,6 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
piov = malloc(sizeof(*piov) * bp->bio_ma_n, M_MD, M_WAITOK);
auio.uio_iov = piov;
vlist = (bus_dma_segment_t *)bp->bio_data;
- len = bp->bio_length;
while (len > 0) {
piov->iov_base = (void *)(uintptr_t)(vlist->ds_addr +
ma_offs);
@@ -909,11 +908,20 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
piov = auio.uio_iov;
} else if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
pb = getpbuf(&md_vnode_pbuf_freecnt);
- pmap_qenter((vm_offset_t)pb->b_data, bp->bio_ma, bp->bio_ma_n);
- aiov.iov_base = (void *)((vm_offset_t)pb->b_data + ma_offs);
- aiov.iov_len = bp->bio_length;
+ bp->bio_resid = len;
+unmapped_step:
+ npages = atop(min(MAXPHYS, round_page(len + (ma_offs &
+ PAGE_MASK))));
+ iolen = min(ptoa(npages) - (ma_offs & PAGE_MASK), len);
+ KASSERT(iolen > 0, ("zero iolen"));
+ pmap_qenter((vm_offset_t)pb->b_data,
+ &bp->bio_ma[atop(ma_offs)], npages);
+ aiov.iov_base = (void *)((vm_offset_t)pb->b_data +
+ (ma_offs & PAGE_MASK));
+ aiov.iov_len = iolen;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
+ auio.uio_resid = iolen;
} else {
aiov.iov_base = bp->bio_data;
aiov.iov_len = bp->bio_length;
@@ -937,15 +945,21 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
vn_finished_write(mp);
}
- if (pb) {
- pmap_qremove((vm_offset_t)pb->b_data, bp->bio_ma_n);
+ if (pb != NULL) {
+ pmap_qremove((vm_offset_t)pb->b_data, npages);
+ if (error == 0) {
+ len -= iolen;
+ bp->bio_resid -= iolen;
+ ma_offs += iolen;
+ if (len > 0)
+ goto unmapped_step;
+ }
relpbuf(pb, &md_vnode_pbuf_freecnt);
}
- if (piov != NULL)
- free(piov, M_MD);
-
- bp->bio_resid = auio.uio_resid;
+ free(piov, M_MD);
+ if (pb == NULL)
+ bp->bio_resid = auio.uio_resid;
return (error);
}
OpenPOWER on IntegriCloud