Annotation of kernel/bsd/miscfs/umapfs/umap_vnops.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /*     $NetBSD: umap_vnops.c,v 1.3 1994/08/19 11:25:42 mycroft Exp $   */
        !            26: 
        !            27: /*
        !            28:  * Copyright (c) 1992, 1993
        !            29:  *     The Regents of the University of California.  All rights reserved.
        !            30:  *
        !            31:  * This code is derived from software donated to Berkeley by
        !            32:  * the UCLA Ficus project.
        !            33:  *
        !            34:  * Redistribution and use in source and binary forms, with or without
        !            35:  * modification, are permitted provided that the following conditions
        !            36:  * are met:
        !            37:  * 1. Redistributions of source code must retain the above copyright
        !            38:  *    notice, this list of conditions and the following disclaimer.
        !            39:  * 2. Redistributions in binary form must reproduce the above copyright
        !            40:  *    notice, this list of conditions and the following disclaimer in the
        !            41:  *    documentation and/or other materials provided with the distribution.
        !            42:  * 3. All advertising materials mentioning features or use of this software
        !            43:  *    must display the following acknowledgement:
        !            44:  *     This product includes software developed by the University of
        !            45:  *     California, Berkeley and its contributors.
        !            46:  * 4. Neither the name of the University nor the names of its contributors
        !            47:  *    may be used to endorse or promote products derived from this software
        !            48:  *    without specific prior written permission.
        !            49:  *
        !            50:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            51:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            52:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            53:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            54:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            55:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            56:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            57:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            58:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            59:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            60:  * SUCH DAMAGE.
        !            61:  *
        !            62:  *     @(#)umap_vnops.c        8.3 (Berkeley) 1/5/94
        !            63:  */
        !            64: 
        !            65: /*
        !            66:  * Umap Layer
        !            67:  */
        !            68: 
        !            69: #include <sys/param.h>
        !            70: #include <sys/systm.h>
        !            71: #include <sys/time.h>
        !            72: #include <sys/types.h>
        !            73: #include <sys/vnode.h>
        !            74: #include <sys/mount.h>
        !            75: #include <sys/namei.h>
        !            76: #include <sys/malloc.h>
        !            77: #include <sys/buf.h>
        !            78: #include <miscfs/umapfs/umap.h>
        !            79: 
        !            80: 
        !            81: int umap_bug_bypass = 0;   /* for debugging: enables bypass printf'ing */
        !            82: 
        !            83: /*
        !            84:  * This is the 10-Apr-92 bypass routine.
        !            85:  * See null_vnops.c:null_bypass for more details.
        !            86:  */ 
        !            87: int
        !            88: umap_bypass(ap)
        !            89:        struct vop_generic_args /* {
        !            90:                struct vnodeop_desc *a_desc;
        !            91:                <other random data follows, presumably>
        !            92:        } */ *ap;
        !            93: {
        !            94:        extern int (**umap_vnodeop_p)();  /* not extern, really "forward" */
        !            95:        struct ucred **credpp = 0, *credp = 0;
        !            96:        struct ucred *savecredp, *savecompcredp = 0;
        !            97:        struct ucred *compcredp = 0;
        !            98:        struct vnode **this_vp_p;
        !            99:        int error;
        !           100:        struct vnode *old_vps[VDESC_MAX_VPS];
        !           101:        struct vnode *vp1 = 0;
        !           102:        struct vnode **vps_p[VDESC_MAX_VPS];
        !           103:        struct vnode ***vppp;
        !           104:        struct vnodeop_desc *descp = ap->a_desc;
        !           105:        int reles, i;
        !           106:        struct componentname **compnamepp = 0;
        !           107: 
        !           108:        if (umap_bug_bypass)
        !           109:                printf ("umap_bypass: %s\n", descp->vdesc_name);
        !           110: 
        !           111: #ifdef SAFETY
        !           112:        /*
        !           113:         * We require at least one vp.
        !           114:         */
        !           115:        if (descp->vdesc_vp_offsets == NULL ||
        !           116:            descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
        !           117:                panic ("umap_bypass: no vp's in map.\n");
        !           118: #endif
        !           119: 
        !           120:        /*
        !           121:         * Map the vnodes going in.
        !           122:         * Later, we'll invoke the operation based on
        !           123:         * the first mapped vnode's operation vector.
        !           124:         */
        !           125:        reles = descp->vdesc_flags;
        !           126:        for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
        !           127:                if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
        !           128:                        break;   /* bail out at end of list */
        !           129:                vps_p[i] = this_vp_p = 
        !           130:                        VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[i], ap);
        !           131: 
        !           132:                if (i == 0) {
        !           133:                        vp1 = *vps_p[0];
        !           134:                }
        !           135: 
        !           136:                /*
        !           137:                 * We're not guaranteed that any but the first vnode
        !           138:                 * are of our type.  Check for and don't map any
        !           139:                 * that aren't.  (Must map first vp or vclean fails.)
        !           140:                 */
        !           141: 
        !           142:                if (i && (*this_vp_p)->v_op != umap_vnodeop_p) {
        !           143:                        old_vps[i] = NULL;
        !           144:                } else {
        !           145:                        old_vps[i] = *this_vp_p;
        !           146:                        *(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p);
        !           147:                        if (reles & 1)
        !           148:                                VREF(*this_vp_p);
        !           149:                }
        !           150:                        
        !           151:        }
        !           152: 
        !           153:        /*
        !           154:         * Fix the credentials.  (That's the purpose of this layer.)
        !           155:         */
        !           156: 
        !           157:        if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
        !           158: 
        !           159:                credpp = VOPARG_OFFSETTO(struct ucred**, 
        !           160:                    descp->vdesc_cred_offset, ap);
        !           161: 
        !           162:                /* Save old values */
        !           163: 
        !           164:                savecredp = *credpp;
        !           165:                if (savecredp != NOCRED)
        !           166:                        *credpp = crdup(savecredp);
        !           167:                credp = *credpp;
        !           168: 
        !           169:                if (umap_bug_bypass && credp->cr_uid != 0)
        !           170:                        printf("umap_bypass: user was %d, group %d\n", 
        !           171:                            credp->cr_uid, credp->cr_gid);
        !           172: 
        !           173:                /* Map all ids in the credential structure. */
        !           174: 
        !           175:                umap_mapids(vp1->v_mount, credp);
        !           176: 
        !           177:                if (umap_bug_bypass && credp->cr_uid != 0)
        !           178:                        printf("umap_bypass: user now %d, group %d\n", 
        !           179:                            credp->cr_uid, credp->cr_gid);
        !           180:        }
        !           181: 
        !           182:        /* BSD often keeps a credential in the componentname structure
        !           183:         * for speed.  If there is one, it better get mapped, too. 
        !           184:         */
        !           185: 
        !           186:        if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
        !           187: 
        !           188:                compnamepp = VOPARG_OFFSETTO(struct componentname**, 
        !           189:                    descp->vdesc_componentname_offset, ap);
        !           190: 
        !           191:                savecompcredp = (*compnamepp)->cn_cred;
        !           192:                if (savecompcredp != NOCRED)
        !           193:                        (*compnamepp)->cn_cred = crdup(savecompcredp);
        !           194:                compcredp = (*compnamepp)->cn_cred;
        !           195: 
        !           196:                if (umap_bug_bypass && compcredp->cr_uid != 0)
        !           197:                        printf("umap_bypass: component credit user was %d, group %d\n", 
        !           198:                            compcredp->cr_uid, compcredp->cr_gid);
        !           199: 
        !           200:                /* Map all ids in the credential structure. */
        !           201: 
        !           202:                umap_mapids(vp1->v_mount, compcredp);
        !           203: 
        !           204:                if (umap_bug_bypass && compcredp->cr_uid != 0)
        !           205:                        printf("umap_bypass: component credit user now %d, group %d\n", 
        !           206:                            compcredp->cr_uid, compcredp->cr_gid);
        !           207:        }
        !           208: 
        !           209:        /*
        !           210:         * Call the operation on the lower layer
        !           211:         * with the modified argument structure.
        !           212:         */
        !           213:        error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
        !           214: 
        !           215:        /*
        !           216:         * Maintain the illusion of call-by-value
        !           217:         * by restoring vnodes in the argument structure
        !           218:         * to their original value.
        !           219:         */
        !           220:        reles = descp->vdesc_flags;
        !           221:        for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
        !           222:                if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
        !           223:                        break;   /* bail out at end of list */
        !           224:                if (old_vps[i]) {
        !           225:                        *(vps_p[i]) = old_vps[i];
        !           226:                        if (reles & 1)
        !           227:                                vrele(*(vps_p[i]));
        !           228:                };
        !           229:        };
        !           230: 
        !           231:        /*
        !           232:         * Map the possible out-going vpp
        !           233:         * (Assumes that the lower layer always returns
        !           234:         * a VREF'ed vpp unless it gets an error.)
        !           235:         */
        !           236:        if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
        !           237:            !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
        !           238:            !error) {
        !           239:                if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
        !           240:                        goto out;
        !           241:                vppp = VOPARG_OFFSETTO(struct vnode***,
        !           242:                                 descp->vdesc_vpp_offset, ap);
        !           243:                error = umap_node_create(old_vps[0]->v_mount, **vppp, *vppp);
        !           244:        };
        !           245: 
        !           246:  out:
        !           247:        /* 
        !           248:         * Free duplicate cred structure and restore old one.
        !           249:         */
        !           250:        if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
        !           251:                if (umap_bug_bypass && credp && credp->cr_uid != 0)
        !           252:                        printf("umap_bypass: returning-user was %d\n",
        !           253:                                        credp->cr_uid);
        !           254: 
        !           255:                if (savecredp != NOCRED) {
        !           256:                        if (credp != NOCRED)
        !           257:                                crfree(credp);
        !           258:                        *credpp = savecredp;
        !           259:                        if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
        !           260:                                printf("umap_bypass: returning-user now %d\n\n", 
        !           261:                                    savecredp->cr_uid);
        !           262:                }
        !           263:        }
        !           264: 
        !           265:        if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
        !           266:                if (umap_bug_bypass && compcredp && compcredp->cr_uid != 0)
        !           267:                        printf("umap_bypass: returning-component-user was %d\n", 
        !           268:                                compcredp->cr_uid);
        !           269: 
        !           270:                if (savecompcredp != NOCRED) {
        !           271:                        if (compcredp != NOCRED)
        !           272:                                crfree(compcredp);
        !           273:                        (*compnamepp)->cn_cred = savecompcredp;
        !           274:                        if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
        !           275:                                printf("umap_bypass: returning-component-user now %d\n", 
        !           276:                                    savecompcredp->cr_uid);
        !           277:                }
        !           278:        }
        !           279: 
        !           280:        return (error);
        !           281: }
        !           282: 
        !           283: 
        !           284: /*
        !           285:  *  We handle getattr to change the fsid.
        !           286:  */
        !           287: int
        !           288: umap_getattr(ap)
        !           289:        struct vop_getattr_args /* {
        !           290:                struct vnode *a_vp;
        !           291:                struct vattr *a_vap;
        !           292:                struct ucred *a_cred;
        !           293:                struct proc *a_p;
        !           294:        } */ *ap;
        !           295: {
        !           296:        uid_t uid;
        !           297:        gid_t gid;
        !           298:        int error, tmpid, nentries, gnentries;
        !           299:        uid_t (*mapdata)[2];
        !           300:        gid_t (*gmapdata)[2];
        !           301:        struct vnode **vp1p;
        !           302:        struct vnodeop_desc *descp = ap->a_desc;
        !           303: 
        !           304:        if (error = umap_bypass(ap))
        !           305:                return (error);
        !           306:        /* Requires that arguments be restored. */
        !           307:        ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
        !           308: 
        !           309:        /*
        !           310:         * Umap needs to map the uid and gid returned by a stat
        !           311:         * into the proper values for this site.  This involves
        !           312:         * finding the returned uid in the mapping information,
        !           313:         * translating it into the uid on the other end,
        !           314:         * and filling in the proper field in the vattr
        !           315:         * structure pointed to by ap->a_vap.  The group
        !           316:         * is easier, since currently all groups will be
        !           317:         * translate to the NULLGROUP.
        !           318:         */
        !           319: 
        !           320:        /* Find entry in map */
        !           321: 
        !           322:        uid = ap->a_vap->va_uid;
        !           323:        gid = ap->a_vap->va_gid;
        !           324:        if (umap_bug_bypass)
        !           325:                printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid, 
        !           326:                    gid);
        !           327: 
        !           328:        vp1p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap);
        !           329:        nentries =  MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries;
        !           330:        mapdata =  (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata);
        !           331:        gnentries =  MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries;
        !           332:        gmapdata =  (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata);
        !           333: 
        !           334:        /* Reverse map the uid for the vnode.  Since it's a reverse
        !           335:                map, we can't use umap_mapids() to do it. */
        !           336: 
        !           337:        tmpid = umap_reverse_findid(uid, mapdata, nentries);
        !           338: 
        !           339:        if (tmpid != -1) {
        !           340:                ap->a_vap->va_uid = (uid_t) tmpid;
        !           341:                if (umap_bug_bypass)
        !           342:                        printf("umap_getattr: original uid = %d\n", uid);
        !           343:        } else 
        !           344:                ap->a_vap->va_uid = (uid_t) NOBODY;
        !           345: 
        !           346:        /* Reverse map the gid for the vnode. */
        !           347: 
        !           348:        tmpid = umap_reverse_findid(gid, gmapdata, gnentries);
        !           349: 
        !           350:        if (tmpid != -1) {
        !           351:                ap->a_vap->va_gid = (gid_t) tmpid;
        !           352:                if (umap_bug_bypass)
        !           353:                        printf("umap_getattr: original gid = %d\n", gid);
        !           354:        } else
        !           355:                ap->a_vap->va_gid = (gid_t) NULLGROUP;
        !           356:        
        !           357:        return (0);
        !           358: }
        !           359: 
        !           360: int
        !           361: umap_inactive(ap)
        !           362:        struct vop_inactive_args /* {
        !           363:                struct vnode *a_vp;
        !           364:        } */ *ap;
        !           365: {
        !           366:        /*
        !           367:         * Do nothing (and _don't_ bypass).
        !           368:         * Wait to vrele lowervp until reclaim,
        !           369:         * so that until then our umap_node is in the
        !           370:         * cache and reusable.
        !           371:         *
        !           372:         */
        !           373:        return (0);
        !           374: }
        !           375: 
        !           376: int
        !           377: umap_reclaim(ap)
        !           378:        struct vop_reclaim_args /* {
        !           379:                struct vnode *a_vp;
        !           380:        } */ *ap;
        !           381: {
        !           382:        struct vnode *vp = ap->a_vp;
        !           383:        struct umap_node *xp = VTOUMAP(vp);
        !           384:        struct vnode *lowervp = xp->umap_lowervp;
        !           385:        
        !           386:        /* After this assignment, this node will not be re-used. */
        !           387:        xp->umap_lowervp = NULL;
        !           388:        LIST_REMOVE(xp, umap_hash);
        !           389:        FREE(vp->v_data, M_TEMP);
        !           390:        vp->v_data = NULL;
        !           391:        vrele(lowervp);
        !           392:        return (0);
        !           393: }
        !           394: 
        !           395: int
        !           396: umap_strategy(ap)
        !           397:        struct vop_strategy_args /* {
        !           398:                struct buf *a_bp;
        !           399:        } */ *ap;
        !           400: {
        !           401:        struct buf *bp = ap->a_bp;
        !           402:        int error;
        !           403:        struct vnode *savedvp;
        !           404: 
        !           405:        savedvp = bp->b_vp;
        !           406:        bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp);
        !           407: 
        !           408:        error = VOP_STRATEGY(ap->a_bp);
        !           409: 
        !           410:        bp->b_vp = savedvp;
        !           411: 
        !           412:        return (error);
        !           413: }
        !           414: 
        !           415: int
        !           416: umap_bwrite(ap)
        !           417:        struct vop_bwrite_args /* {
        !           418:                struct buf *a_bp;
        !           419:        } */ *ap;
        !           420: {
        !           421:        struct buf *bp = ap->a_bp;
        !           422:        int error;
        !           423:        struct vnode *savedvp;
        !           424: 
        !           425:        savedvp = bp->b_vp;
        !           426:        bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp);
        !           427: 
        !           428:        error = VOP_BWRITE(ap->a_bp);
        !           429: 
        !           430:        bp->b_vp = savedvp;
        !           431: 
        !           432:        return (error);
        !           433: }
        !           434: 
        !           435: 
        !           436: int
        !           437: umap_print(ap)
        !           438:        struct vop_print_args /* {
        !           439:                struct vnode *a_vp;
        !           440:        } */ *ap;
        !           441: {
        !           442:        struct vnode *vp = ap->a_vp;
        !           443:        printf("\ttag VT_UMAPFS, vp=%x, lowervp=%x\n", vp, UMAPVPTOLOWERVP(vp));
        !           444:        return (0);
        !           445: }
        !           446: 
        !           447: int
        !           448: umap_rename(ap)
        !           449:        struct vop_rename_args  /* {
        !           450:                struct vnode *a_fdvp;
        !           451:                struct vnode *a_fvp;
        !           452:                struct componentname *a_fcnp;
        !           453:                struct vnode *a_tdvp;
        !           454:                struct vnode *a_tvp;
        !           455:                struct componentname *a_tcnp;
        !           456:        } */ *ap;
        !           457: {
        !           458:        int error;
        !           459:        struct componentname *compnamep;
        !           460:        struct ucred *compcredp, *savecompcredp;
        !           461:        struct vnode *vp;
        !           462: 
        !           463:        /*
        !           464:         * Rename is irregular, having two componentname structures.
        !           465:         * We need to map the cre in the second structure,
        !           466:         * and then bypass takes care of the rest.
        !           467:         */
        !           468: 
        !           469:        vp = ap->a_fdvp;
        !           470:        compnamep = ap->a_tcnp;
        !           471:        compcredp = compnamep->cn_cred;
        !           472: 
        !           473:        savecompcredp = compcredp;
        !           474:        compcredp = compnamep->cn_cred = crdup(savecompcredp);
        !           475: 
        !           476:        if (umap_bug_bypass && compcredp->cr_uid != 0)
        !           477:                printf("umap_rename: rename component credit user was %d, group %d\n", 
        !           478:                    compcredp->cr_uid, compcredp->cr_gid);
        !           479: 
        !           480:        /* Map all ids in the credential structure. */
        !           481: 
        !           482:        umap_mapids(vp->v_mount, compcredp);
        !           483: 
        !           484:        if (umap_bug_bypass && compcredp->cr_uid != 0)
        !           485:                printf("umap_rename: rename component credit user now %d, group %d\n", 
        !           486:                    compcredp->cr_uid, compcredp->cr_gid);
        !           487: 
        !           488:        error = umap_bypass(ap);
        !           489:        
        !           490:        /* Restore the additional mapped componentname cred structure. */
        !           491: 
        !           492:        crfree(compcredp);
        !           493:        compnamep->cn_cred = savecompcredp;
        !           494: 
        !           495:        return error;
        !           496: }
        !           497: 
        !           498: /*
        !           499:  * Global vfs data structures
        !           500:  */
        !           501: /*
        !           502:  * XXX - strategy, bwrite are hand coded currently.  They should
        !           503:  * go away with a merged buffer/block cache.
        !           504:  *
        !           505:  */
        !           506: int (**umap_vnodeop_p)();
        !           507: struct vnodeopv_entry_desc umap_vnodeop_entries[] = {
        !           508:        { &vop_default_desc, umap_bypass },
        !           509: 
        !           510:        { &vop_getattr_desc, umap_getattr },
        !           511:        { &vop_inactive_desc, umap_inactive },
        !           512:        { &vop_reclaim_desc, umap_reclaim },
        !           513:        { &vop_print_desc, umap_print },
        !           514:        { &vop_rename_desc, umap_rename },
        !           515: 
        !           516:        { &vop_strategy_desc, umap_strategy },
        !           517:        { &vop_bwrite_desc, umap_bwrite },
        !           518: 
        !           519:        { (struct vnodeop_desc*) NULL, (int(*)()) NULL }
        !           520: };
        !           521: struct vnodeopv_desc umap_vnodeop_opv_desc =
        !           522:        { &umap_vnodeop_p, umap_vnodeop_entries };

unix.superglobalmegacorp.com

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