Annotation of XNU/bsd/vm/vnode_pager.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /* 
                     23:  * Mach Operating System
                     24:  * Copyright (c) 1987 Carnegie-Mellon University
                     25:  * All rights reserved.  The CMU software License Agreement specifies
                     26:  * the terms and conditions for use and redistribution.
                     27:  */
                     28: /*
                     29:  *     File:   vnode_pager.c
                     30:  *
                     31:  *     "Swap" pager that pages to/from vnodes.  Also
                     32:  *     handles demand paging from files.
                     33:  *
                     34:  * HISTORY
                     35:  * 12-Mar-86  David Golub (dbg) at Carnegie-Mellon University
                     36:  *     Created.
                     37:  */
                     38: 
                     39: #include <mach_nbc.h>
                     40: 
                     41: #include <mach/boolean.h>
                     42: #include <sys/param.h>
                     43: #include <sys/systm.h>
                     44: #include <sys/proc.h>
                     45: #include <sys/buf.h>
                     46: #include <sys/uio.h>
                     47: #include <sys/vnode.h>
                     48: #include <ufs/ufs/quota.h>
                     49: #include <ufs/ufs/inode.h>
                     50: #include <sys/namei.h>
                     51: #include <sys/mach_swapon.h>
                     52: #include <ufs/ffs/fs.h>
                     53: #include <sys/mount.h>
                     54: #include <net/if.h>
                     55: #include <netinet/in.h>
                     56: #include <nfs/rpcv2.h>
                     57: #include <nfs/nfsproto.h>
                     58: #include <nfs/nfs.h>
                     59: #include <sys/lock.h>
                     60: #undef fs_fsok
                     61: #undef fs_tsize
                     62: #undef fs_bsize
                     63: #undef fs_blocks
                     64: #undef fs_bfree
                     65: #undef fs_bavail
                     66: 
                     67: #include <mach/mach_types.h>
                     68: #include <vm/vm_map.h>
                     69: #include <vm/vm_kern.h>
                     70: #include <kern/parallel.h>
                     71: #include <kern/zalloc.h>
                     72: #include <kern/kalloc.h>
                     73: #include       <libkern/libkern.h>
                     74: 
                     75: #include <vm/vnode_pager.h>
                     76: #include <kern/mapfs.h>
                     77: 
                     78: #include <kern/assert.h>
                     79: 
                     80: int print_nfs_addr=0;
                     81: 
                     82: extern struct proc proc0;
                     83: extern struct vnode   *default_pager_vnode;
                     84: 
                     85: pager_return_t
                     86: pager_vnode_pageout(struct vnode *vp,
                     87:        void *addr,
                     88:        vm_offset_t f_offset,
                     89:        vm_size_t size,
                     90:        int * errorp)
                     91: {
                     92:        int             result = PAGER_SUCCESS;
                     93:        pf_entry        entry;
                     94:        struct proc     *p = &proc0;
                     95:        int             error = 0;
                     96:        vm_offset_t     ioaddr = (vm_offset_t)addr;
                     97:        struct uio      auio;
                     98:        struct iovec    aiov;
                     99:        int file_max_size = 0;
                    100:        int sub_size = 0;
                    101:        boolean_t       funnel_state;
                    102: 
                    103:        funnel_state = thread_set_funneled(TRUE);       
                    104: 
                    105:        if (ioaddr) {
                    106: 
                    107:           while(TRUE) {
                    108:                auio.uio_iov = &aiov;
                    109:                auio.uio_iovcnt = 1;
                    110:                auio.uio_offset = f_offset;
                    111:                auio.uio_segflg = UIO_SYSSPACE;
                    112:                auio.uio_rw = UIO_WRITE;
                    113:                auio.uio_procp = NULL;
                    114: 
                    115: #if MACH_NBC
                    116:                auio.uio_resid = size;
                    117:                aiov.iov_len = size;
                    118:                sub_size = size;
                    119: #else
                    120:                auio.uio_resid = PAGE_SIZE;
                    121:                aiov.iov_len = PAGE_SIZE;
                    122:                sub_size = PAGE_SIZE;
                    123: #endif
                    124:                aiov.iov_base = (caddr_t)ioaddr;
                    125: 
                    126: 
                    127: /* this is necessary if we are locking only to sync read/write */
                    128: #if     MACH_NBC
                    129:                {
                    130: #define VNODE_LOCK_RETRY_COUNT  1
                    131: #define VNODE_LOCK_RETRY_TICKS  2
                    132: 
                    133:                        int retry = VNODE_LOCK_RETRY_COUNT;
                    134: vnode_lock_retry:
                    135:                        error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_CANRECURSE, p);
                    136:                        if (error) {
                    137:                                /*
                    138:                                 * Retry the lock after yielding to other threads.
                    139:                                 * Not doing this makes the pageout thread compute
                    140:                                 * bound.  Yielding lets I/O threads run
                    141:                                 * and make forward progress.
                    142:                                 */
                    143:                                if (retry-- > 0) {
                    144:                                        assert_wait_timeout(
                    145:                                                       VNODE_LOCK_RETRY_TICKS,
                    146:                                                       THREAD_INTERRUPTIBLE);
                    147:                                        thread_block((void (*)(void)) 0);
                    148:                                        goto vnode_lock_retry;
                    149:                                }
                    150:                                                        
                    151:                                result = KERN_FAILURE;
                    152:                                break;
                    153:                        }
                    154:                }
                    155: #else /* MACH_NBC */
                    156:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE, p);
                    157: #endif /* MACH_NBC */
                    158: 
                    159: /*
                    160:                error = VOP_PAGEOUT(vp, &auio, IO_SYNC, p->p_ucred);
                    161: */
                    162:                error = VOP_PAGEOUT(vp, &auio, 0, p->p_ucred);
                    163: 
                    164:                if (error) {
                    165:                   if (error == ENOSPC)
                    166:                      result = KERN_RESOURCE_SHORTAGE;
                    167:                   else
                    168:                      result = KERN_FAILURE;
                    169: 
                    170:                   error = PAGER_ERROR;
                    171:                }
                    172:                if(vp->v_vm_info)
                    173:                        vp->v_vm_info->error = error;
                    174: 
                    175:                VOP_UNLOCK(vp, 0, p);
                    176: 
                    177:                /* vnode_pageio_complete(m, ioaddr); */
                    178: #if MACH_NBC
                    179:                break;
                    180: #else
                    181:                size -= PAGE_SIZE;
                    182:                if ((size <= 0) || error)
                    183:                        break;
                    184:                f_offset += PAGE_SIZE;
                    185:                ioaddr += PAGE_SIZE;
                    186: #endif
                    187:               }
                    188:            }
                    189:            else {
                    190:                result = KERN_FAILURE;
                    191:                error = PAGER_ERROR;
                    192:            }
                    193: 
                    194:        if (errorp)
                    195:            *errorp = result;
                    196: 
                    197:        (void) thread_set_funneled(funnel_state);
                    198: 
                    199:        return (error);
                    200: }
                    201: 
                    202: pager_return_t
                    203: vnode_pageout(struct vnode *vp,
                    204:        void *addr,
                    205:        vm_offset_t f_offset,
                    206:        vm_size_t size,
                    207:        int * errorp)
                    208: {
                    209:        int             result = PAGER_SUCCESS;
                    210:        pf_entry        entry;
                    211:        struct proc     *p = current_proc();
                    212:        int             error = 0;
                    213:        vm_offset_t     ioaddr = (vm_offset_t)addr;
                    214:        struct uio      auio;
                    215:        struct iovec    aiov;
                    216:        int file_max_size = 0;
                    217:        int sub_size = 0;
                    218:        boolean_t       funnel_state;
                    219: 
                    220:        funnel_state = thread_set_funneled(TRUE);       
                    221: 
                    222:        if (ioaddr) {
                    223: 
                    224:           while(TRUE) {
                    225:                auio.uio_iov = &aiov;
                    226:                auio.uio_iovcnt = 1;
                    227:                auio.uio_offset = f_offset;
                    228:                auio.uio_segflg = UIO_SYSSPACE;
                    229:                auio.uio_rw = UIO_WRITE;
                    230:                auio.uio_procp = NULL;
                    231: 
                    232: #if MACH_NBC
                    233:                auio.uio_resid = size;
                    234:                aiov.iov_len = size;
                    235:                sub_size = size;
                    236: #else
                    237:                auio.uio_resid = PAGE_SIZE;
                    238:                aiov.iov_len = PAGE_SIZE;
                    239:                sub_size = PAGE_SIZE;
                    240: #endif
                    241:                aiov.iov_base = (caddr_t)ioaddr;
                    242: 
                    243: /* this is necessary if we are locking only to sync read/write */
                    244: /* The MACH_NBC flag has been used below also to support multiple pageout */
                    245: /* request when the file system can only support one.                            */
                    246: #if     MACH_NBC
                    247:                {
                    248: #define VNODE_LOCK_RETRY_COUNT  1
                    249: #define VNODE_LOCK_RETRY_TICKS  2
                    250: 
                    251:                        int retry = VNODE_LOCK_RETRY_COUNT;
                    252: vnode_lock_retry:
                    253:                        error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_CANRECURSE, p);
                    254:                        if (error) {
                    255:                                /*
                    256:                                 * Retry the lock after yielding to other threads.
                    257:                                 * Not doing this makes the pageout thread compute
                    258:                                 * bound.  Yielding lets I/O threads run
                    259:                                 * and make forward progress.
                    260:                                 */
                    261:                                if (retry-- > 0) {
                    262:                                        assert_wait_timeout(
                    263:                                                    VNODE_LOCK_RETRY_TICKS,
                    264:                                                    THREAD_INTERRUPTIBLE);
                    265:                                        thread_block((void (*)(void)) 0);
                    266:                                        goto vnode_lock_retry;
                    267:                                }
                    268:                                
                    269:                                result = KERN_FAILURE;
                    270:                                break;
                    271:                        }
                    272:                }
                    273: #else /* MACH_NBC */
                    274:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE, p);
                    275: #endif /* MACH_NBC */
                    276: 
                    277: 
                    278: 
                    279:                error = VOP_PAGEOUT(vp, &auio, 0, p->p_ucred);
                    280: 
                    281:                if (error) {
                    282:                    result = PAGER_ERROR;
                    283:                    error = PAGER_ERROR;
                    284:                }
                    285: 
                    286:                if(vp->v_vm_info)
                    287:                        vp->v_vm_info->error = error;
                    288: 
                    289:                VOP_UNLOCK(vp, 0, p);
                    290: 
                    291:                /* vnode_pageio_complete(m, ioaddr); */
                    292: #if MACH_NBC
                    293:                break;
                    294: #else
                    295:                size -= PAGE_SIZE;
                    296:                if (size <= 0)
                    297:                        break;
                    298:                f_offset += PAGE_SIZE;
                    299:                ioaddr += PAGE_SIZE;
                    300: #endif
                    301:               }
                    302:            }
                    303:            else {
                    304:                result = PAGER_ERROR;
                    305:                error = PAGER_ERROR;
                    306:            }
                    307: 
                    308:        if (errorp)
                    309:            *errorp = result;
                    310: 
                    311:        (void) thread_set_funneled(funnel_state);
                    312: 
                    313:        return (error);
                    314: }
                    315: 
                    316: 
                    317: pager_return_t
                    318: pager_vnode_pagein(struct vnode *vp,
                    319:        void *addr,
                    320:        vm_offset_t f_offset,
                    321:        vm_size_t size,
                    322:        int * errorp)
                    323: {
                    324:        int     result = PAGER_SUCCESS;
                    325:        pf_entry        entry;
                    326:        struct proc     *p = &proc0;
                    327:        int             error = 0;
                    328:        vm_offset_t             ioaddr = (vm_offset_t) addr;
                    329:        struct uio              auio;
                    330:        struct iovec    aiov;
                    331:        int file_max_size =0;
                    332:        boolean_t       funnel_state;
                    333: 
                    334:        funnel_state = thread_set_funneled(TRUE);       
                    335:                
                    336:        if (ioaddr) {
                    337:                auio.uio_iov = &aiov;
                    338:                auio.uio_iovcnt = 1;
                    339:                auio.uio_offset = f_offset;
                    340:                auio.uio_segflg = UIO_SYSSPACE;
                    341:                auio.uio_rw = UIO_READ;
                    342:                auio.uio_resid = size;
                    343:                auio.uio_procp = NULL;
                    344: 
                    345:                aiov.iov_len = size;
                    346:                aiov.iov_base = (caddr_t)ioaddr;
                    347: 
                    348:                vn_lock(vp, LK_SHARED | LK_RETRY | LK_CANRECURSE, p);
                    349: 
                    350:                error = VOP_PAGEIN(vp, &auio, 0, p->p_ucred);
                    351:                if (error) {
                    352:                    result = PAGER_ERROR;
                    353:                }
                    354:                if(vp->v_vm_info)
                    355:                        vp->v_vm_info->error = error;
                    356: 
                    357:                VOP_UNLOCK(vp, 0, p);
                    358: 
                    359:                if (!error && auio.uio_resid > 0)
                    360:                    (void) memset((void *)(ioaddr + size -
                    361:                                           auio.uio_resid), 0, auio.uio_resid);
                    362: 
                    363:                /* vnode_pageio_complete(m, ioaddr); */
                    364: #ifdef ppc
                    365:                /*
                    366:                 * After a pagein, we must synchronize the processor caches.
                    367:                 * On PPC, the i-cache is not coherent in all models, thus
                    368:                 * it needs to be invalidated.
                    369:                 */
                    370:                /* flush_cache(VM_PAGE_TO_PHYS(m), PAGE_SIZE); */
                    371: #endif /* ppc */
                    372:            }
                    373:            else
                    374:                result = PAGER_ERROR;
                    375: 
                    376:        if (errorp)
                    377:            *errorp = result;
                    378: 
                    379:        (void) thread_set_funneled(funnel_state);
                    380: 
                    381:        return (error);
                    382: }
                    383: 
                    384: 
                    385: pager_return_t
                    386: vnode_pagein(struct vnode *vp,
                    387:        void *addr,
                    388:        vm_offset_t f_offset,
                    389:        vm_size_t size,
                    390:        int * errorp)
                    391: {
                    392:        int     result = PAGER_SUCCESS;
                    393:        pf_entry        entry;
                    394:        struct proc     *p = current_proc();
                    395:        int             error = 0;
                    396:        vm_offset_t             ioaddr = (vm_offset_t) addr;
                    397:        struct uio              auio;
                    398:        struct iovec    aiov;
                    399:        int file_max_size =0;
                    400:        boolean_t       funnel_state;
                    401: 
                    402:        funnel_state = thread_set_funneled(TRUE);
                    403:                
                    404:        if (ioaddr) {
                    405:                auio.uio_iov = &aiov;
                    406:                auio.uio_iovcnt = 1;
                    407:                auio.uio_offset = f_offset;
                    408:                auio.uio_segflg = UIO_SYSSPACE;
                    409:                auio.uio_rw = UIO_READ;
                    410:                auio.uio_resid = size;
                    411:                auio.uio_procp = NULL;
                    412: 
                    413:                aiov.iov_len = size;
                    414:                aiov.iov_base = (caddr_t)ioaddr;
                    415: 
                    416:                vn_lock(vp, LK_SHARED | LK_RETRY | LK_CANRECURSE, p);
                    417: 
                    418:                error = VOP_PAGEIN(vp, &auio, 0, p->p_ucred);
                    419:                if (error)
                    420:                    result = PAGER_ERROR;
                    421: 
                    422:                if(vp->v_vm_info)
                    423:                        vp->v_vm_info->error = error;
                    424: 
                    425:                VOP_UNLOCK(vp, 0, p);
                    426: 
                    427:                if (!error && auio.uio_resid > 0)
                    428:                    (void) memset((void *)(ioaddr + size -
                    429:                                           auio.uio_resid), 0, auio.uio_resid);
                    430: 
                    431:                /* vnode_pageio_complete(m, ioaddr); */
                    432: #ifdef ppc
                    433:                /*
                    434:                 * After a pagein, we must synchronize the processor caches.
                    435:                 * On PPC, the i-cache is not coherent in all models, thus
                    436:                 * it needs to be invalidated.
                    437:                 */
                    438:                /* flush_cache(VM_PAGE_TO_PHYS(m), PAGE_SIZE); */
                    439: #endif /* ppc */
                    440:            }
                    441:            else
                    442:                result = PAGER_ERROR;
                    443: 
                    444:        if (errorp)
                    445:            *errorp = result;
                    446: 
                    447:        (void) thread_set_funneled(funnel_state);
                    448: 
                    449:        return (error);
                    450: }
                    451: 
                    452: void
                    453: vnode_pager_shutdown()
                    454: {
                    455:        int i;
                    456:        extern struct bs_map  bs_port_table[];
                    457: 
                    458:        if (default_pager_vnode) {
                    459:                vrele(default_pager_vnode);
                    460:        }
                    461:        for(i = 0; i < MAX_BACKING_STORE; i++) {
                    462:                if((bs_port_table[i]).vp) {
                    463:                        vrele((bs_port_table[i]).vp);
                    464:                        vrele((bs_port_table[i]).vp);
                    465:                        vrele((bs_port_table[i]).vp);
                    466:                        vrele((bs_port_table[i]).vp);
                    467:                        (bs_port_table[i]).vp = 0;
                    468:                }
                    469:        }
                    470: }
                    471: 
                    472: 
                    473: 
                    474: /*
                    475:  *     Remove an vnode from the object cache.
                    476:  */
                    477: int
                    478: vnode_uncache(vp)
                    479:        register struct vnode   *vp;
                    480: {
                    481:        return(1);
                    482: }
                    483: 
                    484: void
                    485: vnode_pager_setsize(vp, nsize)
                    486: struct vnode *vp;
                    487: u_long nsize;
                    488: {
                    489:        if (vp->v_vm_info)
                    490:                vp->v_vm_info->vnode_size = nsize;
                    491: }
                    492: 
                    493: 
                    494: /*
                    495:  * Remove vnode associated object from the object cache.
                    496:  *
                    497:  * XXX unlock the vnode if it is currently locked.
                    498:  * We must do this since uncaching the object may result in its
                    499:  * destruction which may initiate paging activity which may necessitate
                    500:  * re-locking the vnode.
                    501:  */
                    502: boolean_t
                    503: vnode_pager_uncache(vp)
                    504:     register struct vnode *vp;
                    505: {
                    506:     /*
                    507:         * Not a mapped vnode
                    508:         */
                    509:        if (vp->v_type != VREG)
                    510:                return (TRUE);
                    511: #ifdef DEBUG
                    512:     if (!VOP_ISLOCKED(vp)) {
                    513:        extern int (**nfsv2_vnodeop_p)();
                    514: 
                    515:                if (vp->v_op != nfsv2_vnodeop_p)
                    516:                        panic("vnode_pager_uncache: vnode not locked!");
                    517:        }
                    518: #endif
                    519:        return(vnode_uncache(vp));
                    520: }
                    521: 
                    522: void
                    523: vnode_pager_umount(mp)
                    524:     register struct mount *mp;
                    525: {
                    526:        struct proc *p = current_proc();
                    527:        struct vnode *vp, *nvp;
                    528: 
                    529: loop:
                    530:        for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
                    531:                if (vp->v_mount != mp)
                    532:                        goto loop;
                    533:                nvp = vp->v_mntvnodes.le_next;
                    534:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                    535:                (void) vnode_pager_uncache(vp);
                    536:                VOP_UNLOCK(vp, 0, p);
                    537:        }
                    538: }
                    539: int
                    540: vnode_pager_create(vp,pager)
                    541:        register struct vnode   *vp;
                    542:        void * pager;
                    543: {
                    544:        vnode_pager_t   vs;
                    545:        struct vattr    vattr;
                    546:        vm_size_t       size;
                    547:        struct proc     *p = current_proc();
                    548:        int             error;
                    549: 
                    550:        /*
                    551:         *      XXX This can still livelock -- if the
                    552:         *      pageout daemon needs a vnode_pager record
                    553:         *      it won't get one until someone else
                    554:         *      refills the zone.
                    555:         */
                    556: #if 0
                    557:        if (!vp->v_vm_info) {
                    558:                vm_info_init(vp);
                    559:        }
                    560: #endif
                    561:        vp->v_vm_info->pager = pager;
                    562: 
                    563:        error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
                    564:        if (!error) {
                    565:            size = vattr.va_size;
                    566:            vp->v_vm_info->vnode_size = size;
                    567:        }
                    568:        else
                    569:            vp->v_vm_info->vnode_size = 0;
                    570:        
                    571:        VREF(vp);
                    572: 
                    573: 
                    574:        return(0);
                    575: }
                    576: 
                    577: void
                    578: ubc_truncate( vp, length)
                    579:        register struct vnode   *vp;
                    580:        register vm_offset_t    length;
                    581: {
                    582:        int error;
                    583:        vm_map_t user_map;
                    584:        vm_offset_t addr, addr1;
                    585:        vm_size_t size, pageoff;
                    586:        void *  object;
                    587:        void * pager_cport;
                    588:        kern_return_t kret;
                    589:        register struct vm_info *vmp;
                    590: 
                    591:        vmp = vp->v_vm_info;
                    592:        size = round_page(length);
                    593: 
                    594:        
                    595:        if (ISMAPPEDFILE(vp)) {
                    596:                if (length >= vp->v_vm_info->vnode_size) 
                    597:                        return;
                    598: 
                    599:                pageoff = vp->v_vm_info->vnode_size - size;
                    600: 
                    601:                if (pager_cport = vnode_pager_lookup(vp,
                    602:                                vp->v_vm_info->pager)) {
                    603:                        if(object = vm_object_lookup(pager_cport)) {
                    604:                                kret = memory_object_lock_request(object,
                    605:                                        size,
                    606:                                        round_page(pageoff),
                    607:                                        MEMORY_OBJECT_RETURN_NONE,TRUE,
                    608:                                        VM_PROT_NO_CHANGE,MACH_PORT_NULL);
                    609: #if DIAGNOSTIC
                    610:                                if (kret != KERN_SUCCESS) {
                    611:                                        printf("ubc:failed to invalidate in truncate\n");
                    612:                                }
                    613: #endif /* DIAGNOSTIC */
                    614:                        }
                    615:                }
                    616:        }
                    617: 
                    618: }
                    619: 
                    620: /* called only if ISMAPPEDFILE */
                    621: void
                    622: ubc_unlink(vp)
                    623:        register struct vnode   *vp;
                    624: {
                    625:        mach_port_t cport;
                    626: 
                    627:        if (cport = vnode_pager_lookup(vp, vp->v_vm_info->pager)){
                    628:                memory_object_remove_cached_object(cport);
                    629:        }
                    630: }

unix.superglobalmegacorp.com

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