[BACK]Return to coda_vnops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / coda

Annotation of src/sys/coda/coda_vnops.c, Revision 1.23

1.1       rvb         1: /*
1.3       rvb         2: coda_create/vn_open
1.2       rvb         3: remove/unlink
                      4: link
                      5: mkdir
                      6: rmdir
                      7: symlink
1.1       rvb         8: */
1.23    ! jdolecek    9: /*     $NetBSD: coda_vnops.c,v 1.22 2000/11/27 08:39:40 chs Exp $      */
1.1       rvb        10:
1.2       rvb        11: /*
                     12:  *
                     13:  *             Coda: an Experimental Distributed File System
                     14:  *                              Release 3.1
                     15:  *
                     16:  *           Copyright (c) 1987-1998 Carnegie Mellon University
                     17:  *                          All Rights Reserved
                     18:  *
                     19:  * Permission  to  use, copy, modify and distribute this software and its
                     20:  * documentation is hereby granted,  provided  that  both  the  copyright
                     21:  * notice  and  this  permission  notice  appear  in  all  copies  of the
                     22:  * software, derivative works or  modified  versions,  and  any  portions
                     23:  * thereof, and that both notices appear in supporting documentation, and
                     24:  * that credit is given to Carnegie Mellon University  in  all  documents
                     25:  * and publicity pertaining to direct or indirect use of this code or its
                     26:  * derivatives.
                     27:  *
                     28:  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
                     29:  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
                     30:  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
                     31:  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
                     32:  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
                     33:  * ANY DERIVATIVE WORK.
                     34:  *
                     35:  * Carnegie  Mellon  encourages  users  of  this  software  to return any
                     36:  * improvements or extensions that  they  make,  and  to  grant  Carnegie
                     37:  * Mellon the rights to redistribute these changes without encumbrance.
                     38:  *
1.4       rvb        39:  *     @(#) coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:26:46 rvb Exp $
1.2       rvb        40:  */
1.1       rvb        41:
                     42: /*
                     43:  * Mach Operating System
                     44:  * Copyright (c) 1990 Carnegie-Mellon University
                     45:  * Copyright (c) 1989 Carnegie-Mellon University
                     46:  * All rights reserved.  The CMU software License Agreement specifies
                     47:  * the terms and conditions for use and redistribution.
                     48:  */
                     49:
                     50: /*
                     51:  * This code was written for the Coda file system at Carnegie Mellon
                     52:  * University.  Contributers include David Steere, James Kistler, and
                     53:  * M. Satyanarayanan.
                     54:  */
                     55:
                     56: #include <sys/param.h>
                     57: #include <sys/systm.h>
                     58: #include <sys/malloc.h>
                     59: #include <sys/errno.h>
                     60: #include <sys/acct.h>
                     61: #include <sys/file.h>
                     62: #include <sys/uio.h>
                     63: #include <sys/namei.h>
                     64: #include <sys/ioctl.h>
                     65: #include <sys/mount.h>
                     66: #include <sys/proc.h>
                     67: #include <sys/select.h>
                     68: #include <sys/user.h>
                     69: #include <miscfs/genfs/genfs.h>
                     70:
1.4       rvb        71: #include <coda/coda.h>
                     72: #include <coda/cnode.h>
                     73: #include <coda/coda_vnops.h>
                     74: #include <coda/coda_venus.h>
                     75: #include <coda/coda_opstats.h>
                     76: #include <coda/coda_subr.h>
                     77: #include <coda/coda_namecache.h>
                     78: #include <coda/coda_pioctl.h>
1.1       rvb        79:
                     80: /*
                     81:  * These flags select various performance enhancements.
                     82:  */
1.3       rvb        83: int coda_attr_cache  = 1;       /* Set to cache attributes in the kernel */
                     84: int coda_symlink_cache = 1;     /* Set to cache symbolic link information */
                     85: int coda_access_cache = 1;      /* Set to handle some access checks directly */
1.1       rvb        86:
                     87: /* structure to keep track of vfs calls */
                     88:
1.3       rvb        89: struct coda_op_stats coda_vnodeopstats[CODA_VNODEOPS_SIZE];
1.1       rvb        90:
1.3       rvb        91: #define MARK_ENTRY(op) (coda_vnodeopstats[op].entries++)
                     92: #define MARK_INT_SAT(op) (coda_vnodeopstats[op].sat_intrn++)
                     93: #define MARK_INT_FAIL(op) (coda_vnodeopstats[op].unsat_intrn++)
                     94: #define MARK_INT_GEN(op) (coda_vnodeopstats[op].gen_intrn++)
1.1       rvb        95:
                     96: /* What we are delaying for in printf */
1.3       rvb        97: int coda_printf_delay = 0;  /* in microseconds */
                     98: int coda_vnop_print_entry = 0;
                     99: static int coda_lockdebug = 0;
1.1       rvb       100:
                    101: /* Definition of the vfs operation vector */
                    102:
                    103: /*
                    104:  * Some NetBSD details:
                    105:  *
1.3       rvb       106:  *   coda_start is called at the end of the mount syscall.
                    107:  *   coda_init is called at boot time.
1.1       rvb       108:  */
                    109:
1.3       rvb       110: #define ENTRY if(coda_vnop_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
1.1       rvb       111:
                    112: /* Definition of the vnode operation vector */
                    113:
1.23    ! jdolecek  114: const struct vnodeopv_entry_desc coda_vnodeop_entries[] = {
1.3       rvb       115:     { &vop_default_desc, coda_vop_error },
                    116:     { &vop_lookup_desc, coda_lookup },         /* lookup */
                    117:     { &vop_create_desc, coda_create },         /* create */
1.5       rvb       118:     { &vop_mknod_desc, coda_vop_error },       /* mknod */
1.3       rvb       119:     { &vop_open_desc, coda_open },             /* open */
                    120:     { &vop_close_desc, coda_close },           /* close */
                    121:     { &vop_access_desc, coda_access },         /* access */
1.5       rvb       122:     { &vop_getattr_desc, coda_getattr },       /* getattr */
                    123:     { &vop_setattr_desc, coda_setattr },       /* setattr */
1.3       rvb       124:     { &vop_read_desc, coda_read },             /* read */
                    125:     { &vop_write_desc, coda_write },           /* write */
1.11      wrstuden  126:     { &vop_fcntl_desc, genfs_fcntl },          /* fcntl */
1.3       rvb       127:     { &vop_ioctl_desc, coda_ioctl },           /* ioctl */
                    128: /* 1.3    { &vop_select_desc, coda_select },   select */
                    129:     { &vop_mmap_desc, coda_vop_error },                /* mmap */
                    130:     { &vop_fsync_desc, coda_fsync },           /* fsync */
                    131:     { &vop_remove_desc, coda_remove },         /* remove */
                    132:     { &vop_link_desc, coda_link },             /* link */
                    133:     { &vop_rename_desc, coda_rename },         /* rename */
                    134:     { &vop_mkdir_desc, coda_mkdir },           /* mkdir */
                    135:     { &vop_rmdir_desc, coda_rmdir },           /* rmdir */
1.5       rvb       136:     { &vop_symlink_desc, coda_symlink },       /* symlink */
                    137:     { &vop_readdir_desc, coda_readdir },       /* readdir */
1.3       rvb       138:     { &vop_readlink_desc, coda_readlink },     /* readlink */
1.5       rvb       139:     { &vop_abortop_desc, coda_abortop },       /* abortop */
1.3       rvb       140:     { &vop_inactive_desc, coda_inactive },     /* inactive */
1.5       rvb       141:     { &vop_reclaim_desc, coda_reclaim },       /* reclaim */
1.3       rvb       142:     { &vop_lock_desc, coda_lock },             /* lock */
                    143:     { &vop_unlock_desc, coda_unlock },         /* unlock */
                    144:     { &vop_bmap_desc, coda_bmap },             /* bmap */
                    145:     { &vop_strategy_desc, coda_strategy },     /* strategy */
1.5       rvb       146:     { &vop_print_desc, coda_vop_error },       /* print */
1.3       rvb       147:     { &vop_islocked_desc, coda_islocked },     /* islocked */
                    148:     { &vop_pathconf_desc, coda_vop_error },    /* pathconf */
1.5       rvb       149:     { &vop_advlock_desc, coda_vop_nop },       /* advlock */
1.3       rvb       150:     { &vop_bwrite_desc, coda_vop_error },      /* bwrite */
                    151:     { &vop_lease_desc, coda_vop_nop },         /* lease */
                    152:     { &vop_blkatoff_desc, coda_vop_error },    /* blkatoff */
                    153:     { &vop_valloc_desc, coda_vop_error },      /* valloc */
1.5       rvb       154:     { &vop_vfree_desc, coda_vop_error },       /* vfree */
1.3       rvb       155:     { &vop_truncate_desc, coda_vop_error },    /* truncate */
                    156:     { &vop_update_desc, coda_vop_error },      /* update */
1.1       rvb       157:     { &vop_seek_desc, genfs_seek },            /* seek */
1.5       rvb       158:     { &vop_poll_desc, genfs_poll },            /* poll */
1.1       rvb       159:
                    160:     { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL }
                    161: };
                    162:
1.23    ! jdolecek  163: const struct vnodeopv_desc coda_vnodeop_opv_desc =
1.3       rvb       164:         { &coda_vnodeop_p, coda_vnodeop_entries };
1.1       rvb       165:
                    166: /* Definitions of NetBSD vnodeop interfaces */
                    167:
                    168: /* A generic panic: we were called with something we didn't define yet */
                    169: int
1.3       rvb       170: coda_vop_error(void *anon) {
1.1       rvb       171:     struct vnodeop_desc **desc = (struct vnodeop_desc **)anon;
                    172:
1.9       rvb       173:     myprintf(("coda_vop_error: Vnode operation %s called, but not defined.\n",
1.1       rvb       174:              (*desc)->vdesc_name));
1.9       rvb       175:     /*
1.3       rvb       176:     panic("coda_nbsd_vop_error");
1.1       rvb       177:     return 0;
1.9       rvb       178:     */
                    179:     return EIO;
1.1       rvb       180: }
                    181:
                    182: /* A generic do-nothing.  For lease_check, advlock */
                    183: int
1.3       rvb       184: coda_vop_nop(void *anon) {
1.1       rvb       185:     struct vnodeop_desc **desc = (struct vnodeop_desc **)anon;
                    186:
1.3       rvb       187:     if (codadebug) {
1.1       rvb       188:        myprintf(("Vnode operation %s called, but unsupported\n",
                    189:                  (*desc)->vdesc_name));
                    190:     }
                    191:    return (0);
                    192: }
                    193:
                    194: int
1.3       rvb       195: coda_vnodeopstats_init(void)
1.1       rvb       196: {
1.17      augustss  197:        int i;
1.1       rvb       198:
1.3       rvb       199:        for(i=0;i<CODA_VNODEOPS_SIZE;i++) {
                    200:                coda_vnodeopstats[i].opcode = i;
                    201:                coda_vnodeopstats[i].entries = 0;
                    202:                coda_vnodeopstats[i].sat_intrn = 0;
                    203:                coda_vnodeopstats[i].unsat_intrn = 0;
                    204:                coda_vnodeopstats[i].gen_intrn = 0;
1.1       rvb       205:        }
                    206:
                    207:        return 0;
                    208: }
                    209:
                    210: /*
1.3       rvb       211:  * coda_open calls Venus to return the device, inode pair of the cache
                    212:  * file holding the data. Using iget, coda_open finds the vnode of the
1.1       rvb       213:  * cache file, and then opens it.
                    214:  */
                    215: int
1.3       rvb       216: coda_open(v)
1.1       rvb       217:     void *v;
                    218: {
                    219:     /*
                    220:      * NetBSD can pass the O_EXCL flag in mode, even though the check
                    221:      * has already happened.  Venus defensively assumes that if open
                    222:      * is passed the EXCL, it must be a bug.  We strip the flag here.
                    223:      */
                    224: /* true args */
                    225:     struct vop_open_args *ap = v;
1.17      augustss  226:     struct vnode **vpp = &(ap->a_vp);
1.1       rvb       227:     struct cnode *cp = VTOC(*vpp);
                    228:     int flag = ap->a_mode & (~O_EXCL);
                    229:     struct ucred *cred = ap->a_cred;
                    230:     struct proc *p = ap->a_p;
                    231: /* locals */
                    232:     int error;
                    233:     struct vnode *vp;
                    234:     dev_t dev;
                    235:     ino_t inode;
                    236:
1.3       rvb       237:     MARK_ENTRY(CODA_OPEN_STATS);
1.1       rvb       238:
                    239:     /* Check for open of control file. */
                    240:     if (IS_CTL_VP(*vpp)) {
                    241:        /* XXX */
                    242:        /* if (WRITEABLE(flag)) */
                    243:        if (flag & (FWRITE | O_TRUNC | O_CREAT | O_EXCL)) {
1.3       rvb       244:            MARK_INT_FAIL(CODA_OPEN_STATS);
1.1       rvb       245:            return(EACCES);
                    246:        }
1.3       rvb       247:        MARK_INT_SAT(CODA_OPEN_STATS);
1.1       rvb       248:        return(0);
                    249:     }
                    250:
                    251:     error = venus_open(vtomi((*vpp)), &cp->c_fid, flag, cred, p, &dev, &inode);
                    252:     if (error)
                    253:        return (error);
                    254:     if (!error) {
1.3       rvb       255:        CODADEBUG( CODA_OPEN,myprintf(("open: dev %d inode %d result %d\n",
1.1       rvb       256:                                  dev, inode, error)); )
                    257:     }
                    258:
                    259:     /* Translate the <device, inode> pair for the cache file into
                    260:        an inode pointer. */
1.3       rvb       261:     error = coda_grab_vnode(dev, inode, &vp);
1.1       rvb       262:     if (error)
                    263:        return (error);
                    264:
                    265:     /* We get the vnode back locked in both Mach and NetBSD.  Needs unlocked */
1.2       rvb       266:     VOP_UNLOCK(vp, 0);
1.1       rvb       267:     /* Keep a reference until the close comes in. */
                    268:     vref(*vpp);
                    269:
                    270:     /* Save the vnode pointer for the cache file. */
                    271:     if (cp->c_ovp == NULL) {
                    272:        cp->c_ovp = vp;
                    273:     } else {
                    274:        if (cp->c_ovp != vp)
1.3       rvb       275:            panic("coda_open:  cp->c_ovp != ITOV(ip)");
1.1       rvb       276:     }
                    277:     cp->c_ocount++;
                    278:
                    279:     /* Flush the attribute cached if writing the file. */
                    280:     if (flag & FWRITE) {
                    281:        cp->c_owrite++;
                    282:        cp->c_flags &= ~C_VATTR;
                    283:     }
                    284:
                    285:     /* Save the <device, inode> pair for the cache file to speed
                    286:        up subsequent page_read's. */
                    287:     cp->c_device = dev;
                    288:     cp->c_inode = inode;
                    289:
                    290:     /* Open the cache file. */
                    291:     error = VOP_OPEN(vp, flag, cred, p);
                    292:     return(error);
                    293: }
                    294:
                    295: /*
                    296:  * Close the cache file used for I/O and notify Venus.
                    297:  */
                    298: int
1.3       rvb       299: coda_close(v)
1.1       rvb       300:     void *v;
                    301: {
                    302: /* true args */
                    303:     struct vop_close_args *ap = v;
                    304:     struct vnode *vp = ap->a_vp;
                    305:     struct cnode *cp = VTOC(vp);
                    306:     int flag = ap->a_fflag;
                    307:     struct ucred *cred = ap->a_cred;
                    308:     struct proc *p = ap->a_p;
                    309: /* locals */
                    310:     int error;
                    311:
1.3       rvb       312:     MARK_ENTRY(CODA_CLOSE_STATS);
1.1       rvb       313:
                    314:     /* Check for close of control file. */
                    315:     if (IS_CTL_VP(vp)) {
1.3       rvb       316:        MARK_INT_SAT(CODA_CLOSE_STATS);
1.1       rvb       317:        return(0);
                    318:     }
                    319:
                    320:     if (IS_UNMOUNTING(cp)) {
                    321:        if (cp->c_ovp) {
1.7       rvb       322: #ifdef CODA_VERBOSE
1.3       rvb       323:            printf("coda_close: destroying container ref %d, ufs vp %p of vp %p/cp %p\n",
1.1       rvb       324:                    vp->v_usecount, cp->c_ovp, vp, cp);
1.5       rvb       325: #endif
1.8       rvb       326: #ifdef hmm
1.1       rvb       327:            vgone(cp->c_ovp);
1.8       rvb       328: #else
1.14      wrstuden  329:            vn_lock(cp->c_ovp, LK_EXCLUSIVE | LK_RETRY);
1.8       rvb       330:            VOP_CLOSE(cp->c_ovp, flag, cred, p); /* Do errors matter here? */
1.14      wrstuden  331:            vput(cp->c_ovp);
1.8       rvb       332: #endif
1.1       rvb       333:        } else {
1.7       rvb       334: #ifdef CODA_VERBOSE
1.3       rvb       335:            printf("coda_close: NO container vp %p/cp %p\n", vp, cp);
1.5       rvb       336: #endif
1.1       rvb       337:        }
                    338:        return ENODEV;
                    339:     } else {
1.14      wrstuden  340:        vn_lock(cp->c_ovp, LK_EXCLUSIVE | LK_RETRY);
1.1       rvb       341:        VOP_CLOSE(cp->c_ovp, flag, cred, p); /* Do errors matter here? */
1.14      wrstuden  342:        vput(cp->c_ovp);
1.1       rvb       343:     }
                    344:
                    345:     if (--cp->c_ocount == 0)
                    346:        cp->c_ovp = NULL;
                    347:
                    348:     if (flag & FWRITE)                    /* file was opened for write */
                    349:        --cp->c_owrite;
                    350:
                    351:     error = venus_close(vtomi(vp), &cp->c_fid, flag, cred, p);
                    352:     vrele(CTOV(cp));
                    353:
1.3       rvb       354:     CODADEBUG(CODA_CLOSE, myprintf(("close: result %d\n",error)); )
1.1       rvb       355:     return(error);
                    356: }
                    357:
                    358: int
1.3       rvb       359: coda_read(v)
1.1       rvb       360:     void *v;
                    361: {
                    362:     struct vop_read_args *ap = v;
                    363:
                    364:     ENTRY;
1.3       rvb       365:     return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_READ,
1.1       rvb       366:                    ap->a_ioflag, ap->a_cred, ap->a_uio->uio_procp));
                    367: }
                    368:
                    369: int
1.3       rvb       370: coda_write(v)
1.1       rvb       371:     void *v;
                    372: {
                    373:     struct vop_write_args *ap = v;
                    374:
                    375:     ENTRY;
1.3       rvb       376:     return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_WRITE,
1.1       rvb       377:                    ap->a_ioflag, ap->a_cred, ap->a_uio->uio_procp));
                    378: }
                    379:
                    380: int
1.3       rvb       381: coda_rdwr(vp, uiop, rw, ioflag, cred, p)
1.1       rvb       382:     struct vnode *vp;
                    383:     struct uio *uiop;
                    384:     enum uio_rw rw;
                    385:     int ioflag;
                    386:     struct ucred *cred;
                    387:     struct proc *p;
                    388: {
                    389: /* upcall decl */
                    390:   /* NOTE: container file operation!!! */
                    391: /* locals */
                    392:     struct cnode *cp = VTOC(vp);
                    393:     struct vnode *cfvp = cp->c_ovp;
                    394:     int igot_internally = 0;
                    395:     int opened_internally = 0;
                    396:     int error = 0;
                    397:
1.3       rvb       398:     MARK_ENTRY(CODA_RDWR_STATS);
1.1       rvb       399:
1.12      matt      400:     CODADEBUG(CODA_RDWR, myprintf(("coda_rdwr(%d, %p, %lu, %lld, %d)\n", rw,
                    401:                              uiop->uio_iov->iov_base,
                    402:                              (unsigned long) uiop->uio_resid,
                    403:                              (long long) uiop->uio_offset, uiop->uio_segflg)); )
1.1       rvb       404:
                    405:     /* Check for rdwr of control object. */
                    406:     if (IS_CTL_VP(vp)) {
1.3       rvb       407:        MARK_INT_FAIL(CODA_RDWR_STATS);
1.1       rvb       408:        return(EINVAL);
                    409:     }
                    410:
                    411:     /* Redirect the request to UFS. */
                    412:
                    413:     /*
                    414:      * If file is not already open this must be a page
                    415:      * {read,write} request.  Iget the cache file's inode
                    416:      * pointer if we still have its <device, inode> pair.
                    417:      * Otherwise, we must do an internal open to derive the
                    418:      * pair.
                    419:      */
                    420:     if (cfvp == NULL) {
                    421:        /*
                    422:         * If we're dumping core, do the internal open. Otherwise
                    423:         * venus won't have the correct size of the core when
                    424:         * it's completely written.
                    425:         */
                    426:        if (cp->c_inode != 0 && !(p && (p->p_acflag & ACORE))) {
                    427:            igot_internally = 1;
1.3       rvb       428:            error = coda_grab_vnode(cp->c_device, cp->c_inode, &cfvp);
1.1       rvb       429:            if (error) {
1.3       rvb       430:                MARK_INT_FAIL(CODA_RDWR_STATS);
1.1       rvb       431:                return(error);
                    432:            }
                    433:            /*
                    434:             * We get the vnode back locked in both Mach and
                    435:             * NetBSD.  Needs unlocked
                    436:             */
1.2       rvb       437:            VOP_UNLOCK(cfvp, 0);
1.1       rvb       438:        }
                    439:        else {
                    440:            opened_internally = 1;
1.3       rvb       441:            MARK_INT_GEN(CODA_OPEN_STATS);
1.1       rvb       442:            error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE),
                    443:                             cred, p);
1.18      phil      444: #ifdef CODA_VERBOSE
1.3       rvb       445: printf("coda_rdwr: Internally Opening %p\n", vp);
1.18      phil      446: #endif
1.1       rvb       447:            if (error) {
1.3       rvb       448:                MARK_INT_FAIL(CODA_RDWR_STATS);
1.1       rvb       449:                return(error);
                    450:            }
                    451:            cfvp = cp->c_ovp;
                    452:        }
                    453:     }
                    454:
                    455:     /* Have UFS handle the call. */
1.22      chs       456:     CODADEBUG(CODA_RDWR, myprintf(("indirect rdwr: fid = (%lx.%lx.%lx), refcnt = %d\n",
1.1       rvb       457:                              cp->c_fid.Volume, cp->c_fid.Vnode,
                    458:                              cp->c_fid.Unique, CTOV(cp)->v_usecount)); )
                    459:
                    460:     if (rw == UIO_READ) {
                    461:        error = VOP_READ(cfvp, uiop, ioflag, cred);
                    462:     } else {
                    463:        error = VOP_WRITE(cfvp, uiop, ioflag, cred);
                    464:     }
                    465:
                    466:     if (error)
1.3       rvb       467:        MARK_INT_FAIL(CODA_RDWR_STATS);
1.1       rvb       468:     else
1.3       rvb       469:        MARK_INT_SAT(CODA_RDWR_STATS);
1.1       rvb       470:
                    471:     /* Do an internal close if necessary. */
                    472:     if (opened_internally) {
1.3       rvb       473:        MARK_INT_GEN(CODA_CLOSE_STATS);
1.1       rvb       474:        (void)VOP_CLOSE(vp, (rw == UIO_READ ? FREAD : FWRITE), cred, p);
                    475:     }
                    476:
                    477:     /* Invalidate cached attributes if writing. */
                    478:     if (rw == UIO_WRITE)
                    479:        cp->c_flags &= ~C_VATTR;
                    480:     return(error);
                    481: }
                    482:
                    483: int
1.3       rvb       484: coda_ioctl(v)
1.1       rvb       485:     void *v;
                    486: {
                    487: /* true args */
                    488:     struct vop_ioctl_args *ap = v;
                    489:     struct vnode *vp = ap->a_vp;
                    490:     int com = ap->a_command;
                    491:     caddr_t data = ap->a_data;
                    492:     int flag = ap->a_fflag;
                    493:     struct ucred *cred = ap->a_cred;
                    494:     struct proc  *p = ap->a_p;
                    495: /* locals */
                    496:     int error;
                    497:     struct vnode *tvp;
                    498:     struct nameidata ndp;
                    499:     struct PioctlData *iap = (struct PioctlData *)data;
                    500:
1.3       rvb       501:     MARK_ENTRY(CODA_IOCTL_STATS);
1.1       rvb       502:
1.3       rvb       503:     CODADEBUG(CODA_IOCTL, myprintf(("in coda_ioctl on %s\n", iap->path));)
1.1       rvb       504:
                    505:     /* Don't check for operation on a dying object, for ctlvp it
                    506:        shouldn't matter */
                    507:
                    508:     /* Must be control object to succeed. */
                    509:     if (!IS_CTL_VP(vp)) {
1.3       rvb       510:        MARK_INT_FAIL(CODA_IOCTL_STATS);
                    511:        CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: vp != ctlvp"));)
1.1       rvb       512:            return (EOPNOTSUPP);
                    513:     }
                    514:     /* Look up the pathname. */
                    515:
                    516:     /* Should we use the name cache here? It would get it from
                    517:        lookupname sooner or later anyway, right? */
                    518:
                    519:     NDINIT(&ndp, LOOKUP, (iap->follow ? FOLLOW : NOFOLLOW), UIO_USERSPACE, ((caddr_t)iap->path), p);
                    520:     error = namei(&ndp);
                    521:     tvp = ndp.ni_vp;
                    522:
                    523:     if (error) {
1.3       rvb       524:        MARK_INT_FAIL(CODA_IOCTL_STATS);
                    525:        CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: lookup returns %d\n",
1.1       rvb       526:                                   error));)
                    527:        return(error);
                    528:     }
                    529:
                    530:     /*
                    531:      * Make sure this is a coda style cnode, but it may be a
                    532:      * different vfsp
                    533:      */
                    534:     /* XXX: this totally violates the comment about vtagtype in vnode.h */
1.3       rvb       535:     if (tvp->v_tag != VT_CODA) {
1.1       rvb       536:        vrele(tvp);
1.3       rvb       537:        MARK_INT_FAIL(CODA_IOCTL_STATS);
                    538:        CODADEBUG(CODA_IOCTL,
                    539:                 myprintf(("coda_ioctl error: %s not a coda object\n",
1.1       rvb       540:                        iap->path));)
                    541:        return(EINVAL);
                    542:     }
                    543:
                    544:     if (iap->vi.in_size > VC_MAXDATASIZE) {
                    545:        vrele(tvp);
                    546:        return(EINVAL);
                    547:     }
                    548:     error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag, data, cred, p);
                    549:
                    550:     if (error)
1.3       rvb       551:        MARK_INT_FAIL(CODA_IOCTL_STATS);
1.1       rvb       552:     else
1.3       rvb       553:        CODADEBUG(CODA_IOCTL, myprintf(("Ioctl returns %d \n", error)); )
1.1       rvb       554:
                    555:     vrele(tvp);
                    556:     return(error);
                    557: }
                    558:
                    559: /*
                    560:  * To reduce the cost of a user-level venus;we cache attributes in
                    561:  * the kernel.  Each cnode has storage allocated for an attribute. If
                    562:  * c_vattr is valid, return a reference to it. Otherwise, get the
                    563:  * attributes from venus and store them in the cnode.  There is some
                    564:  * question if this method is a security leak. But I think that in
                    565:  * order to make this call, the user must have done a lookup and
                    566:  * opened the file, and therefore should already have access.
                    567:  */
                    568: int
1.3       rvb       569: coda_getattr(v)
1.1       rvb       570:     void *v;
                    571: {
                    572: /* true args */
                    573:     struct vop_getattr_args *ap = v;
                    574:     struct vnode *vp = ap->a_vp;
                    575:     struct cnode *cp = VTOC(vp);
                    576:     struct vattr *vap = ap->a_vap;
                    577:     struct ucred *cred = ap->a_cred;
                    578:     struct proc *p = ap->a_p;
                    579: /* locals */
                    580:     int error;
                    581:
1.3       rvb       582:     MARK_ENTRY(CODA_GETATTR_STATS);
1.1       rvb       583:
                    584:     /* Check for getattr of control object. */
                    585:     if (IS_CTL_VP(vp)) {
1.3       rvb       586:        MARK_INT_FAIL(CODA_GETATTR_STATS);
1.1       rvb       587:        return(ENOENT);
                    588:     }
                    589:
                    590:     /* Check to see if the attributes have already been cached */
                    591:     if (VALID_VATTR(cp)) {
1.3       rvb       592:        CODADEBUG(CODA_GETATTR, { myprintf(("attr cache hit: (%lx.%lx.%lx)\n",
1.1       rvb       593:                                       cp->c_fid.Volume,
                    594:                                       cp->c_fid.Vnode,
                    595:                                       cp->c_fid.Unique));});
1.3       rvb       596:        CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
1.1       rvb       597:                 print_vattr(&cp->c_vattr); );
                    598:
                    599:        *vap = cp->c_vattr;
1.3       rvb       600:        MARK_INT_SAT(CODA_GETATTR_STATS);
1.1       rvb       601:        return(0);
                    602:     }
                    603:
                    604:     error = venus_getattr(vtomi(vp), &cp->c_fid, cred, p, vap);
                    605:
                    606:     if (!error) {
1.3       rvb       607:        CODADEBUG(CODA_GETATTR, myprintf(("getattr miss (%lx.%lx.%lx): result %d\n",
1.1       rvb       608:                                     cp->c_fid.Volume,
                    609:                                     cp->c_fid.Vnode,
                    610:                                     cp->c_fid.Unique,
                    611:                                     error)); )
                    612:
1.3       rvb       613:        CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
1.1       rvb       614:                 print_vattr(vap);      );
                    615:
                    616:        /* If not open for write, store attributes in cnode */
1.3       rvb       617:        if ((cp->c_owrite == 0) && (coda_attr_cache)) {
1.1       rvb       618:            cp->c_vattr = *vap;
                    619:            cp->c_flags |= C_VATTR;
                    620:        }
                    621:
                    622:     }
                    623:     return(error);
                    624: }
                    625:
                    626: int
1.3       rvb       627: coda_setattr(v)
1.1       rvb       628:     void *v;
                    629: {
                    630: /* true args */
                    631:     struct vop_setattr_args *ap = v;
1.17      augustss  632:     struct vnode *vp = ap->a_vp;
1.1       rvb       633:     struct cnode *cp = VTOC(vp);
1.17      augustss  634:     struct vattr *vap = ap->a_vap;
1.1       rvb       635:     struct ucred *cred = ap->a_cred;
                    636:     struct proc *p = ap->a_p;
                    637: /* locals */
                    638:     int error;
                    639:
1.3       rvb       640:     MARK_ENTRY(CODA_SETATTR_STATS);
1.1       rvb       641:
                    642:     /* Check for setattr of control object. */
                    643:     if (IS_CTL_VP(vp)) {
1.3       rvb       644:        MARK_INT_FAIL(CODA_SETATTR_STATS);
1.1       rvb       645:        return(ENOENT);
                    646:     }
                    647:
1.3       rvb       648:     if (codadebug & CODADBGMSK(CODA_SETATTR)) {
1.1       rvb       649:        print_vattr(vap);
                    650:     }
                    651:     error = venus_setattr(vtomi(vp), &cp->c_fid, vap, cred, p);
                    652:
                    653:     if (!error)
                    654:        cp->c_flags &= ~C_VATTR;
                    655:
1.3       rvb       656:     CODADEBUG(CODA_SETATTR,    myprintf(("setattr %d\n", error)); )
1.1       rvb       657:     return(error);
                    658: }
                    659:
                    660: int
1.3       rvb       661: coda_access(v)
1.1       rvb       662:     void *v;
                    663: {
                    664: /* true args */
                    665:     struct vop_access_args *ap = v;
                    666:     struct vnode *vp = ap->a_vp;
                    667:     struct cnode *cp = VTOC(vp);
                    668:     int mode = ap->a_mode;
                    669:     struct ucred *cred = ap->a_cred;
                    670:     struct proc *p = ap->a_p;
                    671: /* locals */
                    672:     int error;
                    673:
1.3       rvb       674:     MARK_ENTRY(CODA_ACCESS_STATS);
1.1       rvb       675:
                    676:     /* Check for access of control object.  Only read access is
                    677:        allowed on it. */
                    678:     if (IS_CTL_VP(vp)) {
                    679:        /* bogus hack - all will be marked as successes */
1.3       rvb       680:        MARK_INT_SAT(CODA_ACCESS_STATS);
1.1       rvb       681:        return(((mode & VREAD) && !(mode & (VWRITE | VEXEC)))
                    682:               ? 0 : EACCES);
                    683:     }
                    684:
                    685:     /*
                    686:      * if the file is a directory, and we are checking exec (eg lookup)
                    687:      * access, and the file is in the namecache, then the user must have
                    688:      * lookup access to it.
                    689:      */
1.3       rvb       690:     if (coda_access_cache) {
1.1       rvb       691:        if ((vp->v_type == VDIR) && (mode & VEXEC)) {
1.3       rvb       692:            if (coda_nc_lookup(cp, ".", 1, cred)) {
                    693:                MARK_INT_SAT(CODA_ACCESS_STATS);
1.1       rvb       694:                return(0);                     /* it was in the cache */
                    695:            }
                    696:        }
                    697:     }
                    698:
                    699:     error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, p);
                    700:
                    701:     return(error);
                    702: }
                    703:
                    704: /*
1.3       rvb       705:  * CODA abort op, called after namei() when a CREATE/DELETE isn't actually
                    706:  * done. If a buffer has been saved in anticipation of a coda_create or
                    707:  * a coda_remove, delete it.
1.1       rvb       708:  */
                    709: /* ARGSUSED */
                    710: int
1.3       rvb       711: coda_abortop(v)
1.1       rvb       712:     void *v;
                    713: {
                    714: /* true args */
                    715:     struct vop_abortop_args /* {
                    716:        struct vnode *a_dvp;
                    717:        struct componentname *a_cnp;
                    718:     } */ *ap = v;
                    719: /* upcall decl */
                    720: /* locals */
                    721:
                    722:     if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
1.20      thorpej   723:        PNBUF_PUT(ap->a_cnp->cn_pnbuf);
1.1       rvb       724:     return (0);
                    725: }
                    726:
                    727: int
1.3       rvb       728: coda_readlink(v)
1.1       rvb       729:     void *v;
                    730: {
                    731: /* true args */
                    732:     struct vop_readlink_args *ap = v;
                    733:     struct vnode *vp = ap->a_vp;
                    734:     struct cnode *cp = VTOC(vp);
                    735:     struct uio *uiop = ap->a_uio;
                    736:     struct ucred *cred = ap->a_cred;
                    737:     struct proc *p = ap->a_uio->uio_procp;
                    738: /* locals */
                    739:     int error;
                    740:     char *str;
                    741:     int len;
                    742:
1.3       rvb       743:     MARK_ENTRY(CODA_READLINK_STATS);
1.1       rvb       744:
                    745:     /* Check for readlink of control object. */
                    746:     if (IS_CTL_VP(vp)) {
1.3       rvb       747:        MARK_INT_FAIL(CODA_READLINK_STATS);
1.1       rvb       748:        return(ENOENT);
                    749:     }
                    750:
1.3       rvb       751:     if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) { /* symlink was cached */
1.1       rvb       752:        uiop->uio_rw = UIO_READ;
                    753:        error = uiomove(cp->c_symlink, (int)cp->c_symlen, uiop);
                    754:        if (error)
1.3       rvb       755:            MARK_INT_FAIL(CODA_READLINK_STATS);
1.1       rvb       756:        else
1.3       rvb       757:            MARK_INT_SAT(CODA_READLINK_STATS);
1.1       rvb       758:        return(error);
                    759:     }
                    760:
                    761:     error = venus_readlink(vtomi(vp), &cp->c_fid, cred, p, &str, &len);
                    762:
                    763:     if (!error) {
                    764:        uiop->uio_rw = UIO_READ;
                    765:        error = uiomove(str, len, uiop);
                    766:
1.3       rvb       767:        if (coda_symlink_cache) {
1.1       rvb       768:            cp->c_symlink = str;
                    769:            cp->c_symlen = len;
                    770:            cp->c_flags |= C_SYMLINK;
                    771:        } else
1.3       rvb       772:            CODA_FREE(str, len);
1.1       rvb       773:     }
                    774:
1.3       rvb       775:     CODADEBUG(CODA_READLINK, myprintf(("in readlink result %d\n",error));)
1.1       rvb       776:     return(error);
                    777: }
                    778:
                    779: int
1.3       rvb       780: coda_fsync(v)
1.1       rvb       781:     void *v;
                    782: {
                    783: /* true args */
                    784:     struct vop_fsync_args *ap = v;
                    785:     struct vnode *vp = ap->a_vp;
                    786:     struct cnode *cp = VTOC(vp);
                    787:     struct ucred *cred = ap->a_cred;
                    788:     struct proc *p = ap->a_p;
                    789: /* locals */
                    790:     struct vnode *convp = cp->c_ovp;
                    791:     int error;
                    792:
1.3       rvb       793:     MARK_ENTRY(CODA_FSYNC_STATS);
1.1       rvb       794:
                    795:     /* Check for fsync on an unmounting object */
                    796:     /* The NetBSD kernel, in it's infinite wisdom, can try to fsync
                    797:      * after an unmount has been initiated.  This is a Bad Thing,
                    798:      * which we have to avoid.  Not a legitimate failure for stats.
                    799:      */
                    800:     if (IS_UNMOUNTING(cp)) {
                    801:        return(ENODEV);
                    802:     }
                    803:
                    804:     /* Check for fsync of control object. */
                    805:     if (IS_CTL_VP(vp)) {
1.3       rvb       806:        MARK_INT_SAT(CODA_FSYNC_STATS);
1.1       rvb       807:        return(0);
                    808:     }
                    809:
                    810:     if (convp)
1.21      fvdl      811:        VOP_FSYNC(convp, cred, MNT_WAIT, 0, 0, p);
1.1       rvb       812:
                    813:     /*
                    814:      * We can expect fsync on any vnode at all if venus is pruging it.
                    815:      * Venus can't very well answer the fsync request, now can it?
                    816:      * Hopefully, it won't have to, because hopefully, venus preserves
                    817:      * the (possibly untrue) invariant that it never purges an open
                    818:      * vnode.  Hopefully.
                    819:      */
                    820:     if (cp->c_flags & C_PURGING) {
                    821:        return(0);
                    822:     }
                    823:
                    824:     error = venus_fsync(vtomi(vp), &cp->c_fid, cred, p);
                    825:
1.3       rvb       826:     CODADEBUG(CODA_FSYNC, myprintf(("in fsync result %d\n",error)); );
1.1       rvb       827:     return(error);
                    828: }
                    829:
                    830: int
1.3       rvb       831: coda_inactive(v)
1.1       rvb       832:     void *v;
                    833: {
                    834:     /* XXX - at the moment, inactive doesn't look at cred, and doesn't
                    835:        have a proc pointer.  Oops. */
                    836: /* true args */
                    837:     struct vop_inactive_args *ap = v;
                    838:     struct vnode *vp = ap->a_vp;
                    839:     struct cnode *cp = VTOC(vp);
                    840:     struct ucred *cred __attribute__((unused)) = NULL;
                    841:     struct proc *p __attribute__((unused)) = curproc;
                    842: /* upcall decl */
                    843: /* locals */
                    844:
                    845:     /* We don't need to send inactive to venus - DCS */
1.3       rvb       846:     MARK_ENTRY(CODA_INACTIVE_STATS);
1.1       rvb       847:
                    848:     if (IS_CTL_VP(vp)) {
1.3       rvb       849:        MARK_INT_SAT(CODA_INACTIVE_STATS);
1.1       rvb       850:        return 0;
                    851:     }
                    852:
1.3       rvb       853:     CODADEBUG(CODA_INACTIVE, myprintf(("in inactive, %lx.%lx.%lx. vfsp %p\n",
1.1       rvb       854:                                  cp->c_fid.Volume, cp->c_fid.Vnode,
                    855:                                  cp->c_fid.Unique, vp->v_mount));)
                    856:
                    857:     /* If an array has been allocated to hold the symlink, deallocate it */
1.3       rvb       858:     if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) {
1.1       rvb       859:        if (cp->c_symlink == NULL)
1.3       rvb       860:            panic("coda_inactive: null symlink pointer in cnode");
1.1       rvb       861:
1.3       rvb       862:        CODA_FREE(cp->c_symlink, cp->c_symlen);
1.1       rvb       863:        cp->c_flags &= ~C_SYMLINK;
                    864:        cp->c_symlen = 0;
                    865:     }
                    866:
                    867:     /* Remove it from the table so it can't be found. */
1.3       rvb       868:     coda_unsave(cp);
                    869:     if ((struct coda_mntinfo *)(vp->v_mount->mnt_data) == NULL) {
1.1       rvb       870:        myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p wasn't dying\n", vp));
1.3       rvb       871:        panic("badness in coda_inactive\n");
1.1       rvb       872:     }
                    873:
                    874:     if (IS_UNMOUNTING(cp)) {
                    875: #ifdef DEBUG
1.22      chs       876:        printf("coda_inactive: IS_UNMOUNTING use %d: vp %p, cp %p\n", vp->v_usecount, vp, cp);
1.1       rvb       877:        if (cp->c_ovp != NULL)
1.22      chs       878:            printf("coda_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n",
1.1       rvb       879:                   vp->v_usecount, vp, cp);
                    880: #endif
1.10      wrstuden  881:        lockmgr(&vp->v_lock, LK_RELEASE, &vp->v_interlock);
1.1       rvb       882:     } else {
1.5       rvb       883: #ifdef OLD_DIAGNOSTIC
1.1       rvb       884:        if (CTOV(cp)->v_usecount) {
1.3       rvb       885:            panic("coda_inactive: nonzero reference count");
1.1       rvb       886:        }
                    887:        if (cp->c_ovp != NULL) {
1.3       rvb       888:            panic("coda_inactive:  cp->ovp != NULL");
1.1       rvb       889:        }
                    890: #endif
1.2       rvb       891:        VOP_UNLOCK(vp, 0);
1.1       rvb       892:        vgone(vp);
                    893:     }
                    894:
1.3       rvb       895:     MARK_INT_SAT(CODA_INACTIVE_STATS);
1.1       rvb       896:     return(0);
                    897: }
                    898:
                    899: /*
                    900:  * Remote file system operations having to do with directory manipulation.
                    901:  */
                    902:
                    903: /*
                    904:  * It appears that in NetBSD, lookup is supposed to return the vnode locked
                    905:  */
                    906: int
1.3       rvb       907: coda_lookup(v)
1.1       rvb       908:     void *v;
                    909: {
                    910: /* true args */
                    911:     struct vop_lookup_args *ap = v;
                    912:     struct vnode *dvp = ap->a_dvp;
                    913:     struct cnode *dcp = VTOC(dvp);
                    914:     struct vnode **vpp = ap->a_vpp;
                    915:     /*
                    916:      * It looks as though ap->a_cnp->ni_cnd->cn_nameptr holds the rest
                    917:      * of the string to xlate, and that we must try to get at least
                    918:      * ap->a_cnp->ni_cnd->cn_namelen of those characters to macth.  I
                    919:      * could be wrong.
                    920:      */
                    921:     struct componentname  *cnp = ap->a_cnp;
                    922:     struct ucred *cred = cnp->cn_cred;
                    923:     struct proc *p = cnp->cn_proc;
                    924: /* locals */
                    925:     struct cnode *cp;
                    926:     const char *nm = cnp->cn_nameptr;
                    927:     int len = cnp->cn_namelen;
                    928:     ViceFid VFid;
                    929:     int        vtype;
                    930:     int error = 0;
                    931:
1.10      wrstuden  932:     cnp->cn_flags &= ~PDIRUNLOCK;
                    933:
1.3       rvb       934:     MARK_ENTRY(CODA_LOOKUP_STATS);
1.1       rvb       935:
1.3       rvb       936:     CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s in %lx.%lx.%lx\n",
1.1       rvb       937:                                   nm, dcp->c_fid.Volume,
                    938:                                   dcp->c_fid.Vnode, dcp->c_fid.Unique)););
                    939:
                    940:     /* Check for lookup of control object. */
                    941:     if (IS_CTL_NAME(dvp, nm, len)) {
1.3       rvb       942:        *vpp = coda_ctlvp;
1.1       rvb       943:        vref(*vpp);
1.3       rvb       944:        MARK_INT_SAT(CODA_LOOKUP_STATS);
1.1       rvb       945:        goto exit;
                    946:     }
                    947:
1.3       rvb       948:     if (len+1 > CODA_MAXNAMLEN) {
                    949:        MARK_INT_FAIL(CODA_LOOKUP_STATS);
                    950:        CODADEBUG(CODA_LOOKUP, myprintf(("name too long: lookup, %lx.%lx.%lx(%s)\n",
1.1       rvb       951:                                    dcp->c_fid.Volume, dcp->c_fid.Vnode,
                    952:                                    dcp->c_fid.Unique, nm)););
                    953:        *vpp = (struct vnode *)0;
                    954:        error = EINVAL;
                    955:        goto exit;
                    956:     }
                    957:     /* First try to look the file up in the cfs name cache */
                    958:     /* lock the parent vnode? */
1.3       rvb       959:     cp = coda_nc_lookup(dcp, nm, len, cred);
1.1       rvb       960:     if (cp) {
                    961:        *vpp = CTOV(cp);
                    962:        vref(*vpp);
1.3       rvb       963:        CODADEBUG(CODA_LOOKUP,
1.1       rvb       964:                 myprintf(("lookup result %d vpp %p\n",error,*vpp));)
                    965:     } else {
                    966:
                    967:        /* The name wasn't cached, so we need to contact Venus */
                    968:        error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred, p, &VFid, &vtype);
                    969:
                    970:        if (error) {
1.3       rvb       971:            MARK_INT_FAIL(CODA_LOOKUP_STATS);
                    972:            CODADEBUG(CODA_LOOKUP, myprintf(("lookup error on %lx.%lx.%lx(%s)%d\n",
1.1       rvb       973:                                        dcp->c_fid.Volume, dcp->c_fid.Vnode, dcp->c_fid.Unique, nm, error));)
                    974:            *vpp = (struct vnode *)0;
                    975:        } else {
1.3       rvb       976:            MARK_INT_SAT(CODA_LOOKUP_STATS);
                    977:            CODADEBUG(CODA_LOOKUP,
1.1       rvb       978:                     myprintf(("lookup: vol %lx vno %lx uni %lx type %o result %d\n",
                    979:                            VFid.Volume, VFid.Vnode, VFid.Unique, vtype,
                    980:                            error)); )
                    981:
1.3       rvb       982:            cp = make_coda_node(&VFid, dvp->v_mount, vtype);
1.1       rvb       983:            *vpp = CTOV(cp);
                    984:
                    985:            /* enter the new vnode in the Name Cache only if the top bit isn't set */
                    986:            /* And don't enter a new vnode for an invalid one! */
1.3       rvb       987:            if (!(vtype & CODA_NOCACHE))
                    988:                coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1.1       rvb       989:        }
                    990:     }
                    991:
                    992:  exit:
                    993:     /*
                    994:      * If we are creating, and this was the last name to be looked up,
                    995:      * and the error was ENOENT, then there really shouldn't be an
                    996:      * error and we can make the leaf NULL and return success.  Since
                    997:      * this is supposed to work under Mach as well as NetBSD, we're
                    998:      * leaving this fn wrapped.  We also must tell lookup/namei that
                    999:      * we need to save the last component of the name.  (Create will
                   1000:      * have to free the name buffer later...lucky us...)
                   1001:      */
                   1002:     if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME))
                   1003:        && (cnp->cn_flags & ISLASTCN)
                   1004:        && (error == ENOENT))
                   1005:     {
                   1006:        error = EJUSTRETURN;
                   1007:        cnp->cn_flags |= SAVENAME;
                   1008:        *ap->a_vpp = NULL;
                   1009:     }
                   1010:
                   1011:     /*
                   1012:      * If we are removing, and we are at the last element, and we
                   1013:      * found it, then we need to keep the name around so that the
                   1014:      * removal will go ahead as planned.  Unfortunately, this will
                   1015:      * probably also lock the to-be-removed vnode, which may or may
                   1016:      * not be a good idea.  I'll have to look at the bits of
1.3       rvb      1017:      * coda_remove to make sure.  We'll only save the name if we did in
                   1018:      * fact find the name, otherwise coda_remove won't have a chance
1.1       rvb      1019:      * to free the pathname.
                   1020:      */
                   1021:     if ((cnp->cn_nameiop == DELETE)
                   1022:        && (cnp->cn_flags & ISLASTCN)
                   1023:        && !error)
                   1024:     {
                   1025:        cnp->cn_flags |= SAVENAME;
                   1026:     }
                   1027:
                   1028:     /*
                   1029:      * If the lookup went well, we need to (potentially?) unlock the
                   1030:      * parent, and lock the child.  We are only responsible for
                   1031:      * checking to see if the parent is supposed to be unlocked before
                   1032:      * we return.  We must always lock the child (provided there is
                   1033:      * one, and (the parent isn't locked or it isn't the same as the
                   1034:      * parent.)  Simple, huh?  We can never leave the parent locked unless
                   1035:      * we are ISLASTCN
                   1036:      */
                   1037:     if (!error || (error == EJUSTRETURN)) {
                   1038:        if (!(cnp->cn_flags & LOCKPARENT) || !(cnp->cn_flags & ISLASTCN)) {
1.2       rvb      1039:            if ((error = VOP_UNLOCK(dvp, 0))) {
1.1       rvb      1040:                return error;
                   1041:            }
1.10      wrstuden 1042:            cnp->cn_flags |= PDIRUNLOCK;
1.1       rvb      1043:            /*
                   1044:             * The parent is unlocked.  As long as there is a child,
                   1045:             * lock it without bothering to check anything else.
                   1046:             */
                   1047:            if (*ap->a_vpp) {
1.2       rvb      1048:                if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
1.3       rvb      1049:                    printf("coda_lookup: ");
1.1       rvb      1050:                    panic("unlocked parent but couldn't lock child");
                   1051:                }
                   1052:            }
                   1053:        } else {
                   1054:            /* The parent is locked, and may be the same as the child */
                   1055:            if (*ap->a_vpp && (*ap->a_vpp != dvp)) {
                   1056:                /* Different, go ahead and lock it. */
1.2       rvb      1057:                if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
1.3       rvb      1058:                    printf("coda_lookup: ");
1.1       rvb      1059:                    panic("unlocked parent but couldn't lock child");
                   1060:                }
                   1061:            }
                   1062:        }
                   1063:     } else {
                   1064:        /* If the lookup failed, we need to ensure that the leaf is NULL */
                   1065:        /* Don't change any locking? */
                   1066:        *ap->a_vpp = NULL;
                   1067:     }
                   1068:     return(error);
                   1069: }
                   1070:
                   1071: /*ARGSUSED*/
                   1072: int
1.3       rvb      1073: coda_create(v)
1.1       rvb      1074:     void *v;
                   1075: {
                   1076: /* true args */
                   1077:     struct vop_create_args *ap = v;
                   1078:     struct vnode *dvp = ap->a_dvp;
                   1079:     struct cnode *dcp = VTOC(dvp);
                   1080:     struct vattr *va = ap->a_vap;
                   1081:     int exclusive = 1;
                   1082:     int mode = ap->a_vap->va_mode;
                   1083:     struct vnode **vpp = ap->a_vpp;
                   1084:     struct componentname  *cnp = ap->a_cnp;
                   1085:     struct ucred *cred = cnp->cn_cred;
                   1086:     struct proc *p = cnp->cn_proc;
                   1087: /* locals */
                   1088:     int error;
                   1089:     struct cnode *cp;
                   1090:     const char *nm = cnp->cn_nameptr;
                   1091:     int len = cnp->cn_namelen;
                   1092:     ViceFid VFid;
                   1093:     struct vattr attr;
                   1094:
1.3       rvb      1095:     MARK_ENTRY(CODA_CREATE_STATS);
1.1       rvb      1096:
                   1097:     /* All creates are exclusive XXX */
                   1098:     /* I'm assuming the 'mode' argument is the file mode bits XXX */
                   1099:
                   1100:     /* Check for create of control object. */
                   1101:     if (IS_CTL_NAME(dvp, nm, len)) {
                   1102:        *vpp = (struct vnode *)0;
1.3       rvb      1103:        MARK_INT_FAIL(CODA_CREATE_STATS);
1.1       rvb      1104:        return(EACCES);
                   1105:     }
                   1106:
                   1107:     error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive, mode, va, cred, p, &VFid, &attr);
                   1108:
                   1109:     if (!error) {
                   1110:
                   1111:        /* If this is an exclusive create, panic if the file already exists. */
                   1112:        /* Venus should have detected the file and reported EEXIST. */
                   1113:
                   1114:        if ((exclusive == 1) &&
1.3       rvb      1115:            (coda_find(&VFid) != NULL))
1.1       rvb      1116:            panic("cnode existed for newly created file!");
                   1117:
1.3       rvb      1118:        cp = make_coda_node(&VFid, dvp->v_mount, attr.va_type);
1.1       rvb      1119:        *vpp = CTOV(cp);
                   1120:
                   1121:        /* Update va to reflect the new attributes. */
                   1122:        (*va) = attr;
                   1123:
                   1124:        /* Update the attribute cache and mark it as valid */
1.3       rvb      1125:        if (coda_attr_cache) {
1.1       rvb      1126:            VTOC(*vpp)->c_vattr = attr;
                   1127:            VTOC(*vpp)->c_flags |= C_VATTR;
                   1128:        }
                   1129:
                   1130:        /* Invalidate the parent's attr cache, the modification time has changed */
                   1131:        VTOC(dvp)->c_flags &= ~C_VATTR;
                   1132:
                   1133:        /* enter the new vnode in the Name Cache */
1.3       rvb      1134:        coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1.1       rvb      1135:
1.3       rvb      1136:        CODADEBUG(CODA_CREATE,
1.1       rvb      1137:                 myprintf(("create: (%lx.%lx.%lx), result %d\n",
                   1138:                        VFid.Volume, VFid.Vnode, VFid.Unique, error)); )
                   1139:     } else {
                   1140:        *vpp = (struct vnode *)0;
1.3       rvb      1141:        CODADEBUG(CODA_CREATE, myprintf(("create error %d\n", error));)
1.1       rvb      1142:     }
                   1143:
                   1144:     /* Locking strategy. */
                   1145:     /*
                   1146:      * In NetBSD, all creates must explicitly vput their dvp's.  We'll
                   1147:      * go ahead and use the LOCKLEAF flag of the cnp argument.
                   1148:      * However, I'm pretty sure that create must return the leaf
                   1149:      * locked; so there is a DIAGNOSTIC check to ensure that this is
                   1150:      * true.
                   1151:      */
                   1152:     vput(dvp);
                   1153:     if (!error) {
                   1154:        if (cnp->cn_flags & LOCKLEAF) {
1.2       rvb      1155:            if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
1.3       rvb      1156:                printf("coda_create: ");
1.1       rvb      1157:                panic("unlocked parent but couldn't lock child");
                   1158:            }
                   1159:        }
1.7       rvb      1160: #ifdef OLD_DIAGNOSTIC
1.1       rvb      1161:        else {
1.3       rvb      1162:            printf("coda_create: LOCKLEAF not set!\n");
1.1       rvb      1163:        }
1.5       rvb      1164: #endif
1.1       rvb      1165:     }
                   1166:     /* Have to free the previously saved name */
                   1167:     /*
                   1168:      * This condition is stolen from ufs_makeinode.  I have no idea
                   1169:      * why it's here, but what the hey...
                   1170:      */
                   1171:     if ((cnp->cn_flags & SAVESTART) == 0) {
1.20      thorpej  1172:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       rvb      1173:     }
                   1174:     return(error);
                   1175: }
                   1176:
                   1177: int
1.3       rvb      1178: coda_remove(v)
1.1       rvb      1179:     void *v;
                   1180: {
                   1181: /* true args */
                   1182:     struct vop_remove_args *ap = v;
                   1183:     struct vnode *dvp = ap->a_dvp;
                   1184:     struct cnode *cp = VTOC(dvp);
                   1185:     struct componentname  *cnp = ap->a_cnp;
                   1186:     struct ucred *cred = cnp->cn_cred;
                   1187:     struct proc *p = cnp->cn_proc;
                   1188: /* locals */
                   1189:     int error;
                   1190:     const char *nm = cnp->cn_nameptr;
                   1191:     int len = cnp->cn_namelen;
                   1192:     struct cnode *tp;
                   1193:
1.3       rvb      1194:     MARK_ENTRY(CODA_REMOVE_STATS);
1.1       rvb      1195:
1.3       rvb      1196:     CODADEBUG(CODA_REMOVE, myprintf(("remove: %s in %lx.%lx.%lx\n",
1.1       rvb      1197:                                   nm, cp->c_fid.Volume, cp->c_fid.Vnode,
                   1198:                                   cp->c_fid.Unique)););
                   1199:
1.3       rvb      1200:     /* Remove the file's entry from the CODA Name Cache */
1.1       rvb      1201:     /* We're being conservative here, it might be that this person
                   1202:      * doesn't really have sufficient access to delete the file
                   1203:      * but we feel zapping the entry won't really hurt anyone -- dcs
                   1204:      */
                   1205:     /* I'm gonna go out on a limb here. If a file and a hardlink to it
                   1206:      * exist, and one is removed, the link count on the other will be
                   1207:      * off by 1. We could either invalidate the attrs if cached, or
                   1208:      * fix them. I'll try to fix them. DCS 11/8/94
                   1209:      */
1.3       rvb      1210:     tp = coda_nc_lookup(VTOC(dvp), nm, len, cred);
1.1       rvb      1211:     if (tp) {
                   1212:        if (VALID_VATTR(tp)) {  /* If attrs are cached */
                   1213:            if (tp->c_vattr.va_nlink > 1) {     /* If it's a hard link */
                   1214:                tp->c_vattr.va_nlink--;
                   1215:            }
                   1216:        }
                   1217:
1.3       rvb      1218:        coda_nc_zapfile(VTOC(dvp), nm, len);
1.1       rvb      1219:        /* No need to flush it if it doesn't exist! */
                   1220:     }
                   1221:     /* Invalidate the parent's attr cache, the modification time has changed */
                   1222:     VTOC(dvp)->c_flags &= ~C_VATTR;
                   1223:
                   1224:     /* Check for remove of control object. */
                   1225:     if (IS_CTL_NAME(dvp, nm, len)) {
1.3       rvb      1226:        MARK_INT_FAIL(CODA_REMOVE_STATS);
1.1       rvb      1227:        return(ENOENT);
                   1228:     }
                   1229:
                   1230:     error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred, p);
                   1231:
1.3       rvb      1232:     CODADEBUG(CODA_REMOVE, myprintf(("in remove result %d\n",error)); )
1.1       rvb      1233:
                   1234:     /*
                   1235:      * Regardless of what happens, we have to unconditionally drop
                   1236:      * locks/refs on parent and child.  (I hope).  This is based on
                   1237:      * what ufs_remove seems to be doing.
                   1238:      */
                   1239:     if (dvp == ap->a_vp) {
                   1240:        vrele(ap->a_vp);
                   1241:     } else {
                   1242:        vput(ap->a_vp);
                   1243:     }
                   1244:     vput(dvp);
                   1245:
                   1246:     if ((cnp->cn_flags & SAVESTART) == 0) {
1.20      thorpej  1247:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       rvb      1248:     }
                   1249:     return(error);
                   1250: }
                   1251:
                   1252: int
1.3       rvb      1253: coda_link(v)
1.1       rvb      1254:     void *v;
                   1255: {
                   1256: /* true args */
                   1257:     struct vop_link_args *ap = v;
                   1258:     struct vnode *vp = ap->a_vp;
                   1259:     struct cnode *cp = VTOC(vp);
                   1260:     struct vnode *tdvp = ap->a_dvp;
                   1261:     struct cnode *tdcp = VTOC(tdvp);
                   1262:     struct componentname *cnp = ap->a_cnp;
                   1263:     struct ucred *cred = cnp->cn_cred;
                   1264:     struct proc *p = cnp->cn_proc;
                   1265: /* locals */
                   1266:     int error;
                   1267:     const char *nm = cnp->cn_nameptr;
                   1268:     int len = cnp->cn_namelen;
                   1269:
1.3       rvb      1270:     MARK_ENTRY(CODA_LINK_STATS);
1.1       rvb      1271:
1.3       rvb      1272:     if (codadebug & CODADBGMSK(CODA_LINK)) {
1.1       rvb      1273:
                   1274:        myprintf(("nb_link:   vp fid: (%lx.%lx.%lx)\n",
                   1275:                  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
                   1276:        myprintf(("nb_link: tdvp fid: (%lx.%lx.%lx)\n",
                   1277:                  tdcp->c_fid.Volume, tdcp->c_fid.Vnode, tdcp->c_fid.Unique));
                   1278:
                   1279:     }
1.3       rvb      1280:     if (codadebug & CODADBGMSK(CODA_LINK)) {
1.1       rvb      1281:        myprintf(("link:   vp fid: (%lx.%lx.%lx)\n",
                   1282:                  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
                   1283:        myprintf(("link: tdvp fid: (%lx.%lx.%lx)\n",
                   1284:                  tdcp->c_fid.Volume, tdcp->c_fid.Vnode, tdcp->c_fid.Unique));
                   1285:
                   1286:     }
                   1287:
                   1288:     /* Check for link to/from control object. */
                   1289:     if (IS_CTL_NAME(tdvp, nm, len) || IS_CTL_VP(vp)) {
1.3       rvb      1290:        MARK_INT_FAIL(CODA_LINK_STATS);
1.1       rvb      1291:        return(EACCES);
                   1292:     }
                   1293:
                   1294:     /*
                   1295:      * According to the ufs_link operation here's the locking situation:
                   1296:      *     We enter with the thing called "dvp" (the directory) locked.
                   1297:      *     We must unconditionally drop locks on "dvp"
                   1298:      *
                   1299:      *     We enter with the thing called "vp" (the linked-to) unlocked,
                   1300:      *       but ref'd (?)
1.3       rvb      1301:      *     We seem to need to lock it before calling coda_link, and
1.1       rvb      1302:      *       unconditionally unlock it after.
                   1303:      */
                   1304:
1.2       rvb      1305:     if ((ap->a_vp != tdvp) && (error = vn_lock(ap->a_vp, LK_EXCLUSIVE))) {
1.1       rvb      1306:        goto exit;
                   1307:     }
                   1308:
                   1309:     error = venus_link(vtomi(vp), &cp->c_fid, &tdcp->c_fid, nm, len, cred, p);
                   1310:
                   1311:     /* Invalidate the parent's attr cache, the modification time has changed */
                   1312:     VTOC(tdvp)->c_flags &= ~C_VATTR;
                   1313:     VTOC(vp)->c_flags &= ~C_VATTR;
                   1314:
1.3       rvb      1315:     CODADEBUG(CODA_LINK,       myprintf(("in link result %d\n",error)); )
1.1       rvb      1316:
                   1317: exit:
                   1318:
                   1319:     if (ap->a_vp != tdvp) {
1.2       rvb      1320:        VOP_UNLOCK(ap->a_vp, 0);
1.1       rvb      1321:     }
                   1322:     vput(tdvp);
                   1323:
                   1324:     /* Drop the name buffer if we don't need to SAVESTART */
                   1325:     if ((cnp->cn_flags & SAVESTART) == 0) {
1.20      thorpej  1326:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       rvb      1327:     }
                   1328:     return(error);
                   1329: }
                   1330:
                   1331: int
1.3       rvb      1332: coda_rename(v)
1.1       rvb      1333:     void *v;
                   1334: {
                   1335: /* true args */
                   1336:     struct vop_rename_args *ap = v;
                   1337:     struct vnode *odvp = ap->a_fdvp;
                   1338:     struct cnode *odcp = VTOC(odvp);
                   1339:     struct componentname  *fcnp = ap->a_fcnp;
                   1340:     struct vnode *ndvp = ap->a_tdvp;
                   1341:     struct cnode *ndcp = VTOC(ndvp);
                   1342:     struct componentname  *tcnp = ap->a_tcnp;
                   1343:     struct ucred *cred = fcnp->cn_cred;
                   1344:     struct proc *p = fcnp->cn_proc;
                   1345: /* true args */
                   1346:     int error;
                   1347:     const char *fnm = fcnp->cn_nameptr;
                   1348:     int flen = fcnp->cn_namelen;
                   1349:     const char *tnm = tcnp->cn_nameptr;
                   1350:     int tlen = tcnp->cn_namelen;
                   1351:
1.3       rvb      1352:     MARK_ENTRY(CODA_RENAME_STATS);
1.1       rvb      1353:
                   1354:     /* Hmmm.  The vnodes are already looked up.  Perhaps they are locked?
                   1355:        This could be Bad. XXX */
1.5       rvb      1356: #ifdef OLD_DIAGNOSTIC
1.1       rvb      1357:     if ((fcnp->cn_cred != tcnp->cn_cred)
                   1358:        || (fcnp->cn_proc != tcnp->cn_proc))
                   1359:     {
1.3       rvb      1360:        panic("coda_rename: component names don't agree");
1.1       rvb      1361:     }
1.5       rvb      1362: #endif
1.1       rvb      1363:
                   1364:     /* Check for rename involving control object. */
                   1365:     if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) {
1.3       rvb      1366:        MARK_INT_FAIL(CODA_RENAME_STATS);
1.1       rvb      1367:        return(EACCES);
                   1368:     }
                   1369:
                   1370:     /* Problem with moving directories -- need to flush entry for .. */
                   1371:     if (odvp != ndvp) {
1.3       rvb      1372:        struct cnode *ovcp = coda_nc_lookup(VTOC(odvp), fnm, flen, cred);
1.1       rvb      1373:        if (ovcp) {
                   1374:            struct vnode *ovp = CTOV(ovcp);
                   1375:            if ((ovp) &&
                   1376:                (ovp->v_type == VDIR)) /* If it's a directory */
1.3       rvb      1377:                coda_nc_zapfile(VTOC(ovp),"..", 2);
1.1       rvb      1378:        }
                   1379:     }
                   1380:
                   1381:     /* Remove the entries for both source and target files */
1.3       rvb      1382:     coda_nc_zapfile(VTOC(odvp), fnm, flen);
                   1383:     coda_nc_zapfile(VTOC(ndvp), tnm, tlen);
1.1       rvb      1384:
                   1385:     /* Invalidate the parent's attr cache, the modification time has changed */
                   1386:     VTOC(odvp)->c_flags &= ~C_VATTR;
                   1387:     VTOC(ndvp)->c_flags &= ~C_VATTR;
                   1388:
1.3       rvb      1389:     if (flen+1 > CODA_MAXNAMLEN) {
                   1390:        MARK_INT_FAIL(CODA_RENAME_STATS);
1.1       rvb      1391:        error = EINVAL;
                   1392:        goto exit;
                   1393:     }
                   1394:
1.3       rvb      1395:     if (tlen+1 > CODA_MAXNAMLEN) {
                   1396:        MARK_INT_FAIL(CODA_RENAME_STATS);
1.1       rvb      1397:        error = EINVAL;
                   1398:        goto exit;
                   1399:     }
                   1400:
                   1401:     error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm, flen, tnm, tlen, cred, p);
                   1402:
                   1403:  exit:
1.3       rvb      1404:     CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error));)
1.1       rvb      1405:     /* XXX - do we need to call cache pureg on the moved vnode? */
                   1406:     cache_purge(ap->a_fvp);
                   1407:
                   1408:     /* It seems to be incumbent on us to drop locks on all four vnodes */
                   1409:     /* From-vnodes are not locked, only ref'd.  To-vnodes are locked. */
                   1410:
                   1411:     vrele(ap->a_fvp);
                   1412:     vrele(odvp);
                   1413:
                   1414:     if (ap->a_tvp) {
                   1415:        if (ap->a_tvp == ndvp) {
                   1416:            vrele(ap->a_tvp);
                   1417:        } else {
                   1418:            vput(ap->a_tvp);
                   1419:        }
                   1420:     }
                   1421:
                   1422:     vput(ndvp);
                   1423:     return(error);
                   1424: }
                   1425:
                   1426: int
1.3       rvb      1427: coda_mkdir(v)
1.1       rvb      1428:     void *v;
                   1429: {
                   1430: /* true args */
                   1431:     struct vop_mkdir_args *ap = v;
                   1432:     struct vnode *dvp = ap->a_dvp;
                   1433:     struct cnode *dcp = VTOC(dvp);
                   1434:     struct componentname  *cnp = ap->a_cnp;
1.17      augustss 1435:     struct vattr *va = ap->a_vap;
1.1       rvb      1436:     struct vnode **vpp = ap->a_vpp;
                   1437:     struct ucred *cred = cnp->cn_cred;
                   1438:     struct proc *p = cnp->cn_proc;
                   1439: /* locals */
                   1440:     int error;
                   1441:     const char *nm = cnp->cn_nameptr;
                   1442:     int len = cnp->cn_namelen;
                   1443:     struct cnode *cp;
                   1444:     ViceFid VFid;
                   1445:     struct vattr ova;
                   1446:
1.3       rvb      1447:     MARK_ENTRY(CODA_MKDIR_STATS);
1.1       rvb      1448:
                   1449:     /* Check for mkdir of target object. */
                   1450:     if (IS_CTL_NAME(dvp, nm, len)) {
                   1451:        *vpp = (struct vnode *)0;
1.3       rvb      1452:        MARK_INT_FAIL(CODA_MKDIR_STATS);
1.1       rvb      1453:        return(EACCES);
                   1454:     }
                   1455:
1.3       rvb      1456:     if (len+1 > CODA_MAXNAMLEN) {
1.1       rvb      1457:        *vpp = (struct vnode *)0;
1.3       rvb      1458:        MARK_INT_FAIL(CODA_MKDIR_STATS);
1.1       rvb      1459:        return(EACCES);
                   1460:     }
                   1461:
                   1462:     error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred, p, &VFid, &ova);
                   1463:
                   1464:     if (!error) {
1.3       rvb      1465:        if (coda_find(&VFid) != NULL)
1.1       rvb      1466:            panic("cnode existed for newly created directory!");
                   1467:
                   1468:
1.3       rvb      1469:        cp =  make_coda_node(&VFid, dvp->v_mount, va->va_type);
1.1       rvb      1470:        *vpp = CTOV(cp);
                   1471:
                   1472:        /* enter the new vnode in the Name Cache */
1.3       rvb      1473:        coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1.1       rvb      1474:
                   1475:        /* as a side effect, enter "." and ".." for the directory */
1.3       rvb      1476:        coda_nc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp));
                   1477:        coda_nc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp));
1.1       rvb      1478:
1.3       rvb      1479:        if (coda_attr_cache) {
1.1       rvb      1480:            VTOC(*vpp)->c_vattr = ova;          /* update the attr cache */
                   1481:            VTOC(*vpp)->c_flags |= C_VATTR;     /* Valid attributes in cnode */
                   1482:        }
                   1483:
                   1484:        /* Invalidate the parent's attr cache, the modification time has changed */
                   1485:        VTOC(dvp)->c_flags &= ~C_VATTR;
                   1486:
1.3       rvb      1487:        CODADEBUG( CODA_MKDIR, myprintf(("mkdir: (%lx.%lx.%lx) result %d\n",
1.1       rvb      1488:                                    VFid.Volume, VFid.Vnode, VFid.Unique, error)); )
                   1489:     } else {
                   1490:        *vpp = (struct vnode *)0;
1.3       rvb      1491:        CODADEBUG(CODA_MKDIR, myprintf(("mkdir error %d\n",error));)
1.1       rvb      1492:     }
                   1493:
                   1494:     /*
                   1495:      * Currently, all mkdirs explicitly vput their dvp's.
                   1496:      * It also appears that we *must* lock the vpp, since
                   1497:      * lockleaf isn't set, but someone down the road is going
                   1498:      * to try to unlock the new directory.
                   1499:      */
                   1500:     vput(dvp);
                   1501:     if (!error) {
1.2       rvb      1502:        if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
1.3       rvb      1503:            panic("coda_mkdir: couldn't lock child");
1.1       rvb      1504:        }
                   1505:     }
                   1506:
                   1507:     /* Have to free the previously saved name */
                   1508:     /*
                   1509:      * ufs_mkdir doesn't check for SAVESTART before freeing the
                   1510:      * pathname buffer, but ufs_create does.  For the moment, I'll
                   1511:      * follow their lead, but this seems like it is probably
                   1512:      * incorrect.
                   1513:      */
1.20      thorpej  1514:     PNBUF_PUT(cnp->cn_pnbuf);
1.1       rvb      1515:     return(error);
                   1516: }
                   1517:
                   1518: int
1.3       rvb      1519: coda_rmdir(v)
1.1       rvb      1520:     void *v;
                   1521: {
                   1522: /* true args */
                   1523:     struct vop_rmdir_args *ap = v;
                   1524:     struct vnode *dvp = ap->a_dvp;
                   1525:     struct cnode *dcp = VTOC(dvp);
                   1526:     struct componentname  *cnp = ap->a_cnp;
                   1527:     struct ucred *cred = cnp->cn_cred;
                   1528:     struct proc *p = cnp->cn_proc;
                   1529: /* true args */
                   1530:     int error;
                   1531:     const char *nm = cnp->cn_nameptr;
                   1532:     int len = cnp->cn_namelen;
                   1533:     struct cnode *cp;
                   1534:
1.3       rvb      1535:     MARK_ENTRY(CODA_RMDIR_STATS);
1.1       rvb      1536:
                   1537:     /* Check for rmdir of control object. */
                   1538:     if (IS_CTL_NAME(dvp, nm, len)) {
1.3       rvb      1539:        MARK_INT_FAIL(CODA_RMDIR_STATS);
1.1       rvb      1540:        return(ENOENT);
                   1541:     }
                   1542:
                   1543:     /* We're being conservative here, it might be that this person
                   1544:      * doesn't really have sufficient access to delete the file
                   1545:      * but we feel zapping the entry won't really hurt anyone -- dcs
                   1546:      */
                   1547:     /*
                   1548:      * As a side effect of the rmdir, remove any entries for children of
                   1549:      * the directory, especially "." and "..".
                   1550:      */
1.3       rvb      1551:     cp = coda_nc_lookup(dcp, nm, len, cred);
                   1552:     if (cp) coda_nc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL);
1.1       rvb      1553:
1.3       rvb      1554:     /* Remove the file's entry from the CODA Name Cache */
                   1555:     coda_nc_zapfile(dcp, nm, len);
1.1       rvb      1556:
                   1557:     /* Invalidate the parent's attr cache, the modification time has changed */
                   1558:     dcp->c_flags &= ~C_VATTR;
                   1559:
                   1560:     error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred, p);
                   1561:
1.3       rvb      1562:     CODADEBUG(CODA_RMDIR, myprintf(("in rmdir result %d\n", error)); )
1.1       rvb      1563:
                   1564:     /*
                   1565:      * regardless of what happens, we need to drop locks/refs on the
                   1566:      * parent and child.  I think.
                   1567:      */
                   1568:     if (dvp == ap->a_vp) {
                   1569:        vrele(ap->a_vp);
                   1570:     } else {
                   1571:        vput(ap->a_vp);
                   1572:     }
                   1573:     vput(dvp);
                   1574:
                   1575:     if ((cnp->cn_flags & SAVESTART) == 0) {
1.20      thorpej  1576:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       rvb      1577:     }
                   1578:     return(error);
                   1579: }
                   1580:
                   1581: int
1.3       rvb      1582: coda_symlink(v)
1.1       rvb      1583:     void *v;
                   1584: {
                   1585: /* true args */
                   1586:     struct vop_symlink_args *ap = v;
                   1587:     struct vnode *tdvp = ap->a_dvp;
                   1588:     struct cnode *tdcp = VTOC(tdvp);
                   1589:     struct componentname *cnp = ap->a_cnp;
                   1590:     struct vattr *tva = ap->a_vap;
                   1591:     char *path = ap->a_target;
                   1592:     struct ucred *cred = cnp->cn_cred;
                   1593:     struct proc *p = cnp->cn_proc;
                   1594: /* locals */
                   1595:     int error;
                   1596:     /*
1.3       rvb      1597:      * XXX I'm assuming the following things about coda_symlink's
1.1       rvb      1598:      * arguments:
                   1599:      *       t(foo) is the new name/parent/etc being created.
                   1600:      *       lname is the contents of the new symlink.
                   1601:      */
1.2       rvb      1602:     const char *nm = cnp->cn_nameptr;
1.1       rvb      1603:     int len = cnp->cn_namelen;
                   1604:     int plen = strlen(path);
                   1605:
                   1606:     /* XXX What about the vpp argument?  Do we need it? */
                   1607:     /*
                   1608:      * Here's the strategy for the moment: perform the symlink, then
                   1609:      * do a lookup to grab the resulting vnode.  I know this requires
                   1610:      * two communications with Venus for a new sybolic link, but
                   1611:      * that's the way the ball bounces.  I don't yet want to change
                   1612:      * the way the Mach symlink works.  When Mach support is
                   1613:      * deprecated, we should change symlink so that the common case
                   1614:      * returns the resultant vnode in a vpp argument.
                   1615:      */
                   1616:
1.3       rvb      1617:     MARK_ENTRY(CODA_SYMLINK_STATS);
1.1       rvb      1618:
                   1619:     /* Check for symlink of control object. */
                   1620:     if (IS_CTL_NAME(tdvp, nm, len)) {
1.3       rvb      1621:        MARK_INT_FAIL(CODA_SYMLINK_STATS);
1.1       rvb      1622:        return(EACCES);
                   1623:     }
                   1624:
1.3       rvb      1625:     if (plen+1 > CODA_MAXPATHLEN) {
                   1626:        MARK_INT_FAIL(CODA_SYMLINK_STATS);
1.1       rvb      1627:        return(EINVAL);
                   1628:     }
                   1629:
1.3       rvb      1630:     if (len+1 > CODA_MAXNAMLEN) {
                   1631:        MARK_INT_FAIL(CODA_SYMLINK_STATS);
1.1       rvb      1632:        error = EINVAL;
                   1633:        goto exit;
                   1634:     }
                   1635:
                   1636:     error = venus_symlink(vtomi(tdvp), &tdcp->c_fid, path, plen, nm, len, tva, cred, p);
                   1637:
                   1638:     /* Invalidate the parent's attr cache, the modification time has changed */
                   1639:     tdcp->c_flags &= ~C_VATTR;
                   1640:
                   1641:     if (!error)
                   1642:     {
                   1643:        struct nameidata nd;
                   1644:        NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, nm, p);
                   1645:        nd.ni_cnd.cn_cred = cred;
                   1646:        nd.ni_loopcnt = 0;
                   1647:        nd.ni_startdir = tdvp;
                   1648:        nd.ni_cnd.cn_pnbuf = (char *)nm;
                   1649:        nd.ni_cnd.cn_nameptr = nd.ni_cnd.cn_pnbuf;
                   1650:        nd.ni_pathlen = len;
                   1651:        vput(tdvp);
                   1652:        error = lookup(&nd);
                   1653:        *ap->a_vpp = nd.ni_vp;
                   1654:     }
                   1655:
                   1656:     /*
                   1657:      * Okay, now we have to drop locks on dvp.  vpp is unlocked, but
                   1658:      * ref'd.  It doesn't matter what happens in either symlink or
                   1659:      * lookup.  Furthermore, there isn't any way for (dvp == *vpp), so
                   1660:      * we don't bother checking.
                   1661:      */
                   1662: /*  vput(ap->a_dvp);           released earlier */
                   1663:     if (*ap->a_vpp) {
1.2       rvb      1664:        VOP_UNLOCK(*ap->a_vpp, 0);      /* this line is new!! It is necessary because lookup() calls
1.3       rvb      1665:                                   VOP_LOOKUP (coda_lookup) which returns vpp locked.  cfs_nb_lookup
                   1666:                                   merged with coda_lookup() to become coda_lookup so UNLOCK is
1.1       rvb      1667:                                   necessary */
                   1668:        vrele(*ap->a_vpp);
                   1669:     }
                   1670:
                   1671:     /*
                   1672:      * Free the name buffer
                   1673:      */
                   1674:     if ((cnp->cn_flags & SAVESTART) == 0) {
1.20      thorpej  1675:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       rvb      1676:     }
                   1677:
                   1678:  exit:
1.3       rvb      1679:     CODADEBUG(CODA_SYMLINK, myprintf(("in symlink result %d\n",error)); )
1.1       rvb      1680:     return(error);
                   1681: }
                   1682:
                   1683: /*
                   1684:  * Read directory entries.
                   1685:  */
                   1686: int
1.3       rvb      1687: coda_readdir(v)
1.1       rvb      1688:     void *v;
                   1689: {
                   1690: /* true args */
                   1691:     struct vop_readdir_args *ap = v;
                   1692:     struct vnode *vp = ap->a_vp;
                   1693:     struct cnode *cp = VTOC(vp);
1.17      augustss 1694:     struct uio *uiop = ap->a_uio;
1.1       rvb      1695:     struct ucred *cred = ap->a_cred;
                   1696:     int *eofflag = ap->a_eofflag;
                   1697:     off_t **cookies = ap->a_cookies;
                   1698:     int *ncookies = ap->a_ncookies;
                   1699:     struct proc *p = ap->a_uio->uio_procp;
                   1700: /* upcall decl */
                   1701: /* locals */
                   1702:     int error = 0;
                   1703:
1.3       rvb      1704:     MARK_ENTRY(CODA_READDIR_STATS);
1.1       rvb      1705:
1.12      matt     1706:     CODADEBUG(CODA_READDIR, myprintf(("coda_readdir(%p, %lu, %lld, %d)\n", uiop->uio_iov->iov_base, (unsigned long) uiop->uio_resid, (long long) uiop->uio_offset, uiop->uio_segflg)); )
1.1       rvb      1707:
                   1708:     /* Check for readdir of control object. */
                   1709:     if (IS_CTL_VP(vp)) {
1.3       rvb      1710:        MARK_INT_FAIL(CODA_READDIR_STATS);
1.1       rvb      1711:        return(ENOENT);
                   1712:     }
                   1713:
1.2       rvb      1714:     {
1.1       rvb      1715:        /* Redirect the request to UFS. */
                   1716:
                   1717:        /* If directory is not already open do an "internal open" on it. */
                   1718:        int opened_internally = 0;
                   1719:        if (cp->c_ovp == NULL) {
                   1720:            opened_internally = 1;
1.3       rvb      1721:            MARK_INT_GEN(CODA_OPEN_STATS);
1.1       rvb      1722:            error = VOP_OPEN(vp, FREAD, cred, p);
1.18      phil     1723: #ifdef CODA_VERBOSE
1.3       rvb      1724: printf("coda_readdir: Internally Opening %p\n", vp);
1.18      phil     1725: #endif
1.1       rvb      1726:            if (error) return(error);
                   1727:        }
                   1728:
                   1729:        /* Have UFS handle the call. */
1.22      chs      1730:        CODADEBUG(CODA_READDIR, myprintf(("indirect readdir: fid = (%lx.%lx.%lx), refcnt = %d\n",cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, vp->v_usecount)); )
1.1       rvb      1731:        error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, cookies,
                   1732:                               ncookies);
                   1733:        if (error)
1.3       rvb      1734:            MARK_INT_FAIL(CODA_READDIR_STATS);
1.1       rvb      1735:        else
1.3       rvb      1736:            MARK_INT_SAT(CODA_READDIR_STATS);
1.1       rvb      1737:
                   1738:        /* Do an "internal close" if necessary. */
                   1739:        if (opened_internally) {
1.3       rvb      1740:            MARK_INT_GEN(CODA_CLOSE_STATS);
1.1       rvb      1741:            (void)VOP_CLOSE(vp, FREAD, cred, p);
                   1742:        }
                   1743:     }
                   1744:
                   1745:     return(error);
                   1746: }
                   1747:
                   1748: /*
                   1749:  * Convert from file system blocks to device blocks
                   1750:  */
                   1751: int
1.3       rvb      1752: coda_bmap(v)
1.1       rvb      1753:     void *v;
                   1754: {
                   1755:     /* XXX on the global proc */
                   1756: /* true args */
                   1757:     struct vop_bmap_args *ap = v;
                   1758:     struct vnode *vp __attribute__((unused)) = ap->a_vp;       /* file's vnode */
                   1759:     daddr_t bn __attribute__((unused)) = ap->a_bn;     /* fs block number */
                   1760:     struct vnode **vpp = ap->a_vpp;                    /* RETURN vp of device */
                   1761:     daddr_t *bnp __attribute__((unused)) = ap->a_bnp;  /* RETURN device block number */
                   1762:     struct proc *p __attribute__((unused)) = curproc;
                   1763: /* upcall decl */
                   1764: /* locals */
                   1765:
                   1766:        *vpp = (struct vnode *)0;
1.3       rvb      1767:        myprintf(("coda_bmap called!\n"));
1.1       rvb      1768:        return(EINVAL);
                   1769: }
                   1770:
                   1771: /*
                   1772:  * I don't think the following two things are used anywhere, so I've
                   1773:  * commented them out
                   1774:  *
                   1775:  * struct buf *async_bufhead;
                   1776:  * int async_daemon_count;
                   1777:  */
                   1778: int
1.3       rvb      1779: coda_strategy(v)
1.1       rvb      1780:     void *v;
                   1781: {
                   1782: /* true args */
                   1783:     struct vop_strategy_args *ap = v;
1.17      augustss 1784:     struct buf *bp __attribute__((unused)) = ap->a_bp;
1.1       rvb      1785:     struct proc *p __attribute__((unused)) = curproc;
                   1786: /* upcall decl */
                   1787: /* locals */
                   1788:
1.3       rvb      1789:        myprintf(("coda_strategy called!  "));
1.1       rvb      1790:        return(EINVAL);
                   1791: }
                   1792:
                   1793: int
1.3       rvb      1794: coda_reclaim(v)
1.1       rvb      1795:     void *v;
                   1796: {
                   1797: /* true args */
                   1798:     struct vop_reclaim_args *ap = v;
                   1799:     struct vnode *vp = ap->a_vp;
                   1800:     struct cnode *cp = VTOC(vp);
                   1801: /* upcall decl */
                   1802: /* locals */
                   1803:
                   1804: /*
                   1805:  * Forced unmount/flush will let vnodes with non zero use be destroyed!
                   1806:  */
                   1807:     ENTRY;
                   1808:
                   1809:     if (IS_UNMOUNTING(cp)) {
                   1810: #ifdef DEBUG
                   1811:        if (VTOC(vp)->c_ovp) {
                   1812:            if (IS_UNMOUNTING(cp))
1.3       rvb      1813:                printf("coda_reclaim: c_ovp not void: vp %p, cp %p\n", vp, cp);
1.1       rvb      1814:        }
                   1815: #endif
                   1816:     } else {
1.5       rvb      1817: #ifdef OLD_DIAGNOSTIC
1.1       rvb      1818:        if (vp->v_usecount != 0)
1.5       rvb      1819:            print("coda_reclaim: pushing active %p\n", vp);
1.1       rvb      1820:        if (VTOC(vp)->c_ovp) {
1.3       rvb      1821:            panic("coda_reclaim: c_ovp not void");
1.2       rvb      1822:        }
1.5       rvb      1823: #endif
1.1       rvb      1824:     }
                   1825:     cache_purge(vp);
1.3       rvb      1826:     coda_free(VTOC(vp));
1.1       rvb      1827:     VTOC(vp) = NULL;
                   1828:     return (0);
                   1829: }
                   1830:
                   1831: int
1.3       rvb      1832: coda_lock(v)
1.1       rvb      1833:     void *v;
                   1834: {
                   1835: /* true args */
                   1836:     struct vop_lock_args *ap = v;
                   1837:     struct vnode *vp = ap->a_vp;
                   1838:     struct cnode *cp = VTOC(vp);
                   1839: /* upcall decl */
                   1840: /* locals */
                   1841:
                   1842:     ENTRY;
                   1843:
1.3       rvb      1844:     if (coda_lockdebug) {
1.1       rvb      1845:        myprintf(("Attempting lock on %lx.%lx.%lx\n",
                   1846:                  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
                   1847:     }
                   1848:
1.10      wrstuden 1849:     return (lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock));
1.1       rvb      1850: }
                   1851:
                   1852: int
1.3       rvb      1853: coda_unlock(v)
1.1       rvb      1854:     void *v;
                   1855: {
                   1856: /* true args */
                   1857:     struct vop_unlock_args *ap = v;
                   1858:     struct vnode *vp = ap->a_vp;
                   1859:     struct cnode *cp = VTOC(vp);
                   1860: /* upcall decl */
                   1861: /* locals */
                   1862:
                   1863:     ENTRY;
1.3       rvb      1864:     if (coda_lockdebug) {
1.1       rvb      1865:        myprintf(("Attempting unlock on %lx.%lx.%lx\n",
                   1866:                  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
                   1867:     }
                   1868:
1.10      wrstuden 1869:     return (lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock));
1.1       rvb      1870: }
                   1871:
                   1872: int
1.3       rvb      1873: coda_islocked(v)
1.1       rvb      1874:     void *v;
                   1875: {
                   1876: /* true args */
                   1877:     struct vop_islocked_args *ap = v;
                   1878:     ENTRY;
                   1879:
1.10      wrstuden 1880:     return (lockstatus(&ap->a_vp->v_lock));
1.1       rvb      1881: }
                   1882:
                   1883: /* How one looks up a vnode given a device/inode pair: */
                   1884: int
1.3       rvb      1885: coda_grab_vnode(dev_t dev, ino_t ino, struct vnode **vpp)
1.1       rvb      1886: {
                   1887:     /* This is like VFS_VGET() or igetinode()! */
                   1888:     int           error;
                   1889:     struct mount *mp;
                   1890:
                   1891:     if (!(mp = devtomp(dev))) {
1.3       rvb      1892:        myprintf(("coda_grab_vnode: devtomp(%d) returns NULL\n", dev));
1.1       rvb      1893:        return(ENXIO);
                   1894:     }
                   1895:
                   1896:     /* XXX - ensure that nonzero-return means failure */
                   1897:     error = VFS_VGET(mp,ino,vpp);
                   1898:     if (error) {
1.3       rvb      1899:        myprintf(("coda_grab_vnode: iget/vget(%d, %d) returns %p, err %d\n",
1.1       rvb      1900:                  dev, ino, *vpp, error));
                   1901:        return(ENOENT);
                   1902:     }
                   1903:     return(0);
                   1904: }
                   1905:
                   1906: void
                   1907: print_vattr( attr )
                   1908:        struct vattr *attr;
                   1909: {
                   1910:     char *typestr;
                   1911:
                   1912:     switch (attr->va_type) {
                   1913:     case VNON:
                   1914:        typestr = "VNON";
                   1915:        break;
                   1916:     case VREG:
                   1917:        typestr = "VREG";
                   1918:        break;
                   1919:     case VDIR:
                   1920:        typestr = "VDIR";
                   1921:        break;
                   1922:     case VBLK:
                   1923:        typestr = "VBLK";
                   1924:        break;
                   1925:     case VCHR:
                   1926:        typestr = "VCHR";
                   1927:        break;
                   1928:     case VLNK:
                   1929:        typestr = "VLNK";
                   1930:        break;
                   1931:     case VSOCK:
                   1932:        typestr = "VSCK";
                   1933:        break;
                   1934:     case VFIFO:
                   1935:        typestr = "VFFO";
                   1936:        break;
                   1937:     case VBAD:
                   1938:        typestr = "VBAD";
                   1939:        break;
                   1940:     default:
                   1941:        typestr = "????";
                   1942:        break;
                   1943:     }
                   1944:
                   1945:
                   1946:     myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n",
                   1947:              typestr, (int)attr->va_mode, (int)attr->va_uid,
                   1948:              (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev));
                   1949:
                   1950:     myprintf(("      fileid %d nlink %d size %d blocksize %d bytes %d\n",
                   1951:              (int)attr->va_fileid, (int)attr->va_nlink,
                   1952:              (int)attr->va_size,
                   1953:              (int)attr->va_blocksize,(int)attr->va_bytes));
                   1954:     myprintf(("      gen %ld flags %ld vaflags %d\n",
                   1955:              attr->va_gen, attr->va_flags, attr->va_vaflags));
                   1956:     myprintf(("      atime sec %d nsec %d\n",
                   1957:              (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec));
                   1958:     myprintf(("      mtime sec %d nsec %d\n",
                   1959:              (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec));
                   1960:     myprintf(("      ctime sec %d nsec %d\n",
                   1961:              (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec));
                   1962: }
                   1963:
                   1964: /* How to print a ucred */
                   1965: void
                   1966: print_cred(cred)
                   1967:        struct ucred *cred;
                   1968: {
                   1969:
                   1970:        int i;
                   1971:
                   1972:        myprintf(("ref %d\tuid %d\n",cred->cr_ref,cred->cr_uid));
                   1973:
                   1974:        for (i=0; i < cred->cr_ngroups; i++)
                   1975:                myprintf(("\tgroup %d: (%d)\n",i,cred->cr_groups[i]));
                   1976:        myprintf(("\n"));
                   1977:
                   1978: }
                   1979:
                   1980: /*
                   1981:  * Return a vnode for the given fid.
                   1982:  * If no cnode exists for this fid create one and put it
                   1983:  * in a table hashed by fid.Volume and fid.Vnode.  If the cnode for
                   1984:  * this fid is already in the table return it (ref count is
1.3       rvb      1985:  * incremented by coda_find.  The cnode will be flushed from the
                   1986:  * table when coda_inactive calls coda_unsave.
1.1       rvb      1987:  */
                   1988: struct cnode *
1.3       rvb      1989: make_coda_node(fid, vfsp, type)
1.1       rvb      1990:      ViceFid *fid; struct mount *vfsp; short type;
                   1991: {
                   1992:     struct cnode *cp;
                   1993:     int          err;
                   1994:
1.3       rvb      1995:     if ((cp = coda_find(fid)) == NULL) {
1.1       rvb      1996:        struct vnode *vp;
                   1997:
1.3       rvb      1998:        cp = coda_alloc();
1.1       rvb      1999:        cp->c_fid = *fid;
                   2000:
1.3       rvb      2001:        err = getnewvnode(VT_CODA, vfsp, coda_vnodeop_p, &vp);
1.1       rvb      2002:        if (err) {
1.3       rvb      2003:            panic("coda: getnewvnode returned error %d\n", err);
1.1       rvb      2004:        }
                   2005:        vp->v_data = cp;
                   2006:        vp->v_type = type;
                   2007:        cp->c_vnode = vp;
1.3       rvb      2008:        coda_save(cp);
1.1       rvb      2009:
                   2010:     } else {
                   2011:        vref(CTOV(cp));
                   2012:     }
                   2013:
                   2014:     return cp;
                   2015: }

CVSweb <webmaster@jp.NetBSD.org>