Annotation of Net2/vm/vnode_pager.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.