int physio(int (*strat)(struct buf *), struct buf *bp, dev_t dev, int rw, void (*mincnt)(struct buf *), struct uio *uio) { return (default_physio(strat, bp, dev, rw, mincnt, uio)); }
/* * Wrapper for the physio() function. * Splits one uio operation with multiple iovecs into uio operations with * only one iovecs to do the watchpoint handling separately for each iovecs. */ static int watch_physio(int (*strat)(struct buf *), struct buf *bp, dev_t dev, int rw, void (*mincnt)(struct buf *), struct uio *uio) { struct uio auio; struct iovec *iov; caddr_t base; size_t len; int seg_rw; int error = 0; if (uio->uio_segflg == UIO_SYSSPACE) return (default_physio(strat, bp, dev, rw, mincnt, uio)); seg_rw = (rw == B_READ) ? S_WRITE : S_READ; while (uio->uio_iovcnt > 0) { if (uio->uio_resid == 0) { /* * Make sure to return the uio structure with the * same values as default_physio() does. */ uio->uio_iov++; uio->uio_iovcnt--; continue; } iov = uio->uio_iov; len = MIN(iov->iov_len, uio->uio_resid); auio.uio_iovcnt = 1; auio.uio_iov = iov; auio.uio_resid = len; auio.uio_loffset = uio->uio_loffset; auio.uio_llimit = uio->uio_llimit; auio.uio_fmode = uio->uio_fmode; auio.uio_extflg = uio->uio_extflg; auio.uio_segflg = uio->uio_segflg; base = iov->iov_base; if (!pr_is_watched(base, len, seg_rw)) { /* * The given memory references don't cover a * watched page. */ error = default_physio(strat, bp, dev, rw, mincnt, &auio); /* Update uio with values from auio. */ len -= auio.uio_resid; uio->uio_resid -= len; uio->uio_loffset += len; /* * Return if an error occurred or not all data * was copied. */ if (auio.uio_resid || error) break; uio->uio_iov++; uio->uio_iovcnt--; } else { int mapped, watchcode, ta; caddr_t vaddr = base; klwp_t *lwp = ttolwp(curthread); watchcode = pr_is_watchpoint(&vaddr, &ta, len, NULL, seg_rw); if (watchcode == 0 || ta != 0) { /* * Do the io if the given memory references * don't cover a watched area (watchcode=0) * or if WA_TRAPAFTER was specified. */ mapped = pr_mappage(base, len, seg_rw, 1); error = default_physio(strat, bp, dev, rw, mincnt, &auio); if (mapped) pr_unmappage(base, len, seg_rw, 1); len -= auio.uio_resid; uio->uio_resid -= len; uio->uio_loffset += len; } /* * If we hit a watched address, do the watchpoint logic. */ if (watchcode && (!sys_watchpoint(vaddr, watchcode, ta) || lwp->lwp_sysabort)) { lwp->lwp_sysabort = 0; return (EFAULT); } /* * Check for errors from default_physio(). */ if (watchcode == 0 || ta != 0) { if (auio.uio_resid || error) break; uio->uio_iov++; uio->uio_iovcnt--; } } } return (error); }