Module Name: src Committed By: hannken Date: Sat Dec 13 15:59:30 UTC 2014
Modified Files: src/sys/coda: cnode.h coda_subr.c coda_vfsops.c coda_vfsops.h coda_vnops.c Log Message: Change coda from hashlist to vcache. - Replace all hash list crawlers with vfs_vnode_iterator. To generate a diff of this commit: cvs rdiff -u -r1.19 -r1.20 src/sys/coda/cnode.h cvs rdiff -u -r1.29 -r1.30 src/sys/coda/coda_subr.c cvs rdiff -u -r1.83 -r1.84 src/sys/coda/coda_vfsops.c cvs rdiff -u -r1.18 -r1.19 src/sys/coda/coda_vfsops.h cvs rdiff -u -r1.100 -r1.101 src/sys/coda/coda_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/coda/cnode.h diff -u src/sys/coda/cnode.h:1.19 src/sys/coda/cnode.h:1.20 --- src/sys/coda/cnode.h:1.19 Sat Dec 13 15:58:13 2014 +++ src/sys/coda/cnode.h Sat Dec 13 15:59:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: cnode.h,v 1.19 2014/12/13 15:58:13 hannken Exp $ */ +/* $NetBSD: cnode.h,v 1.20 2014/12/13 15:59:30 hannken Exp $ */ /* * @@ -106,7 +106,7 @@ struct cnode { u_short c_symlen; /* length of symbolic link */ dev_t c_device; /* associated vnode device */ ino_t c_inode; /* associated vnode inode */ - struct cnode *c_next; /* links if on NetBSD machine */ + kmutex_t c_lock; }; #define VTOC(vp) ((struct cnode *)(vp)->v_data) #define SET_VTOC(vp) ((vp)->v_data) Index: src/sys/coda/coda_subr.c diff -u src/sys/coda/coda_subr.c:1.29 src/sys/coda/coda_subr.c:1.30 --- src/sys/coda/coda_subr.c:1.29 Sat Dec 13 15:58:39 2014 +++ src/sys/coda/coda_subr.c Sat Dec 13 15:59:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: coda_subr.c,v 1.29 2014/12/13 15:58:39 hannken Exp $ */ +/* $NetBSD: coda_subr.c,v 1.30 2014/12/13 15:59:30 hannken Exp $ */ /* * @@ -55,7 +55,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: coda_subr.c,v 1.29 2014/12/13 15:58:39 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: coda_subr.c,v 1.30 2014/12/13 15:59:30 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -70,22 +70,11 @@ __KERNEL_RCSID(0, "$NetBSD: coda_subr.c, #include <coda/coda_subr.h> #include <coda/coda_namecache.h> - -int coda_active = 0; -int coda_reuse = 0; -int coda_new = 0; - -struct cnode *coda_freelist = NULL; -struct cnode *coda_cache[CODA_CACHESIZE]; -MALLOC_DEFINE(M_CODA, "coda", "Coda file system structures and tables"); - int codadebug = 0; int coda_printf_delay = 0; /* in microseconds */ int coda_vnop_print_entry = 0; int coda_vfsop_print_entry = 0; -#define CNODE_NEXT(cp) ((cp)->c_next) - #ifdef CODA_COMPAT_5 #define coda_hash(fid) \ (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1)) @@ -99,99 +88,56 @@ int coda_vfsop_print_entry = 0; struct vnode *coda_ctlvp; /* - * Allocate a cnode. + * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it. + * The cnode is returned locked with the vnode referenced. */ struct cnode * -coda_alloc(void) +coda_find(CodaFid *fid) { - struct cnode *cp; - - if (coda_freelist) { - cp = coda_freelist; - coda_freelist = CNODE_NEXT(cp); - coda_reuse++; - } - else { - CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode)); - /* NetBSD vnodes don't have any Pager info in them ('cause there are - no external pagers, duh!) */ -#define VNODE_VM_INFO_INIT(vp) /* MT */ - VNODE_VM_INFO_INIT(CTOV(cp)); - coda_new++; - } - memset(cp, 0, sizeof (struct cnode)); + int i; + struct vnode *vp; + struct cnode *cp; - return(cp); -} + for (i = 0; i < NVCODA; i++) { + if (!coda_mnttbl[i].mi_started) + continue; + if (vcache_get(coda_mnttbl[i].mi_vfsp, + fid, sizeof(CodaFid), &vp) != 0) + continue; + mutex_enter(vp->v_interlock); + cp = VTOC(vp); + if (vp->v_type == VNON || cp == NULL || IS_UNMOUNTING(cp)) { + mutex_exit(vp->v_interlock); + vrele(vp); + continue; + } + mutex_enter(&cp->c_lock); + mutex_exit(vp->v_interlock); -/* - * Deallocate a cnode. - */ -void -coda_free(struct cnode *cp) -{ + return cp; + } - CNODE_NEXT(cp) = coda_freelist; - coda_freelist = cp; + return NULL; } /* - * Put a cnode in the hash table + * Iterate over all nodes attached to coda mounts. */ -void -coda_save(struct cnode *cp) +static void +coda_iterate(bool (*f)(void *, struct vnode *), void *cl) { - CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)]; - coda_cache[coda_hash(&cp->c_fid)] = cp; -} - -/* - * Remove a cnode from the hash table - */ -void -coda_unsave(struct cnode *cp) -{ - struct cnode *ptr; - struct cnode *ptrprev = NULL; - - ptr = coda_cache[coda_hash(&cp->c_fid)]; - while (ptr != NULL) { - if (ptr == cp) { - if (ptrprev == NULL) { - coda_cache[coda_hash(&cp->c_fid)] - = CNODE_NEXT(ptr); - } else { - CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr); - } - CNODE_NEXT(cp) = NULL; + int i; + struct vnode_iterator *marker; + struct vnode *vp; - return; + for (i = 0; i < NVCODA; i++) { + if (coda_mnttbl[i].mi_vfsp == NULL) + continue; + vfs_vnode_iterator_init(coda_mnttbl[i].mi_vfsp, &marker); + while ((vp = vfs_vnode_iterator_next(marker, f, cl)) != NULL) + vrele(vp); + vfs_vnode_iterator_destroy(marker); } - ptrprev = ptr; - ptr = CNODE_NEXT(ptr); - } -} - -/* - * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it. - * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95 - */ -struct cnode * -coda_find(CodaFid *fid) -{ - struct cnode *cp; - - cp = coda_cache[coda_hash(fid)]; - while (cp) { - if (coda_fid_eq(&(cp->c_fid), fid) && - (!IS_UNMOUNTING(cp))) - { - coda_active++; - return(cp); - } - cp = CNODE_NEXT(cp); - } - return(NULL); } /* @@ -203,19 +149,25 @@ coda_find(CodaFid *fid) * running, only kill the cnodes for a particular entry in the * coda_mnttbl. -- DCS 12/1/94 */ +static bool +coda_kill_selector(void *cl, struct vnode *vp) +{ + int *count = cl; + + (*count)++; + + return false; +} + int coda_kill(struct mount *whoIam, enum dc_status dcstat) { - int hash, count = 0; - struct cnode *cp; + int count = 0; + struct vnode_iterator *marker; /* * Algorithm is as follows: * Second, flush whatever vnodes we can from the name cache. - * - * Finally, step through whatever is left and mark them dying. - * This prevents any operation at all. - */ /* This is slightly overkill, but should work. Eventually it'd be @@ -223,23 +175,11 @@ coda_kill(struct mount *whoIam, enum dc_ * reference a vnode in this vfs. */ coda_nc_flush(dcstat); - for (hash = 0; hash < CODA_CACHESIZE; hash++) { - for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { - if (IS_CTL_VP(CTOV(cp))) - continue; - if (CTOV(cp)->v_mount == whoIam) { -#ifdef DEBUG - printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp); -#endif - count++; - CODADEBUG(CODA_FLUSH, - myprintf(("Live cnode fid %s flags %d count %d\n", - coda_f2s(&cp->c_fid), - cp->c_flags, - CTOV(cp)->v_usecount)); ); - } - } - } + + vfs_vnode_iterator_init(whoIam, &marker); + vfs_vnode_iterator_next(marker, coda_kill_selector, &count); + vfs_vnode_iterator_destroy(marker); + return count; } @@ -247,43 +187,48 @@ coda_kill(struct mount *whoIam, enum dc_ * There are two reasons why a cnode may be in use, it may be in the * name cache or it may be executing. */ +static bool +coda_flush_selector(void *cl, struct vnode *vp) +{ + struct cnode *cp = VTOC(vp); + + if (cp != NULL && !IS_DIR(cp->c_fid)) /* only files can be executed */ + coda_vmflush(cp); + + return false; +} void coda_flush(enum dc_status dcstat) { - int hash; - struct cnode *cp; coda_clstat.ncalls++; coda_clstat.reqs[CODA_FLUSH]++; coda_nc_flush(dcstat); /* flush files from the name cache */ - for (hash = 0; hash < CODA_CACHESIZE; hash++) { - for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { - if (!IS_DIR(cp->c_fid)) /* only files can be executed */ - coda_vmflush(cp); - } - } + coda_iterate(coda_flush_selector, NULL); } /* * As a debugging measure, print out any cnodes that lived through a * name cache flush. */ +static bool +coda_testflush_selector(void *cl, struct vnode *vp) +{ + struct cnode *cp = VTOC(vp); + + if (cp != NULL) + myprintf(("Live cnode fid %s count %d\n", + coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount)); + + return false; +} void coda_testflush(void) { - int hash; - struct cnode *cp; - for (hash = 0; hash < CODA_CACHESIZE; hash++) { - for (cp = coda_cache[hash]; - cp != NULL; - cp = CNODE_NEXT(cp)) { - myprintf(("Live cnode fid %s count %d\n", - coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount)); - } - } + coda_iterate(coda_testflush_selector, NULL); } /* @@ -292,62 +237,66 @@ coda_testflush(void) * is dead, which would be a bad thing. * */ +static bool +coda_unmounting_selector(void *cl, struct vnode *vp) +{ + struct cnode *cp = VTOC(vp); + + if (cp) + cp->c_flags |= C_UNMOUNTING; + + return false; +} void coda_unmounting(struct mount *whoIam) { - int hash; - struct cnode *cp; + struct vnode_iterator *marker; - for (hash = 0; hash < CODA_CACHESIZE; hash++) { - for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { - if (CTOV(cp)->v_mount == whoIam) { - cp->c_flags |= C_UNMOUNTING; - } - } - } + vfs_vnode_iterator_init(whoIam, &marker); + vfs_vnode_iterator_next(marker, coda_unmounting_selector, NULL); + vfs_vnode_iterator_destroy(marker); } #ifdef DEBUG +static bool +coda_checkunmounting_selector(void *cl, struct vnode *vp) +{ + struct cnode *cp = VTOC(vp); + + if (cp && !(cp->c_flags & C_UNMOUNTING)) { + printf("vp %p, cp %p missed\n", vp, cp); + cp->c_flags |= C_UNMOUNTING; + } + + return false; +} void coda_checkunmounting(struct mount *mp) { - struct vnode *vp; - struct cnode *cp; - int count = 0, bad = 0; -loop: - TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { - if (vp->v_mount != mp) - goto loop; - cp = VTOC(vp); - count++; - if (!(cp->c_flags & C_UNMOUNTING)) { - bad++; - printf("vp %p, cp %p missed\n", vp, cp); - cp->c_flags |= C_UNMOUNTING; - } - } + struct vnode_iterator *marker; + + vfs_vnode_iterator_init(mp, &marker); + vfs_vnode_iterator_next(marker, coda_checkunmounting_selector, NULL); + vfs_vnode_iterator_destroy(marker); } void coda_cacheprint(struct mount *whoIam) { - int hash; - struct cnode *cp; + struct vnode *vp; + struct vnode_iterator *marker; int count = 0; printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp)); coda_nc_name(VTOC(coda_ctlvp)); printf("\n"); - for (hash = 0; hash < CODA_CACHESIZE; hash++) { - for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { - if (CTOV(cp)->v_mount == whoIam) { - printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp); - coda_nc_name(cp); - printf("\n"); - count++; - } - } + vfs_vnode_iterator_init(whoIam, &marker); + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL)) != NULL) { + printf("coda_cacheprint: vp %p, cp %p", vp, VTOC(vp)); + coda_nc_name(VTOC(vp)); + printf("\n"); + count++; } printf("coda_cacheprint: count %d\n", count); } @@ -414,8 +363,6 @@ int handleDownCall(int opcode, union out cp = coda_find(&out->coda_zapfile.Fid); if (cp != NULL) { - vref(CTOV(cp)); - cp->c_flags &= ~C_VATTR; if (CTOV(cp)->v_iflag & VI_TEXT) error = coda_vmflush(cp); @@ -425,6 +372,7 @@ int handleDownCall(int opcode, union out if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } + mutex_exit(&cp->c_lock); vrele(CTOV(cp)); } @@ -439,8 +387,6 @@ int handleDownCall(int opcode, union out cp = coda_find(&out->coda_zapdir.Fid); if (cp != NULL) { - vref(CTOV(cp)); - cp->c_flags &= ~C_VATTR; coda_nc_zapParentfid(&out->coda_zapdir.Fid, IS_DOWNCALL); @@ -450,6 +396,7 @@ int handleDownCall(int opcode, union out if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } + mutex_exit(&cp->c_lock); vrele(CTOV(cp)); } @@ -465,7 +412,6 @@ int handleDownCall(int opcode, union out cp = coda_find(&out->coda_purgefid.Fid); if (cp != NULL) { - vref(CTOV(cp)); if (IS_DIR(out->coda_purgefid.Fid)) { /* Vnode is a directory */ coda_nc_zapParentfid(&out->coda_purgefid.Fid, IS_DOWNCALL); @@ -483,6 +429,7 @@ int handleDownCall(int opcode, union out if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } + mutex_exit(&cp->c_lock); vrele(CTOV(cp)); } return(error); @@ -496,16 +443,24 @@ int handleDownCall(int opcode, union out cp = coda_find(&out->coda_replace.OldFid); if (cp != NULL) { - /* remove the cnode from the hash table, replace the fid, and reinsert */ - vref(CTOV(cp)); - coda_unsave(cp); + error = vcache_rekey_enter(CTOV(cp)->v_mount, CTOV(cp), + &out->coda_replace.OldFid, sizeof(CodaFid), + &out->coda_replace.NewFid, sizeof(CodaFid)); + if (error) { + mutex_exit(&cp->c_lock); + vrele(CTOV(cp)); + return error; + } cp->c_fid = out->coda_replace.NewFid; - coda_save(cp); + vcache_rekey_exit(CTOV(cp)->v_mount, CTOV(cp), + &out->coda_replace.OldFid, sizeof(CodaFid), + &cp->c_fid, sizeof(CodaFid)); CODADEBUG(CODA_REPLACE, myprintf(( "replace: oldfid = %s, newfid = %s, cp = %p\n", coda_f2s(&out->coda_replace.OldFid), coda_f2s(&cp->c_fid), cp));) + mutex_exit(&cp->c_lock); vrele(CTOV(cp)); } return (0); Index: src/sys/coda/coda_vfsops.c diff -u src/sys/coda/coda_vfsops.c:1.83 src/sys/coda/coda_vfsops.c:1.84 --- src/sys/coda/coda_vfsops.c:1.83 Sat Dec 13 15:58:39 2014 +++ src/sys/coda/coda_vfsops.c Sat Dec 13 15:59:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: coda_vfsops.c,v 1.83 2014/12/13 15:58:39 hannken Exp $ */ +/* $NetBSD: coda_vfsops.c,v 1.84 2014/12/13 15:59:30 hannken Exp $ */ /* * @@ -45,7 +45,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: coda_vfsops.c,v 1.83 2014/12/13 15:58:39 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: coda_vfsops.c,v 1.84 2014/12/13 15:59:30 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -106,6 +106,7 @@ struct vfsops coda_vfsops = { .vfs_statvfs = coda_nb_statvfs, .vfs_sync = coda_sync, .vfs_vget = coda_vget, + .vfs_loadvnode = coda_loadvnode, .vfs_fhtovp = (void *)eopnotsupp, .vfs_vptofh = (void *)eopnotsupp, .vfs_init = coda_init, @@ -371,13 +372,19 @@ coda_root(struct mount *vfsp, struct vno error = venus_root(vftomi(vfsp), l->l_cred, l->l_proc, &VFid); if (!error) { + struct cnode *cp = VTOC(mi->mi_rootvp); + /* - * Save the new rootfid in the cnode, and rehash the cnode into the - * cnode hash with the new fid key. + * Save the new rootfid in the cnode, and rekey the cnode + * with the new fid key. */ - coda_unsave(VTOC(mi->mi_rootvp)); - VTOC(mi->mi_rootvp)->c_fid = VFid; - coda_save(VTOC(mi->mi_rootvp)); + error = vcache_rekey_enter(vfsp, mi->mi_rootvp, + &invalfid, sizeof(CodaFid), &VFid, sizeof(CodaFid)); + if (error) + goto exit; + cp->c_fid = VFid; + vcache_rekey_exit(vfsp, mi->mi_rootvp, + &invalfid, sizeof(CodaFid), &cp->c_fid, sizeof(CodaFid)); *vpp = mi->mi_rootvp; vref(*vpp); @@ -475,6 +482,31 @@ coda_vget(struct mount *vfsp, ino_t ino, return (EOPNOTSUPP); } +int +coda_loadvnode(struct mount *mp, struct vnode *vp, + const void *key, size_t key_len, const void **new_key) +{ + CodaFid fid; + struct cnode *cp; + extern int (**coda_vnodeop_p)(void *); + + KASSERT(key_len == sizeof(CodaFid)); + memcpy(&fid, key, key_len); + + cp = kmem_zalloc(sizeof(*cp), KM_SLEEP); + mutex_init(&cp->c_lock, MUTEX_DEFAULT, IPL_NONE); + cp->c_fid = fid; + cp->c_vnode = vp; + vp->v_op = coda_vnodeop_p; + vp->v_tag = VT_CODA; + vp->v_type = VNON; + vp->v_data = cp; + + *new_key = &cp->c_fid; + + return 0; +} + /* * fhtovp is now what vget used to be in 4.3-derived systems. For * some silly reason, vget is now keyed by a 32 bit ino_t, rather than Index: src/sys/coda/coda_vfsops.h diff -u src/sys/coda/coda_vfsops.h:1.18 src/sys/coda/coda_vfsops.h:1.19 --- src/sys/coda/coda_vfsops.h:1.18 Mon Nov 26 19:01:28 2007 +++ src/sys/coda/coda_vfsops.h Sat Dec 13 15:59:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: coda_vfsops.h,v 1.18 2007/11/26 19:01:28 pooka Exp $ */ +/* $NetBSD: coda_vfsops.h,v 1.19 2014/12/13 15:59:30 hannken Exp $ */ /* * @@ -53,6 +53,8 @@ int coda_root(struct mount *, struct vno int coda_nb_statvfs(struct mount *, struct statvfs *); int coda_sync(struct mount *, int, kauth_cred_t); int coda_vget(struct mount *, ino_t, struct vnode **); +int coda_loadvnode(struct mount *, struct vnode *, const void *, size_t, + const void **); int coda_fhtovp(struct mount *, struct fid *, struct mbuf *, struct vnode **, int *, kauth_cred_t *); int coda_vptofh(struct vnode *, struct fid *); Index: src/sys/coda/coda_vnops.c diff -u src/sys/coda/coda_vnops.c:1.100 src/sys/coda/coda_vnops.c:1.101 --- src/sys/coda/coda_vnops.c:1.100 Sat Dec 13 15:59:03 2014 +++ src/sys/coda/coda_vnops.c Sat Dec 13 15:59:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: coda_vnops.c,v 1.100 2014/12/13 15:59:03 hannken Exp $ */ +/* $NetBSD: coda_vnops.c,v 1.101 2014/12/13 15:59:30 hannken Exp $ */ /* * @@ -46,7 +46,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: coda_vnops.c,v 1.100 2014/12/13 15:59:03 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: coda_vnops.c,v 1.101 2014/12/13 15:59:30 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -793,8 +793,8 @@ coda_fsync(void *v) return(ENODEV); } - /* Check for fsync of control object. */ - if (IS_CTL_VP(vp)) { + /* Check for fsync of control object or unitialized cnode. */ + if (IS_CTL_VP(vp) || vp->v_type == VNON) { MARK_INT_SAT(CODA_FSYNC_STATS); return(0); } @@ -1675,9 +1675,16 @@ coda_reclaim(void *v) } /* Remove it from the table so it can't be found. */ - coda_unsave(cp); - coda_free(VTOC(vp)); + vcache_remove(vp->v_mount, &cp->c_fid, sizeof(CodaFid)); + + mutex_enter(vp->v_interlock); + mutex_enter(&cp->c_lock); SET_VTOC(vp) = NULL; + mutex_exit(&cp->c_lock); + mutex_exit(vp->v_interlock); + mutex_destroy(&cp->c_lock); + kmem_free(cp, sizeof(*cp)); + return (0); } @@ -1830,32 +1837,30 @@ coda_print_vattr(struct vattr *attr) struct cnode * make_coda_node(CodaFid *fid, struct mount *fvsp, short type) { - struct cnode *cp; - int error; - - if ((cp = coda_find(fid)) == NULL) { - vnode_t *vp; - - cp = coda_alloc(); - cp->c_fid = *fid; - - error = getnewvnode(VT_CODA, fvsp, coda_vnodeop_p, NULL, &vp); - if (error) { - panic("%s: getnewvnode returned error %d", __func__, error); + int error __diagused; + struct vnode *vp; + struct cnode *cp; + + error = vcache_get(fvsp, fid, sizeof(CodaFid), &vp); + KASSERT(error == 0); + + mutex_enter(vp->v_interlock); + cp = VTOC(vp); + KASSERT(cp != NULL); + mutex_enter(&cp->c_lock); + mutex_exit(vp->v_interlock); + + if (vp->v_type != type) { + if (vp->v_type == VCHR || vp->v_type == VBLK) + spec_node_destroy(vp); + vp->v_type = type; + if (type == VCHR || type == VBLK) + spec_node_init(vp, NODEV); + uvm_vnp_setsize(vp, 0); } - vp->v_data = cp; - vp->v_type = type; - cp->c_vnode = vp; - if (type == VCHR || type == VBLK) - spec_node_init(vp, NODEV); - uvm_vnp_setsize(vp, 0); - coda_save(cp); - - } else { - vref(CTOV(cp)); - } + mutex_exit(&cp->c_lock); - return cp; + return cp; } /*