| 205 | } |
| 206 | |
| 207 | int |
| 208 | proc_rwmem(struct proc *p, struct uio *uio) |
| 209 | { |
| 210 | vm_map_t map; |
| 211 | vm_offset_t pageno; /* page number */ |
| 212 | vm_prot_t reqprot; |
| 213 | int error, fault_flags, page_offset, writing; |
| 214 | |
| 215 | /* |
| 216 | * Assert that someone has locked this vmspace. (Should be |
| 217 | * curthread but we can't assert that.) This keeps the process |
| 218 | * from exiting out from under us until this operation completes. |
| 219 | */ |
| 220 | PROC_ASSERT_HELD(p); |
| 221 | PROC_LOCK_ASSERT(p, MA_NOTOWNED); |
| 222 | |
| 223 | /* |
| 224 | * The map we want... |
| 225 | */ |
| 226 | map = &p->p_vmspace->vm_map; |
| 227 | |
| 228 | /* |
| 229 | * If we are writing, then we request vm_fault() to create a private |
| 230 | * copy of each page. Since these copies will not be writeable by the |
| 231 | * process, we must explicity request that they be dirtied. |
| 232 | */ |
| 233 | writing = uio->uio_rw == UIO_WRITE; |
| 234 | reqprot = writing ? VM_PROT_COPY | VM_PROT_READ : VM_PROT_READ; |
| 235 | fault_flags = writing ? VM_FAULT_DIRTY : VM_FAULT_NORMAL; |
| 236 | |
| 237 | /* |
| 238 | * Only map in one page at a time. We don't have to, but it |
| 239 | * makes things easier. This way is trivial - right? |
| 240 | */ |
| 241 | do { |
| 242 | vm_offset_t uva; |
| 243 | u_int len; |
| 244 | vm_page_t m; |
| 245 | |
| 246 | uva = (vm_offset_t)uio->uio_offset; |
| 247 | |
| 248 | /* |
| 249 | * Get the page number of this segment. |
| 250 | */ |
| 251 | pageno = trunc_page(uva); |
| 252 | page_offset = uva - pageno; |
| 253 | |
| 254 | /* |
| 255 | * How many bytes to copy |
| 256 | */ |
| 257 | len = min(PAGE_SIZE - page_offset, uio->uio_resid); |
| 258 | |
| 259 | /* |
| 260 | * Fault and hold the page on behalf of the process. |
| 261 | */ |
| 262 | error = vm_fault(map, pageno, reqprot, fault_flags, &m); |
| 263 | if (error != KERN_SUCCESS) { |
| 264 | if (error == KERN_RESOURCE_SHORTAGE) |
no test coverage detected