1 /*- 2 * Copyright (c) 1994 John S. Dyson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice immediately at the beginning of the file, without modification, 10 * this list of conditions, and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Absolutely no warranty of function or purpose is made by the author 15 * John S. Dyson. 16 * 4. Modifications may be freely made to this file if the above conditions 17 * are met. 18 */ 19 20 #include <sys/cdefs.h> 21 __FBSDID("$FreeBSD$"); 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/bio.h> 26 #include <sys/buf.h> 27 #include <sys/conf.h> 28 #include <sys/malloc.h> 29 #include <sys/proc.h> 30 #include <sys/uio.h> 31 #include <geom/geom.h> 32 33 #include <vm/vm.h> 34 #include <vm/vm_page.h> 35 #include <vm/vm_extern.h> 36 #include <vm/vm_map.h> 37 38 int 39 physio(struct cdev *dev, struct uio *uio, int ioflag) 40 { 41 struct buf *pbuf; 42 struct bio *bp; 43 struct vm_page **pages; 44 caddr_t sa; 45 u_int iolen, poff; 46 int error, i, npages, maxpages; 47 vm_prot_t prot; 48 49 /* XXX: sanity check */ 50 if(dev->si_iosize_max < PAGE_SIZE) { 51 printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n", 52 devtoname(dev), dev->si_iosize_max); 53 dev->si_iosize_max = DFLTPHYS; 54 } 55 56 /* 57 * If the driver does not want I/O to be split, that means that we 58 * need to reject any requests that will not fit into one buffer. 59 */ 60 if (dev->si_flags & SI_NOSPLIT && 61 (uio->uio_resid > dev->si_iosize_max || uio->uio_resid > MAXPHYS || 62 uio->uio_iovcnt > 1)) { 63 /* 64 * Tell the user why his I/O was rejected. 65 */ 66 if (uio->uio_resid > dev->si_iosize_max) 67 uprintf("%s: request size=%zd > si_iosize_max=%d; " 68 "cannot split request\n", devtoname(dev), 69 uio->uio_resid, dev->si_iosize_max); 70 if (uio->uio_resid > MAXPHYS) 71 uprintf("%s: request size=%zd > MAXPHYS=%d; " 72 "cannot split request\n", devtoname(dev), 73 uio->uio_resid, MAXPHYS); 74 if (uio->uio_iovcnt > 1) 75 uprintf("%s: request vectors=%d > 1; " 76 "cannot split request\n", devtoname(dev), 77 uio->uio_iovcnt); 78 return (EFBIG); 79 } 80 81 /* 82 * Keep the process UPAGES from being swapped. Processes swapped 83 * out while holding pbufs, used by swapper, may lead to deadlock. 84 */ 85 PHOLD(curproc); 86 87 bp = g_alloc_bio(); 88 if (uio->uio_segflg != UIO_USERSPACE) { 89 pbuf = NULL; 90 pages = NULL; 91 } else if ((dev->si_flags & SI_UNMAPPED) && unmapped_buf_allowed) { 92 pbuf = NULL; 93 maxpages = btoc(MIN(uio->uio_resid, MAXPHYS)) + 1; 94 pages = malloc(sizeof(*pages) * maxpages, M_DEVBUF, M_WAITOK); 95 } else { 96 pbuf = getpbuf(NULL); 97 sa = pbuf->b_data; 98 maxpages = btoc(MAXPHYS); 99 pages = pbuf->b_pages; 100 } 101 prot = VM_PROT_READ; 102 if (uio->uio_rw == UIO_READ) 103 prot |= VM_PROT_WRITE; /* Less backwards than it looks */ 104 error = 0; 105 for (i = 0; i < uio->uio_iovcnt; i++) { 106 while (uio->uio_iov[i].iov_len) { 107 bzero(bp, sizeof(*bp)); 108 if (uio->uio_rw == UIO_READ) { 109 bp->bio_cmd = BIO_READ; 110 curthread->td_ru.ru_inblock++; 111 } else { 112 bp->bio_cmd = BIO_WRITE; 113 curthread->td_ru.ru_oublock++; 114 } 115 bp->bio_offset = uio->uio_offset; 116 bp->bio_data = uio->uio_iov[i].iov_base; 117 bp->bio_length = uio->uio_iov[i].iov_len; 118 if (bp->bio_length > dev->si_iosize_max) 119 bp->bio_length = dev->si_iosize_max; 120 if (bp->bio_length > MAXPHYS) 121 bp->bio_length = MAXPHYS; 122 123 /* 124 * Make sure the pbuf can map the request. 125 * The pbuf has kvasize = MAXPHYS, so a request 126 * larger than MAXPHYS - PAGE_SIZE must be 127 * page aligned or it will be fragmented. 128 */ 129 poff = (vm_offset_t)bp->bio_data & PAGE_MASK; 130 if (pbuf && bp->bio_length + poff > pbuf->b_kvasize) { 131 if (dev->si_flags & SI_NOSPLIT) { 132 uprintf("%s: request ptr %p is not " 133 "on a page boundary; cannot split " 134 "request\n", devtoname(dev), 135 bp->bio_data); 136 error = EFBIG; 137 goto doerror; 138 } 139 bp->bio_length = pbuf->b_kvasize; 140 if (poff != 0) 141 bp->bio_length -= PAGE_SIZE; 142 } 143 144 bp->bio_bcount = bp->bio_length; 145 bp->bio_dev = dev; 146 147 if (pages) { 148 if ((npages = vm_fault_quick_hold_pages( 149 &curproc->p_vmspace->vm_map, 150 (vm_offset_t)bp->bio_data, bp->bio_length, 151 prot, pages, maxpages)) < 0) { 152 error = EFAULT; 153 goto doerror; 154 } 155 if (pbuf) { 156 pmap_qenter((vm_offset_t)sa, 157 pages, npages); 158 bp->bio_data = sa + poff; 159 } else { 160 bp->bio_ma = pages; 161 bp->bio_ma_n = npages; 162 bp->bio_ma_offset = poff; 163 bp->bio_data = unmapped_buf; 164 bp->bio_flags |= BIO_UNMAPPED; 165 } 166 } 167 168 dev->si_devsw->d_strategy(bp); 169 if (uio->uio_rw == UIO_READ) 170 biowait(bp, "physrd"); 171 else 172 biowait(bp, "physwr"); 173 174 if (pages) { 175 if (pbuf) 176 pmap_qremove((vm_offset_t)sa, npages); 177 vm_page_unhold_pages(pages, npages); 178 } 179 180 iolen = bp->bio_length - bp->bio_resid; 181 if (iolen == 0 && !(bp->bio_flags & BIO_ERROR)) 182 goto doerror; /* EOF */ 183 uio->uio_iov[i].iov_len -= iolen; 184 uio->uio_iov[i].iov_base = 185 (char *)uio->uio_iov[i].iov_base + iolen; 186 uio->uio_resid -= iolen; 187 uio->uio_offset += iolen; 188 if (bp->bio_flags & BIO_ERROR) { 189 error = bp->bio_error; 190 goto doerror; 191 } 192 } 193 } 194 doerror: 195 if (pbuf) 196 relpbuf(pbuf, NULL); 197 else if (pages) 198 free(pages, M_DEVBUF); 199 g_destroy_bio(bp); 200 PRELE(curproc); 201 return (error); 202 } 203