1*0a6a1f1dSLionel Sambuc /* $NetBSD: puffs_node.c,v 1.36 2014/11/10 18:46:33 maxv Exp $ */
284d9c625SLionel Sambuc
384d9c625SLionel Sambuc /*
484d9c625SLionel Sambuc * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
584d9c625SLionel Sambuc *
684d9c625SLionel Sambuc * Development of this software was supported by the
784d9c625SLionel Sambuc * Google Summer of Code program, the Ulla Tuominen Foundation
884d9c625SLionel Sambuc * and the Finnish Cultural Foundation.
984d9c625SLionel Sambuc *
1084d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
1184d9c625SLionel Sambuc * modification, are permitted provided that the following conditions
1284d9c625SLionel Sambuc * are met:
1384d9c625SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
1484d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1584d9c625SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
1684d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
1784d9c625SLionel Sambuc * documentation and/or other materials provided with the distribution.
1884d9c625SLionel Sambuc *
1984d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
2084d9c625SLionel Sambuc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2184d9c625SLionel Sambuc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2284d9c625SLionel Sambuc * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2384d9c625SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2484d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2584d9c625SLionel Sambuc * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2684d9c625SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2784d9c625SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2884d9c625SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2984d9c625SLionel Sambuc * SUCH DAMAGE.
3084d9c625SLionel Sambuc */
3184d9c625SLionel Sambuc
3284d9c625SLionel Sambuc #include <sys/cdefs.h>
33*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: puffs_node.c,v 1.36 2014/11/10 18:46:33 maxv Exp $");
3484d9c625SLionel Sambuc
3584d9c625SLionel Sambuc #include <sys/param.h>
3684d9c625SLionel Sambuc #include <sys/hash.h>
3784d9c625SLionel Sambuc #include <sys/kmem.h>
3884d9c625SLionel Sambuc #include <sys/mount.h>
3984d9c625SLionel Sambuc #include <sys/namei.h>
4084d9c625SLionel Sambuc #include <sys/vnode.h>
4184d9c625SLionel Sambuc
4284d9c625SLionel Sambuc #include <uvm/uvm.h>
4384d9c625SLionel Sambuc
4484d9c625SLionel Sambuc #include <fs/puffs/puffs_msgif.h>
4584d9c625SLionel Sambuc #include <fs/puffs/puffs_sys.h>
4684d9c625SLionel Sambuc
4784d9c625SLionel Sambuc #include <miscfs/genfs/genfs_node.h>
4884d9c625SLionel Sambuc #include <miscfs/specfs/specdev.h>
4984d9c625SLionel Sambuc
5084d9c625SLionel Sambuc struct pool puffs_pnpool;
5184d9c625SLionel Sambuc struct pool puffs_vapool;
5284d9c625SLionel Sambuc
5384d9c625SLionel Sambuc /*
5484d9c625SLionel Sambuc * Grab a vnode, intialize all the puffs-dependent stuff.
5584d9c625SLionel Sambuc */
56*0a6a1f1dSLionel Sambuc 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)57*0a6a1f1dSLionel Sambuc puffs_getvnode1(struct mount *mp, puffs_cookie_t ck, enum vtype type,
58*0a6a1f1dSLionel Sambuc voff_t vsize, dev_t rdev, bool may_exist, struct vnode **vpp)
5984d9c625SLionel Sambuc {
6084d9c625SLionel Sambuc struct puffs_mount *pmp;
6184d9c625SLionel Sambuc struct vnode *vp;
6284d9c625SLionel Sambuc struct puffs_node *pnode;
6384d9c625SLionel Sambuc int error;
6484d9c625SLionel Sambuc
6584d9c625SLionel Sambuc pmp = MPTOPUFFSMP(mp);
6684d9c625SLionel Sambuc
6784d9c625SLionel Sambuc if (type <= VNON || type >= VBAD) {
6884d9c625SLionel Sambuc puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL,
6984d9c625SLionel Sambuc "bad node type", ck);
70*0a6a1f1dSLionel Sambuc return EPROTO;
7184d9c625SLionel Sambuc }
7284d9c625SLionel Sambuc if (vsize == VSIZENOTSET) {
7384d9c625SLionel Sambuc puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL,
7484d9c625SLionel Sambuc "VSIZENOTSET is not a valid size", ck);
75*0a6a1f1dSLionel Sambuc return EPROTO;
7684d9c625SLionel Sambuc }
7784d9c625SLionel Sambuc
78*0a6a1f1dSLionel Sambuc for (;;) {
79*0a6a1f1dSLionel Sambuc error = vcache_get(mp, &ck, sizeof(ck), &vp);
80*0a6a1f1dSLionel Sambuc if (error)
81*0a6a1f1dSLionel Sambuc return error;
82*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
83*0a6a1f1dSLionel Sambuc pnode = VPTOPP(vp);
84*0a6a1f1dSLionel Sambuc if (pnode != NULL)
85*0a6a1f1dSLionel Sambuc break;
86*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
87*0a6a1f1dSLionel Sambuc vrele(vp);
8884d9c625SLionel Sambuc }
89*0a6a1f1dSLionel Sambuc mutex_enter(&pnode->pn_mtx);
90*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
91*0a6a1f1dSLionel Sambuc
92*0a6a1f1dSLionel Sambuc /*
93*0a6a1f1dSLionel Sambuc * Release and error out if caller wants a fresh vnode.
94*0a6a1f1dSLionel Sambuc */
95*0a6a1f1dSLionel Sambuc if (vp->v_type != VNON && ! may_exist) {
96*0a6a1f1dSLionel Sambuc mutex_exit(&pnode->pn_mtx);
97*0a6a1f1dSLionel Sambuc vrele(vp);
98*0a6a1f1dSLionel Sambuc return EEXIST;
99*0a6a1f1dSLionel Sambuc }
100*0a6a1f1dSLionel Sambuc
101*0a6a1f1dSLionel Sambuc *vpp = vp;
102*0a6a1f1dSLionel Sambuc
103*0a6a1f1dSLionel Sambuc /*
104*0a6a1f1dSLionel Sambuc * If fully initialized were done.
105*0a6a1f1dSLionel Sambuc */
106*0a6a1f1dSLionel Sambuc if (vp->v_type != VNON) {
107*0a6a1f1dSLionel Sambuc mutex_exit(&pnode->pn_mtx);
108*0a6a1f1dSLionel Sambuc return 0;
109*0a6a1f1dSLionel Sambuc }
110*0a6a1f1dSLionel Sambuc
111*0a6a1f1dSLionel Sambuc /*
112*0a6a1f1dSLionel Sambuc * Set type and finalize the initialisation.
113*0a6a1f1dSLionel Sambuc */
11484d9c625SLionel Sambuc vp->v_type = type;
115*0a6a1f1dSLionel Sambuc if (type == VCHR || type == VBLK) {
11684d9c625SLionel Sambuc vp->v_op = puffs_specop_p;
11784d9c625SLionel Sambuc spec_node_init(vp, rdev);
118*0a6a1f1dSLionel Sambuc } else if (type == VFIFO) {
11984d9c625SLionel Sambuc vp->v_op = puffs_fifoop_p;
120*0a6a1f1dSLionel Sambuc } else if (vp->v_type == VREG) {
12184d9c625SLionel Sambuc uvm_vnp_setsize(vp, vsize);
12284d9c625SLionel Sambuc }
12384d9c625SLionel Sambuc
12484d9c625SLionel Sambuc pnode->pn_serversize = vsize;
12584d9c625SLionel Sambuc
12684d9c625SLionel Sambuc DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
12784d9c625SLionel Sambuc pnode, pnode->pn_cookie));
12884d9c625SLionel Sambuc
129*0a6a1f1dSLionel Sambuc mutex_exit(&pnode->pn_mtx);
130*0a6a1f1dSLionel Sambuc
13184d9c625SLionel Sambuc return 0;
13284d9c625SLionel Sambuc }
13384d9c625SLionel Sambuc
134*0a6a1f1dSLionel Sambuc int
puffs_getvnode(struct mount * mp,puffs_cookie_t ck,enum vtype type,voff_t vsize,dev_t rdev,struct vnode ** vpp)135*0a6a1f1dSLionel Sambuc puffs_getvnode(struct mount *mp, puffs_cookie_t ck, enum vtype type,
136*0a6a1f1dSLionel Sambuc voff_t vsize, dev_t rdev, struct vnode **vpp)
137*0a6a1f1dSLionel Sambuc {
138*0a6a1f1dSLionel Sambuc
139*0a6a1f1dSLionel Sambuc return puffs_getvnode1(mp, ck, type, vsize, rdev, true, vpp);
14084d9c625SLionel Sambuc }
14184d9c625SLionel Sambuc
14284d9c625SLionel Sambuc /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
14384d9c625SLionel Sambuc int
puffs_newnode(struct mount * mp,struct vnode * dvp,struct vnode ** vpp,puffs_cookie_t ck,struct componentname * cnp,enum vtype type,dev_t rdev)14484d9c625SLionel Sambuc puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
14584d9c625SLionel Sambuc puffs_cookie_t ck, struct componentname *cnp,
14684d9c625SLionel Sambuc enum vtype type, dev_t rdev)
14784d9c625SLionel Sambuc {
14884d9c625SLionel Sambuc struct puffs_mount *pmp = MPTOPUFFSMP(mp);
14984d9c625SLionel Sambuc int error;
15084d9c625SLionel Sambuc
15184d9c625SLionel Sambuc /* userspace probably has this as a NULL op */
152*0a6a1f1dSLionel Sambuc if (ck == NULL)
153*0a6a1f1dSLionel Sambuc return EOPNOTSUPP;
15484d9c625SLionel Sambuc
15584d9c625SLionel Sambuc /*
15684d9c625SLionel Sambuc * Check for previous node with the same designation.
15784d9c625SLionel Sambuc * Explicitly check the root node cookie, since it might be
15884d9c625SLionel Sambuc * reclaimed from the kernel when this check is made.
15984d9c625SLionel Sambuc */
160*0a6a1f1dSLionel Sambuc if (ck == pmp->pmp_root_cookie) {
16184d9c625SLionel Sambuc puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST,
16284d9c625SLionel Sambuc "cookie exists", ck);
16384d9c625SLionel Sambuc return EPROTO;
16484d9c625SLionel Sambuc }
16584d9c625SLionel Sambuc
16684d9c625SLionel Sambuc KASSERT(curlwp != uvm.pagedaemon_lwp);
16784d9c625SLionel Sambuc
168*0a6a1f1dSLionel Sambuc error = puffs_getvnode1(dvp->v_mount, ck, type, 0, rdev, false, vpp);
169*0a6a1f1dSLionel Sambuc if (error) {
170*0a6a1f1dSLionel Sambuc if (error == EEXIST) {
171*0a6a1f1dSLionel Sambuc puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST,
172*0a6a1f1dSLionel Sambuc "cookie exists", ck);
173*0a6a1f1dSLionel Sambuc error = EPROTO;
174*0a6a1f1dSLionel Sambuc }
17584d9c625SLionel Sambuc return error;
176*0a6a1f1dSLionel Sambuc }
17784d9c625SLionel Sambuc
17884d9c625SLionel Sambuc if (PUFFS_USE_NAMECACHE(pmp))
179*0a6a1f1dSLionel Sambuc cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
18084d9c625SLionel Sambuc cnp->cn_flags);
18184d9c625SLionel Sambuc
182*0a6a1f1dSLionel Sambuc puffs_updatenode(VPTOPP(dvp), PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0);
183*0a6a1f1dSLionel Sambuc
18484d9c625SLionel Sambuc return 0;
18584d9c625SLionel Sambuc }
18684d9c625SLionel Sambuc
18784d9c625SLionel Sambuc void
puffs_putvnode(struct vnode * vp)18884d9c625SLionel Sambuc puffs_putvnode(struct vnode *vp)
18984d9c625SLionel Sambuc {
19084d9c625SLionel Sambuc struct puffs_node *pnode;
19184d9c625SLionel Sambuc
19284d9c625SLionel Sambuc pnode = VPTOPP(vp);
19384d9c625SLionel Sambuc
194*0a6a1f1dSLionel Sambuc KASSERT(vp->v_tag == VT_PUFFS);
19584d9c625SLionel Sambuc
196*0a6a1f1dSLionel Sambuc vcache_remove(vp->v_mount, &pnode->pn_cookie, sizeof(pnode->pn_cookie));
19784d9c625SLionel Sambuc genfs_node_destroy(vp);
19884d9c625SLionel Sambuc
19984d9c625SLionel Sambuc /*
200*0a6a1f1dSLionel Sambuc * To interlock with puffs_getvnode1().
20184d9c625SLionel Sambuc */
202*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
203*0a6a1f1dSLionel Sambuc vp->v_data = NULL;
204*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
205*0a6a1f1dSLionel Sambuc puffs_releasenode(pnode);
20684d9c625SLionel Sambuc }
20784d9c625SLionel Sambuc
20884d9c625SLionel Sambuc /*
20984d9c625SLionel Sambuc * Make sure root vnode exists and reference it. Does NOT lock.
21084d9c625SLionel Sambuc */
21184d9c625SLionel Sambuc static int
puffs_makeroot(struct puffs_mount * pmp)21284d9c625SLionel Sambuc puffs_makeroot(struct puffs_mount *pmp)
21384d9c625SLionel Sambuc {
21484d9c625SLionel Sambuc struct vnode *vp;
21584d9c625SLionel Sambuc int rv;
21684d9c625SLionel Sambuc
21784d9c625SLionel Sambuc /*
21884d9c625SLionel Sambuc * pmp_lock must be held if vref()'ing or vrele()'ing the
21984d9c625SLionel Sambuc * root vnode. the latter is controlled by puffs_inactive().
22084d9c625SLionel Sambuc *
22184d9c625SLionel Sambuc * pmp_root is set here and cleared in puffs_reclaim().
22284d9c625SLionel Sambuc */
22384d9c625SLionel Sambuc
224*0a6a1f1dSLionel Sambuc rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie,
225*0a6a1f1dSLionel Sambuc pmp->pmp_root_vtype, pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp);
226*0a6a1f1dSLionel Sambuc if (rv != 0)
22784d9c625SLionel Sambuc return rv;
22884d9c625SLionel Sambuc
22984d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
230*0a6a1f1dSLionel Sambuc if (pmp->pmp_root == NULL)
23184d9c625SLionel Sambuc pmp->pmp_root = vp;
23284d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
23384d9c625SLionel Sambuc
23484d9c625SLionel Sambuc return 0;
23584d9c625SLionel Sambuc }
23684d9c625SLionel Sambuc
23784d9c625SLionel Sambuc /*
23884d9c625SLionel Sambuc * Locate the in-kernel vnode based on the cookie received given
23984d9c625SLionel Sambuc * from userspace.
24084d9c625SLionel Sambuc *
24184d9c625SLionel Sambuc * returns 0 on success. otherwise returns an errno or PUFFS_NOSUCHCOOKIE.
24284d9c625SLionel Sambuc *
24384d9c625SLionel Sambuc * returns PUFFS_NOSUCHCOOKIE if no vnode for the cookie is found.
24484d9c625SLionel Sambuc */
24584d9c625SLionel Sambuc int
puffs_cookie2vnode(struct puffs_mount * pmp,puffs_cookie_t ck,struct vnode ** vpp)246*0a6a1f1dSLionel Sambuc puffs_cookie2vnode(struct puffs_mount *pmp, puffs_cookie_t ck,
247*0a6a1f1dSLionel Sambuc struct vnode **vpp)
24884d9c625SLionel Sambuc {
249*0a6a1f1dSLionel Sambuc int rv;
25084d9c625SLionel Sambuc
25184d9c625SLionel Sambuc /*
25284d9c625SLionel Sambuc * Handle root in a special manner, since we want to make sure
25384d9c625SLionel Sambuc * pmp_root is properly set.
25484d9c625SLionel Sambuc */
25584d9c625SLionel Sambuc if (ck == pmp->pmp_root_cookie) {
25684d9c625SLionel Sambuc if ((rv = puffs_makeroot(pmp)))
25784d9c625SLionel Sambuc return rv;
25884d9c625SLionel Sambuc *vpp = pmp->pmp_root;
25984d9c625SLionel Sambuc return 0;
26084d9c625SLionel Sambuc }
26184d9c625SLionel Sambuc
262*0a6a1f1dSLionel Sambuc rv = vcache_get(PMPTOMP(pmp), &ck, sizeof(ck), vpp);
263*0a6a1f1dSLionel Sambuc if (rv != 0)
264*0a6a1f1dSLionel Sambuc return rv;
265*0a6a1f1dSLionel Sambuc mutex_enter((*vpp)->v_interlock);
266*0a6a1f1dSLionel Sambuc if ((*vpp)->v_type == VNON) {
267*0a6a1f1dSLionel Sambuc mutex_exit((*vpp)->v_interlock);
268*0a6a1f1dSLionel Sambuc /* XXX vrele() calls VOP_INACTIVE() with VNON node */
269*0a6a1f1dSLionel Sambuc vrele(*vpp);
270*0a6a1f1dSLionel Sambuc *vpp = NULL;
27184d9c625SLionel Sambuc return PUFFS_NOSUCHCOOKIE;
27284d9c625SLionel Sambuc }
273*0a6a1f1dSLionel Sambuc mutex_exit((*vpp)->v_interlock);
27484d9c625SLionel Sambuc
27584d9c625SLionel Sambuc return 0;
27684d9c625SLionel Sambuc }
27784d9c625SLionel Sambuc
27884d9c625SLionel Sambuc void
puffs_updatenode(struct puffs_node * pn,int flags,voff_t size)27984d9c625SLionel Sambuc puffs_updatenode(struct puffs_node *pn, int flags, voff_t size)
28084d9c625SLionel Sambuc {
28184d9c625SLionel Sambuc struct timespec ts;
28284d9c625SLionel Sambuc
28384d9c625SLionel Sambuc if (flags == 0)
28484d9c625SLionel Sambuc return;
28584d9c625SLionel Sambuc
28684d9c625SLionel Sambuc nanotime(&ts);
28784d9c625SLionel Sambuc
28884d9c625SLionel Sambuc if (flags & PUFFS_UPDATEATIME) {
28984d9c625SLionel Sambuc pn->pn_mc_atime = ts;
29084d9c625SLionel Sambuc pn->pn_stat |= PNODE_METACACHE_ATIME;
29184d9c625SLionel Sambuc }
29284d9c625SLionel Sambuc if (flags & PUFFS_UPDATECTIME) {
29384d9c625SLionel Sambuc pn->pn_mc_ctime = ts;
29484d9c625SLionel Sambuc pn->pn_stat |= PNODE_METACACHE_CTIME;
29584d9c625SLionel Sambuc }
29684d9c625SLionel Sambuc if (flags & PUFFS_UPDATEMTIME) {
29784d9c625SLionel Sambuc pn->pn_mc_mtime = ts;
29884d9c625SLionel Sambuc pn->pn_stat |= PNODE_METACACHE_MTIME;
29984d9c625SLionel Sambuc }
30084d9c625SLionel Sambuc if (flags & PUFFS_UPDATESIZE) {
30184d9c625SLionel Sambuc pn->pn_mc_size = size;
30284d9c625SLionel Sambuc pn->pn_stat |= PNODE_METACACHE_SIZE;
30384d9c625SLionel Sambuc }
30484d9c625SLionel Sambuc }
30584d9c625SLionel Sambuc
30684d9c625SLionel Sambuc /*
30784d9c625SLionel Sambuc * Add reference to node.
30884d9c625SLionel Sambuc * mutex held on entry and return
30984d9c625SLionel Sambuc */
31084d9c625SLionel Sambuc void
puffs_referencenode(struct puffs_node * pn)31184d9c625SLionel Sambuc puffs_referencenode(struct puffs_node *pn)
31284d9c625SLionel Sambuc {
31384d9c625SLionel Sambuc
31484d9c625SLionel Sambuc KASSERT(mutex_owned(&pn->pn_mtx));
31584d9c625SLionel Sambuc pn->pn_refcount++;
31684d9c625SLionel Sambuc }
31784d9c625SLionel Sambuc
31884d9c625SLionel Sambuc /*
31984d9c625SLionel Sambuc * Release pnode structure which dealing with references to the
32084d9c625SLionel Sambuc * puffs_node instead of the vnode. Can't use vref()/vrele() on
32184d9c625SLionel Sambuc * the vnode there, since that causes the lovely VOP_INACTIVE(),
32284d9c625SLionel Sambuc * which in turn causes the lovely deadlock when called by the one
32384d9c625SLionel Sambuc * who is supposed to handle it.
32484d9c625SLionel Sambuc */
32584d9c625SLionel Sambuc void
puffs_releasenode(struct puffs_node * pn)32684d9c625SLionel Sambuc puffs_releasenode(struct puffs_node *pn)
32784d9c625SLionel Sambuc {
32884d9c625SLionel Sambuc
32984d9c625SLionel Sambuc mutex_enter(&pn->pn_mtx);
33084d9c625SLionel Sambuc if (--pn->pn_refcount == 0) {
33184d9c625SLionel Sambuc mutex_exit(&pn->pn_mtx);
33284d9c625SLionel Sambuc mutex_destroy(&pn->pn_mtx);
33384d9c625SLionel Sambuc mutex_destroy(&pn->pn_sizemtx);
33484d9c625SLionel Sambuc seldestroy(&pn->pn_sel);
33584d9c625SLionel Sambuc if (pn->pn_va_cache != NULL)
33684d9c625SLionel Sambuc pool_put(&puffs_vapool, pn->pn_va_cache);
33784d9c625SLionel Sambuc pool_put(&puffs_pnpool, pn);
33884d9c625SLionel Sambuc } else {
33984d9c625SLionel Sambuc mutex_exit(&pn->pn_mtx);
34084d9c625SLionel Sambuc }
34184d9c625SLionel Sambuc }
342