Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/fs/puffs/puffs_node.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/fs/puffs/puffs_node.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.31 retrieving revision 1.31.4.3 diff -u -p -r1.31 -r1.31.4.3 --- src/sys/fs/puffs/puffs_node.c 2014/01/23 10:13:56 1.31 +++ src/sys/fs/puffs/puffs_node.c 2014/09/30 18:14:22 1.31.4.3 @@ -1,4 +1,4 @@ -/* $NetBSD: puffs_node.c,v 1.31 2014/01/23 10:13:56 hannken Exp $ */ +/* $NetBSD: puffs_node.c,v 1.31.4.3 2014/09/30 18:14:22 martin Exp $ */ /* * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. @@ -30,7 +30,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: puffs_node.c,v 1.31 2014/01/23 10:13:56 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: puffs_node.c,v 1.31.4.3 2014/09/30 18:14:22 martin Exp $"); #include #include @@ -48,148 +48,96 @@ __KERNEL_RCSID(0, "$NetBSD: puffs_node.c #include #include -static const struct genfs_ops puffs_genfsops = { - .gop_size = puffs_gop_size, - .gop_write = genfs_gop_write, - .gop_markupdate = puffs_gop_markupdate, -#if 0 - .gop_alloc, should ask userspace -#endif -}; - -static __inline struct puffs_node_hashlist - *puffs_cookie2hashlist(struct puffs_mount *, puffs_cookie_t); -static struct puffs_node *puffs_cookie2pnode(struct puffs_mount *, - puffs_cookie_t); - struct pool puffs_pnpool; struct pool puffs_vapool; /* * Grab a vnode, intialize all the puffs-dependent stuff. */ -int -puffs_getvnode(struct mount *mp, puffs_cookie_t ck, enum vtype type, - voff_t vsize, dev_t rdev, struct vnode **vpp) +static int +puffs_getvnode1(struct mount *mp, puffs_cookie_t ck, enum vtype type, + voff_t vsize, dev_t rdev, bool may_exist, struct vnode **vpp) { struct puffs_mount *pmp; - struct puffs_newcookie *pnc; struct vnode *vp; struct puffs_node *pnode; - struct puffs_node_hashlist *plist; int error; pmp = MPTOPUFFSMP(mp); - error = EPROTO; if (type <= VNON || type >= VBAD) { puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL, "bad node type", ck); - goto bad; + return EPROTO; } if (vsize == VSIZENOTSET) { puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL, "VSIZENOTSET is not a valid size", ck); - goto bad; + return EPROTO; } - error = getnewvnode(VT_PUFFS, mp, puffs_vnodeop_p, NULL, &vp); - if (error) { - goto bad; + for (;;) { + error = vcache_get(mp, &ck, sizeof(ck), &vp); + if (error) + return error; + mutex_enter(vp->v_interlock); + pnode = VPTOPP(vp); + if (pnode != NULL) + break; + mutex_exit(vp->v_interlock); + vrele(vp); } - vp->v_type = type; + mutex_enter(&pnode->pn_mtx); + mutex_exit(vp->v_interlock); /* - * Creation should not fail after this point. Or if it does, - * care must be taken so that VOP_INACTIVE() isn't called. + * Release and error out if caller wants a fresh vnode. */ + if (vp->v_type != VNON && ! may_exist) { + mutex_exit(&pnode->pn_mtx); + vrele(vp); + return EEXIST; + } - /* default size */ - uvm_vnp_setsize(vp, 0); + *vpp = vp; - /* dances based on vnode type. almost ufs_vinit(), but not quite */ - switch (type) { - case VCHR: - case VBLK: - /* - * replace vnode operation vector with the specops vector. - * our user server has very little control over the node - * if it decides its a character or block special file - */ + /* + * If fully initialized were done. + */ + if (vp->v_type != VNON) { + mutex_exit(&pnode->pn_mtx); + return 0; + } + + /* + * Set type and finalize the initialisation. + */ + vp->v_type = type; + if (type == VCHR || type == VBLK) { vp->v_op = puffs_specop_p; spec_node_init(vp, rdev); - break; - - case VFIFO: + } else if (type == VFIFO) { vp->v_op = puffs_fifoop_p; - break; - - case VREG: + } else if (vp->v_type == VREG) { uvm_vnp_setsize(vp, vsize); - break; - - case VDIR: - case VLNK: - case VSOCK: - break; - default: - panic("puffs_getvnode: invalid vtype %d", type); - } - - pnode = pool_get(&puffs_pnpool, PR_WAITOK); - memset(pnode, 0, sizeof(struct puffs_node)); - - pnode->pn_cookie = ck; - pnode->pn_refcount = 1; - - /* insert cookie on list, take off of interlock list */ - mutex_init(&pnode->pn_mtx, MUTEX_DEFAULT, IPL_NONE); - selinit(&pnode->pn_sel); - plist = puffs_cookie2hashlist(pmp, ck); - mutex_enter(&pmp->pmp_lock); - LIST_INSERT_HEAD(plist, pnode, pn_hashent); - if (ck != pmp->pmp_root_cookie) { - LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) { - if (pnc->pnc_cookie == ck) { - LIST_REMOVE(pnc, pnc_entries); - kmem_free(pnc, sizeof(struct puffs_newcookie)); - break; - } - } - KASSERT(pnc != NULL); } - mutex_init(&pnode->pn_sizemtx, MUTEX_DEFAULT, IPL_NONE); - mutex_exit(&pmp->pmp_lock); - vp->v_data = pnode; - vp->v_type = type; - pnode->pn_vp = vp; pnode->pn_serversize = vsize; - genfs_node_init(vp, &puffs_genfsops); - *vpp = vp; - DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp, pnode, pnode->pn_cookie)); + mutex_exit(&pnode->pn_mtx); + return 0; +} - bad: - /* remove staging cookie from list */ - if (ck != pmp->pmp_root_cookie) { - mutex_enter(&pmp->pmp_lock); - LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) { - if (pnc->pnc_cookie == ck) { - LIST_REMOVE(pnc, pnc_entries); - kmem_free(pnc, sizeof(struct puffs_newcookie)); - break; - } - } - KASSERT(pnc != NULL); - mutex_exit(&pmp->pmp_lock); - } +int +puffs_getvnode(struct mount *mp, puffs_cookie_t ck, enum vtype type, + voff_t vsize, dev_t rdev, struct vnode **vpp) +{ - return error; + return puffs_getvnode1(mp, ck, type, vsize, rdev, true, vpp); } /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */ @@ -199,56 +147,41 @@ puffs_newnode(struct mount *mp, struct v enum vtype type, dev_t rdev) { struct puffs_mount *pmp = MPTOPUFFSMP(mp); - struct puffs_newcookie *pnc; - struct vnode *vp; int error; /* userspace probably has this as a NULL op */ - if (ck == NULL) { - error = EOPNOTSUPP; - return error; - } + if (ck == NULL) + return EOPNOTSUPP; /* * Check for previous node with the same designation. * Explicitly check the root node cookie, since it might be * reclaimed from the kernel when this check is made. */ - mutex_enter(&pmp->pmp_lock); - if (ck == pmp->pmp_root_cookie - || puffs_cookie2pnode(pmp, ck) != NULL) { - mutex_exit(&pmp->pmp_lock); + if (ck == pmp->pmp_root_cookie) { puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST, "cookie exists", ck); return EPROTO; } - LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) { - if (pnc->pnc_cookie == ck) { - mutex_exit(&pmp->pmp_lock); - puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST, - "newcookie exists", ck); - return EPROTO; - } - } - KASSERT(curlwp != uvm.pagedaemon_lwp); - pnc = kmem_alloc(sizeof(struct puffs_newcookie), KM_SLEEP); - pnc->pnc_cookie = ck; - LIST_INSERT_HEAD(&pmp->pmp_newcookie, pnc, pnc_entries); - mutex_exit(&pmp->pmp_lock); - error = puffs_getvnode(dvp->v_mount, ck, type, 0, rdev, &vp); - if (error) + error = puffs_getvnode1(dvp->v_mount, ck, type, 0, rdev, false, vpp); + if (error) { + if (error == EEXIST) { + puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST, + "cookie exists", ck); + error = EPROTO; + } return error; - - vp->v_type = type; - *vpp = vp; + } if (PUFFS_USE_NAMECACHE(pmp)) - cache_enter(dvp, vp, cnp->cn_nameptr, cnp->cn_namelen, + cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); + puffs_updatenode(VPTOPP(dvp), PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0); + return 0; } @@ -259,44 +192,18 @@ puffs_putvnode(struct vnode *vp) pnode = VPTOPP(vp); -#ifdef DIAGNOSTIC - if (vp->v_tag != VT_PUFFS) - panic("puffs_putvnode: %p not a puffs vnode", vp); -#endif + KASSERT(vp->v_tag == VT_PUFFS); + vcache_remove(vp->v_mount, &pnode->pn_cookie, sizeof(pnode->pn_cookie)); genfs_node_destroy(vp); - puffs_releasenode(pnode); + + /* + * To interlock with puffs_getvnode1(). + */ + mutex_enter(vp->v_interlock); vp->v_data = NULL; - - return; -} - -static __inline struct puffs_node_hashlist * -puffs_cookie2hashlist(struct puffs_mount *pmp, puffs_cookie_t ck) -{ - uint32_t hash; - - hash = hash32_buf(&ck, sizeof(ck), HASH32_BUF_INIT); - return &pmp->pmp_pnodehash[hash % pmp->pmp_npnodehash]; -} - -/* - * Translate cookie to puffs_node. Caller must hold pmp_lock - * and it will be held upon return. - */ -static struct puffs_node * -puffs_cookie2pnode(struct puffs_mount *pmp, puffs_cookie_t ck) -{ - struct puffs_node_hashlist *plist; - struct puffs_node *pnode; - - plist = puffs_cookie2hashlist(pmp, ck); - LIST_FOREACH(pnode, plist, pn_hashent) { - if (pnode->pn_cookie == ck) - break; - } - - return pnode; + mutex_exit(vp->v_interlock); + puffs_releasenode(pnode); } /* @@ -314,48 +221,15 @@ puffs_makeroot(struct puffs_mount *pmp) * * pmp_root is set here and cleared in puffs_reclaim(). */ - retry: - mutex_enter(&pmp->pmp_lock); - vp = pmp->pmp_root; - if (vp) { - mutex_enter(vp->v_interlock); - mutex_exit(&pmp->pmp_lock); - switch (vget(vp, 0)) { - case ENOENT: - goto retry; - case 0: - return 0; - default: - break; - } - } else - mutex_exit(&pmp->pmp_lock); - /* - * So, didn't have the magic root vnode available. - * No matter, grab another and stuff it with the cookie. - */ - if ((rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie, - pmp->pmp_root_vtype, pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp))) + rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie, + pmp->pmp_root_vtype, pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp); + if (rv != 0) return rv; - /* - * Someone magically managed to race us into puffs_getvnode? - * Put our previous new vnode back and retry. - */ mutex_enter(&pmp->pmp_lock); - if (pmp->pmp_root) { - struct puffs_node *pnode = vp->v_data; - - LIST_REMOVE(pnode, pn_hashent); - mutex_exit(&pmp->pmp_lock); - puffs_putvnode(vp); - goto retry; - } - - /* store cache */ - vp->v_vflag |= VV_ROOT; - pmp->pmp_root = vp; + if (pmp->pmp_root == NULL) + pmp->pmp_root = vp; mutex_exit(&pmp->pmp_lock); return 0; @@ -364,26 +238,16 @@ puffs_makeroot(struct puffs_mount *pmp) /* * Locate the in-kernel vnode based on the cookie received given * from userspace. - * The parameter "lock" control whether to lock the possible or - * not. Locking always might cause us to lock against ourselves - * in situations where we want the vnode but don't care for the - * vnode lock, e.g. file server issued putpages. * * returns 0 on success. otherwise returns an errno or PUFFS_NOSUCHCOOKIE. * * returns PUFFS_NOSUCHCOOKIE if no vnode for the cookie is found. - * in that case, if willcreate=true, the pmp_newcookie list is populated with - * the given cookie. it's the caller's responsibility to consume the entry - * with calling puffs_getvnode. */ int -puffs_cookie2vnode(struct puffs_mount *pmp, puffs_cookie_t ck, int lock, - int willcreate, struct vnode **vpp) +puffs_cookie2vnode(struct puffs_mount *pmp, puffs_cookie_t ck, + struct vnode **vpp) { - struct puffs_node *pnode; - struct puffs_newcookie *pnc; - struct vnode *vp; - int vgetflags, rv; + int rv; /* * Handle root in a special manner, since we want to make sure @@ -392,43 +256,22 @@ puffs_cookie2vnode(struct puffs_mount *p if (ck == pmp->pmp_root_cookie) { if ((rv = puffs_makeroot(pmp))) return rv; - if (lock) - vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY); - *vpp = pmp->pmp_root; return 0; } - retry: - mutex_enter(&pmp->pmp_lock); - pnode = puffs_cookie2pnode(pmp, ck); - if (pnode == NULL) { - if (willcreate) { - pnc = kmem_alloc(sizeof(struct puffs_newcookie), - KM_SLEEP); - pnc->pnc_cookie = ck; - LIST_INSERT_HEAD(&pmp->pmp_newcookie, pnc, pnc_entries); - } - mutex_exit(&pmp->pmp_lock); - return PUFFS_NOSUCHCOOKIE; - } - vp = pnode->pn_vp; - mutex_enter(vp->v_interlock); - mutex_exit(&pmp->pmp_lock); - - vgetflags = 0; - if (lock) - vgetflags |= LK_EXCLUSIVE; - switch (rv = vget(vp, vgetflags)) { - case ENOENT: - goto retry; - case 0: - break; - default: + rv = vcache_get(PMPTOMP(pmp), &ck, sizeof(ck), vpp); + if (rv != 0) return rv; + mutex_enter((*vpp)->v_interlock); + if ((*vpp)->v_type == VNON) { + mutex_exit((*vpp)->v_interlock); + vrele(*vpp); + *vpp = NULL; + return PUFFS_NOSUCHCOOKIE; } + mutex_exit((*vpp)->v_interlock); - *vpp = vp; return 0; }