1 /* 2 * Copyright (c) 1990 University of Utah. 3 * Copyright (c) 1991 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)vnode_pager.c 7.12 (Berkeley) 07/08/92 13 */ 14 15 /* 16 * Page to/from files (vnodes). 17 * 18 * TODO: 19 * pageouts 20 * fix credential use (uses current process credentials now) 21 */ 22 #include "vnodepager.h" 23 #if NVNODEPAGER > 0 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 #include <sys/proc.h> 28 #include <sys/malloc.h> 29 #include <sys/vnode.h> 30 #include <sys/uio.h> 31 #include <sys/mount.h> 32 33 #include <vm/vm.h> 34 #include <vm/vm_page.h> 35 #include <vm/vnode_pager.h> 36 37 queue_head_t vnode_pager_list; /* list of managed vnodes */ 38 39 #ifdef DEBUG 40 int vpagerdebug = 0x00; 41 #define VDB_FOLLOW 0x01 42 #define VDB_INIT 0x02 43 #define VDB_IO 0x04 44 #define VDB_FAIL 0x08 45 #define VDB_ALLOC 0x10 46 #define VDB_SIZE 0x20 47 #endif 48 49 static vm_pager_t vnode_pager_alloc __P((caddr_t, vm_size_t, vm_prot_t)); 50 static void vnode_pager_dealloc __P((vm_pager_t)); 51 static int vnode_pager_getpage 52 __P((vm_pager_t, vm_page_t, boolean_t)); 53 static boolean_t vnode_pager_haspage __P((vm_pager_t, vm_offset_t)); 54 static void vnode_pager_init __P((void)); 55 static int vnode_pager_io 56 __P((vn_pager_t, vm_page_t, enum uio_rw)); 57 static boolean_t vnode_pager_putpage 58 __P((vm_pager_t, vm_page_t, boolean_t)); 59 60 struct pagerops vnodepagerops = { 61 vnode_pager_init, 62 vnode_pager_alloc, 63 vnode_pager_dealloc, 64 vnode_pager_getpage, 65 vnode_pager_putpage, 66 vnode_pager_haspage 67 }; 68 69 static void 70 vnode_pager_init() 71 { 72 #ifdef DEBUG 73 if (vpagerdebug & VDB_FOLLOW) 74 printf("vnode_pager_init()\n"); 75 #endif 76 queue_init(&vnode_pager_list); 77 } 78 79 /* 80 * Allocate (or lookup) pager for a vnode. 81 * Handle is a vnode pointer. 82 */ 83 static vm_pager_t 84 vnode_pager_alloc(handle, size, prot) 85 caddr_t handle; 86 vm_size_t size; 87 vm_prot_t prot; 88 { 89 register vm_pager_t pager; 90 register vn_pager_t vnp; 91 vm_object_t object; 92 struct vattr vattr; 93 struct vnode *vp; 94 struct proc *p = curproc; /* XXX */ 95 96 #ifdef DEBUG 97 if (vpagerdebug & (VDB_FOLLOW|VDB_ALLOC)) 98 printf("vnode_pager_alloc(%x, %x, %x)\n", handle, size, prot); 99 #endif 100 /* 101 * Pageout to vnode, no can do yet. 102 */ 103 if (handle == NULL) 104 return(NULL); 105 106 /* 107 * Vnodes keep a pointer to any associated pager so no need to 108 * lookup with vm_pager_lookup. 109 */ 110 vp = (struct vnode *)handle; 111 pager = (vm_pager_t)vp->v_vmdata; 112 if (pager == NULL) { 113 /* 114 * Allocate pager structures 115 */ 116 pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK); 117 if (pager == NULL) 118 return(NULL); 119 vnp = (vn_pager_t)malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK); 120 if (vnp == NULL) { 121 free((caddr_t)pager, M_VMPAGER); 122 return(NULL); 123 } 124 /* 125 * And an object of the appropriate size 126 */ 127 if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) { 128 object = vm_object_allocate(round_page(vattr.va_size)); 129 vm_object_enter(object, pager); 130 vm_object_setpager(object, pager, 0, TRUE); 131 } else { 132 free((caddr_t)vnp, M_VMPGDATA); 133 free((caddr_t)pager, M_VMPAGER); 134 return(NULL); 135 } 136 /* 137 * Hold a reference to the vnode and initialize pager data. 138 */ 139 VREF(vp); 140 vnp->vnp_flags = 0; 141 vnp->vnp_vp = vp; 142 vnp->vnp_size = vattr.va_size; 143 queue_enter(&vnode_pager_list, pager, vm_pager_t, pg_list); 144 pager->pg_handle = handle; 145 pager->pg_type = PG_VNODE; 146 pager->pg_ops = &vnodepagerops; 147 pager->pg_data = (caddr_t)vnp; 148 vp->v_vmdata = (caddr_t)pager; 149 } else { 150 /* 151 * vm_object_lookup() will remove the object from the 152 * cache if found and also gain a reference to the object. 153 */ 154 object = vm_object_lookup(pager); 155 #ifdef DEBUG 156 vnp = (vn_pager_t)pager->pg_data; 157 #endif 158 } 159 #ifdef DEBUG 160 if (vpagerdebug & VDB_ALLOC) 161 printf("vnode_pager_setup: vp %x sz %x pager %x object %x\n", 162 vp, vnp->vnp_size, pager, object); 163 #endif 164 return(pager); 165 } 166 167 static void 168 vnode_pager_dealloc(pager) 169 vm_pager_t pager; 170 { 171 register vn_pager_t vnp = (vn_pager_t)pager->pg_data; 172 register struct vnode *vp; 173 struct proc *p = curproc; /* XXX */ 174 175 #ifdef DEBUG 176 if (vpagerdebug & VDB_FOLLOW) 177 printf("vnode_pager_dealloc(%x)\n", pager); 178 #endif 179 if (vp = vnp->vnp_vp) { 180 vp->v_vmdata = NULL; 181 vp->v_flag &= ~VTEXT; 182 #if 0 183 /* can hang if done at reboot on NFS FS */ 184 (void) VOP_FSYNC(vp, p->p_ucred, p); 185 #endif 186 vrele(vp); 187 } 188 queue_remove(&vnode_pager_list, pager, vm_pager_t, pg_list); 189 free((caddr_t)vnp, M_VMPGDATA); 190 free((caddr_t)pager, M_VMPAGER); 191 } 192 193 static int 194 vnode_pager_getpage(pager, m, sync) 195 vm_pager_t pager; 196 vm_page_t m; 197 boolean_t sync; 198 { 199 200 #ifdef DEBUG 201 if (vpagerdebug & VDB_FOLLOW) 202 printf("vnode_pager_getpage(%x, %x)\n", pager, m); 203 #endif 204 return(vnode_pager_io((vn_pager_t)pager->pg_data, m, UIO_READ)); 205 } 206 207 static boolean_t 208 vnode_pager_putpage(pager, m, sync) 209 vm_pager_t pager; 210 vm_page_t m; 211 boolean_t sync; 212 { 213 int err; 214 215 #ifdef DEBUG 216 if (vpagerdebug & VDB_FOLLOW) 217 printf("vnode_pager_putpage(%x, %x)\n", pager, m); 218 #endif 219 if (pager == NULL) 220 return (FALSE); /* ??? */ 221 err = vnode_pager_io((vn_pager_t)pager->pg_data, m, UIO_WRITE); 222 if (err == VM_PAGER_OK) { 223 m->clean = TRUE; /* XXX - wrong place */ 224 pmap_clear_modify(VM_PAGE_TO_PHYS(m)); /* XXX - wrong place */ 225 } 226 return(err); 227 } 228 229 static boolean_t 230 vnode_pager_haspage(pager, offset) 231 vm_pager_t pager; 232 vm_offset_t offset; 233 { 234 register vn_pager_t vnp = (vn_pager_t)pager->pg_data; 235 daddr_t bn; 236 int err; 237 238 #ifdef DEBUG 239 if (vpagerdebug & VDB_FOLLOW) 240 printf("vnode_pager_haspage(%x, %x)\n", pager, offset); 241 #endif 242 243 /* 244 * Offset beyond end of file, do not have the page 245 */ 246 if (offset >= vnp->vnp_size) { 247 #ifdef DEBUG 248 if (vpagerdebug & (VDB_FAIL|VDB_SIZE)) 249 printf("vnode_pager_haspage: pg %x, off %x, size %x\n", 250 pager, offset, vnp->vnp_size); 251 #endif 252 return(FALSE); 253 } 254 255 /* 256 * Read the index to find the disk block to read 257 * from. If there is no block, report that we don't 258 * have this data. 259 * 260 * Assumes that the vnode has whole page or nothing. 261 */ 262 err = VOP_BMAP(vnp->vnp_vp, 263 offset / vnp->vnp_vp->v_mount->mnt_stat.f_iosize, 264 (struct vnode **)0, &bn); 265 if (err) { 266 #ifdef DEBUG 267 if (vpagerdebug & VDB_FAIL) 268 printf("vnode_pager_haspage: BMAP err %d, pg %x, off %x\n", 269 err, pager, offset); 270 #endif 271 return(TRUE); 272 } 273 return((long)bn < 0 ? FALSE : TRUE); 274 } 275 276 /* 277 * (XXX) 278 * Lets the VM system know about a change in size for a file. 279 * If this vnode is mapped into some address space (i.e. we have a pager 280 * for it) we adjust our own internal size and flush any cached pages in 281 * the associated object that are affected by the size change. 282 * 283 * Note: this routine may be invoked as a result of a pager put 284 * operation (possibly at object termination time), so we must be careful. 285 */ 286 void 287 vnode_pager_setsize(vp, nsize) 288 struct vnode *vp; 289 u_long nsize; 290 { 291 register vn_pager_t vnp; 292 register vm_object_t object; 293 vm_pager_t pager; 294 295 /* 296 * Not a mapped vnode 297 */ 298 if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL) 299 return; 300 /* 301 * Hasn't changed size 302 */ 303 pager = (vm_pager_t)vp->v_vmdata; 304 vnp = (vn_pager_t)pager->pg_data; 305 if (nsize == vnp->vnp_size) 306 return; 307 /* 308 * No object. 309 * This can happen during object termination since 310 * vm_object_page_clean is called after the object 311 * has been removed from the hash table, and clean 312 * may cause vnode write operations which can wind 313 * up back here. 314 */ 315 object = vm_object_lookup(pager); 316 if (object == NULL) 317 return; 318 319 #ifdef DEBUG 320 if (vpagerdebug & (VDB_FOLLOW|VDB_SIZE)) 321 printf("vnode_pager_setsize: vp %x obj %x osz %d nsz %d\n", 322 vp, object, vnp->vnp_size, nsize); 323 #endif 324 /* 325 * File has shrunk. 326 * Toss any cached pages beyond the new EOF. 327 */ 328 if (nsize < vnp->vnp_size) { 329 vm_object_lock(object); 330 vm_object_page_remove(object, 331 (vm_offset_t)nsize, vnp->vnp_size); 332 vm_object_unlock(object); 333 } 334 vnp->vnp_size = (vm_offset_t)nsize; 335 vm_object_deallocate(object); 336 } 337 338 void 339 vnode_pager_umount(mp) 340 register struct mount *mp; 341 { 342 register vm_pager_t pager, npager; 343 struct vnode *vp; 344 345 pager = (vm_pager_t) queue_first(&vnode_pager_list); 346 while (!queue_end(&vnode_pager_list, (queue_entry_t)pager)) { 347 /* 348 * Save the next pointer now since uncaching may 349 * terminate the object and render pager invalid 350 */ 351 vp = ((vn_pager_t)pager->pg_data)->vnp_vp; 352 npager = (vm_pager_t) queue_next(&pager->pg_list); 353 if (mp == (struct mount *)0 || vp->v_mount == mp) 354 (void) vnode_pager_uncache(vp); 355 pager = npager; 356 } 357 } 358 359 /* 360 * Remove vnode associated object from the object cache. 361 * 362 * Note: this routine may be invoked as a result of a pager put 363 * operation (possibly at object termination time), so we must be careful. 364 */ 365 boolean_t 366 vnode_pager_uncache(vp) 367 register struct vnode *vp; 368 { 369 register vm_object_t object; 370 boolean_t uncached, locked; 371 vm_pager_t pager; 372 373 /* 374 * Not a mapped vnode 375 */ 376 pager = (vm_pager_t)vp->v_vmdata; 377 if (pager == NULL) 378 return (TRUE); 379 /* 380 * Unlock the vnode if it is currently locked. 381 * We do this since uncaching the object may result 382 * in its destruction which may initiate paging 383 * activity which may necessitate locking the vnode. 384 */ 385 locked = VOP_ISLOCKED(vp); 386 if (locked) 387 VOP_UNLOCK(vp); 388 /* 389 * Must use vm_object_lookup() as it actually removes 390 * the object from the cache list. 391 */ 392 object = vm_object_lookup(pager); 393 if (object) { 394 uncached = (object->ref_count <= 1); 395 pager_cache(object, FALSE); 396 } else 397 uncached = TRUE; 398 if (locked) 399 VOP_LOCK(vp); 400 return(uncached); 401 } 402 403 static int 404 vnode_pager_io(vnp, m, rw) 405 register vn_pager_t vnp; 406 vm_page_t m; 407 enum uio_rw rw; 408 { 409 struct uio auio; 410 struct iovec aiov; 411 vm_offset_t kva, foff; 412 int error, size; 413 struct proc *p = curproc; /* XXX */ 414 415 #ifdef DEBUG 416 if (vpagerdebug & VDB_FOLLOW) 417 printf("vnode_pager_io(%x, %x, %c): vnode %x\n", 418 vnp, m, rw == UIO_READ ? 'R' : 'W', vnp->vnp_vp); 419 #endif 420 foff = m->offset + m->object->paging_offset; 421 /* 422 * Return failure if beyond current EOF 423 */ 424 if (foff >= vnp->vnp_size) { 425 #ifdef DEBUG 426 if (vpagerdebug & VDB_SIZE) 427 printf("vnode_pager_io: vp %x, off %d size %d\n", 428 vnp->vnp_vp, foff, vnp->vnp_size); 429 #endif 430 return(VM_PAGER_BAD); 431 } 432 if (foff + PAGE_SIZE > vnp->vnp_size) 433 size = vnp->vnp_size - foff; 434 else 435 size = PAGE_SIZE; 436 /* 437 * Allocate a kernel virtual address and initialize so that 438 * we can use VOP_READ/WRITE routines. 439 */ 440 kva = vm_pager_map_page(m); 441 aiov.iov_base = (caddr_t)kva; 442 aiov.iov_len = size; 443 auio.uio_iov = &aiov; 444 auio.uio_iovcnt = 1; 445 auio.uio_offset = foff; 446 auio.uio_segflg = UIO_SYSSPACE; 447 auio.uio_rw = rw; 448 auio.uio_resid = size; 449 auio.uio_procp = (struct proc *)0; 450 #ifdef DEBUG 451 if (vpagerdebug & VDB_IO) 452 printf("vnode_pager_io: vp %x kva %x foff %x size %x", 453 vnp->vnp_vp, kva, foff, size); 454 #endif 455 if (rw == UIO_READ) 456 error = VOP_READ(vnp->vnp_vp, &auio, 0, p->p_ucred); 457 else 458 error = VOP_WRITE(vnp->vnp_vp, &auio, 0, p->p_ucred); 459 #ifdef DEBUG 460 if (vpagerdebug & VDB_IO) { 461 if (error || auio.uio_resid) 462 printf(" returns error %x, resid %x", 463 error, auio.uio_resid); 464 printf("\n"); 465 } 466 #endif 467 if (!error) { 468 register int count = size - auio.uio_resid; 469 470 if (count == 0) 471 error = EINVAL; 472 else if (count != PAGE_SIZE && rw == UIO_READ) 473 bzero((void *)(kva + count), PAGE_SIZE - count); 474 } 475 vm_pager_unmap_page(kva); 476 return (error ? VM_PAGER_FAIL : VM_PAGER_OK); 477 } 478 #endif 479