diff options
Diffstat (limited to 'sys/kern/kern_physio.c')
-rw-r--r-- | sys/kern/kern_physio.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/sys/kern/kern_physio.c b/sys/kern/kern_physio.c index ab9c344..88cd0cf 100644 --- a/sys/kern/kern_physio.c +++ b/sys/kern/kern_physio.c @@ -54,6 +54,36 @@ physio(struct cdev *dev, struct uio *uio, int ioflag) dev->si_iosize_max = DFLTPHYS; } + /* + * If the driver does not want I/O to be split, that means that we + * need to reject any requests that will not fit into one buffer. + */ + if ((dev->si_flags & SI_NOSPLIT) && + ((uio->uio_resid > dev->si_iosize_max) || + (uio->uio_resid > MAXPHYS) || + (uio->uio_iovcnt > 1))) { + /* + * Tell the user why his I/O was rejected. + */ + if (uio->uio_resid > dev->si_iosize_max) + printf("%s: request size %zd > si_iosize_max=%d, " + "cannot split request\n", devtoname(dev), + uio->uio_resid, dev->si_iosize_max); + + if (uio->uio_resid > MAXPHYS) + printf("%s: request size %zd > MAXPHYS=%d, " + "cannot split request\n", devtoname(dev), + uio->uio_resid, MAXPHYS); + + if (uio->uio_iovcnt > 1) + printf("%s: request vectors=%d > 1, " + "cannot split request\n", devtoname(dev), + uio->uio_iovcnt); + + error = EFBIG; + goto doerror; + } + for (i = 0; i < uio->uio_iovcnt; i++) { while (uio->uio_iov[i].iov_len) { bp->b_flags = 0; @@ -83,6 +113,17 @@ physio(struct cdev *dev, struct uio *uio, int ioflag) */ iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK; if ((bp->b_bcount + iolen) > bp->b_kvasize) { + /* + * This device does not want I/O to be split. + */ + if (dev->si_flags & SI_NOSPLIT) { + printf("%s: request ptr %#jx is not " + "on a page boundary, cannot split " + "request\n", devtoname(dev), + (uintmax_t)bp->b_data); + error = EFBIG; + goto doerror; + } bp->b_bcount = bp->b_kvasize; if (iolen != 0) bp->b_bcount -= PAGE_SIZE; |