Annotation of src/sys/fs/puffs/puffs_subr.c, Revision 1.39
1.39 ! pooka 1: /* $NetBSD: puffs_subr.c,v 1.38 2007/07/01 22:54:16 pooka Exp $ */
1.1 pooka 2:
3: /*
4: * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
5: *
6: * Development of this software was supported by the
7: * Google Summer of Code program and the Ulla Tuominen Foundation.
8: * The Google SoC project was mentored by Bill Studenmund.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: #include <sys/cdefs.h>
1.39 ! pooka 33: __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.38 2007/07/01 22:54:16 pooka Exp $");
1.1 pooka 34:
35: #include <sys/param.h>
36: #include <sys/conf.h>
1.16 pooka 37: #include <sys/hash.h>
1.31 pooka 38: #include <sys/kauth.h>
1.1 pooka 39: #include <sys/malloc.h>
40: #include <sys/mount.h>
1.31 pooka 41: #include <sys/namei.h>
42: #include <sys/poll.h>
1.1 pooka 43: #include <sys/socketvar.h>
44: #include <sys/vnode.h>
45:
46: #include <fs/puffs/puffs_msgif.h>
47: #include <fs/puffs/puffs_sys.h>
48:
1.7 pooka 49: #include <miscfs/genfs/genfs_node.h>
1.4 pooka 50: #include <miscfs/specfs/specdev.h>
51:
1.26 pooka 52: struct pool puffs_pnpool;
1.1 pooka 53:
1.19 pooka 54: #ifdef PUFFSDEBUG
1.10 pooka 55: int puffsdebug;
56: #endif
57:
1.16 pooka 58: static __inline struct puffs_node_hashlist
59: *puffs_cookie2hashlist(struct puffs_mount *, void *);
60: static struct puffs_node *puffs_cookie2pnode(struct puffs_mount *, void *);
1.7 pooka 61:
62: static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
63: static void puffs_gop_markupdate(struct vnode *, int);
64:
65: static const struct genfs_ops puffs_genfsops = {
66: .gop_size = puffs_gop_size,
67: .gop_write = genfs_gop_write,
68: .gop_markupdate = puffs_gop_markupdate,
69: #if 0
70: .gop_alloc, should ask userspace
71: #endif
72: };
73:
1.1 pooka 74: /*
75: * Grab a vnode, intialize all the puffs-dependant stuff.
76: */
77: int
1.4 pooka 78: puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
1.7 pooka 79: voff_t vsize, dev_t rdev, struct vnode **vpp)
1.1 pooka 80: {
81: struct puffs_mount *pmp;
1.4 pooka 82: struct vnode *vp, *nvp;
1.1 pooka 83: struct puffs_node *pnode;
1.16 pooka 84: struct puffs_node_hashlist *plist;
1.1 pooka 85: int error;
86:
1.39 ! pooka 87: if (type <= VNON || type >= VBAD)
! 88: return EINVAL;
! 89:
1.1 pooka 90: pmp = MPTOPUFFSMP(mp);
91:
1.2 pooka 92: /*
93: * XXX: there is a deadlock condition between vfs_busy() and
94: * vnode locks. For an unmounting file system the mountpoint
95: * is frozen, but in unmount(FORCE) vflush() wants to access all
96: * of the vnodes. If we are here waiting for the mountpoint
97: * lock while holding on to a vnode lock, well, we ain't
98: * just pining for the fjords anymore. If we release the
99: * vnode lock, we will be in the situation "mount point
100: * is dying" and panic() will ensue in insmntque. So as a
101: * temporary workaround, get a vnode without putting it on
102: * the mount point list, check if mount point is still alive
103: * and kicking and only then add the vnode to the list.
104: */
105: error = getnewvnode(VT_PUFFS, NULL, puffs_vnodeop_p, &vp);
106: if (error)
1.1 pooka 107: return error;
1.2 pooka 108: vp->v_vnlock = NULL;
1.4 pooka 109: vp->v_type = type;
1.2 pooka 110:
111: /*
112: * Check what mount point isn't going away. This will work
113: * until we decide to remove biglock or make the kernel
114: * preemptive. But hopefully the real problem will be fixed
115: * by then.
116: *
117: * XXX: yes, should call vfs_busy(), but thar be rabbits with
118: * vicious streaks a mile wide ...
119: */
120: if (mp->mnt_iflag & IMNT_UNMOUNT) {
121: DPRINTF(("puffs_getvnode: mp %p unmount, unable to create "
122: "vnode for cookie %p\n", mp, cookie));
123: ungetnewvnode(vp);
124: return ENXIO;
1.1 pooka 125: }
126:
1.2 pooka 127: /* So it's not dead yet.. good.. inform new vnode of its master */
128: simple_lock(&mntvnode_slock);
1.16 pooka 129: TAILQ_INSERT_TAIL(&mp->mnt_vnodelist, vp, v_mntvnodes);
1.2 pooka 130: simple_unlock(&mntvnode_slock);
131: vp->v_mount = mp;
132:
1.4 pooka 133: /*
134: * clerical tasks & footwork
135: */
136:
1.29 pooka 137: /* default size */
138: uvm_vnp_setsize(vp, 0);
139:
1.4 pooka 140: /* dances based on vnode type. almost ufs_vinit(), but not quite */
141: switch (type) {
142: case VCHR:
143: case VBLK:
144: /*
145: * replace vnode operation vector with the specops vector.
146: * our user server has very little control over the node
147: * if it decides its a character or block special file
148: */
149: vp->v_op = puffs_specop_p;
150:
151: /* do the standard checkalias-dance */
152: if ((nvp = checkalias(vp, rdev, mp)) != NULL) {
153: /*
1.6 pooka 154: * found: release & unallocate aliased
1.4 pooka 155: * old (well, actually, new) node
156: */
157: vp->v_op = spec_vnodeop_p;
158: vp->v_flag &= ~VLOCKSWORK;
159: vrele(vp);
160: vgone(vp); /* cya */
161:
162: /* init "new" vnode */
163: vp = nvp;
164: vp->v_vnlock = NULL;
165: vp->v_mount = mp;
166: }
167: break;
1.7 pooka 168:
1.5 pooka 169: case VFIFO:
170: vp->v_op = puffs_fifoop_p;
171: break;
1.7 pooka 172:
173: case VREG:
174: uvm_vnp_setsize(vp, vsize);
175: break;
176:
1.5 pooka 177: case VDIR:
178: case VLNK:
179: case VSOCK:
180: break;
1.4 pooka 181: default:
1.5 pooka 182: #ifdef DIAGNOSTIC
183: panic("puffs_getvnode: invalid vtype %d", type);
184: #endif
1.4 pooka 185: break;
186: }
187:
1.2 pooka 188: pnode = pool_get(&puffs_pnpool, PR_WAITOK);
1.1 pooka 189: pnode->pn_cookie = cookie;
190: pnode->pn_stat = 0;
1.31 pooka 191: pnode->pn_refcount = 1;
192:
193: mutex_init(&pnode->pn_mtx, MUTEX_DEFAULT, IPL_NONE);
194: SLIST_INIT(&pnode->pn_sel.sel_klist);
195: pnode->pn_revents = 0;
196:
1.16 pooka 197: plist = puffs_cookie2hashlist(pmp, cookie);
198: LIST_INSERT_HEAD(plist, pnode, pn_hashent);
1.1 pooka 199: vp->v_data = pnode;
1.4 pooka 200: vp->v_type = type;
1.1 pooka 201: pnode->pn_vp = vp;
202:
1.7 pooka 203: genfs_node_init(vp, &puffs_genfsops);
1.1 pooka 204: *vpp = vp;
205:
206: DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
207: pnode, pnode->pn_cookie));
208:
209: return 0;
210: }
211:
212: /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
213: int
214: puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
1.4 pooka 215: void *cookie, struct componentname *cnp, enum vtype type, dev_t rdev)
1.1 pooka 216: {
1.13 pooka 217: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.1 pooka 218: struct vnode *vp;
219: int error;
220:
221: /* userspace probably has this as a NULL op */
222: if (cookie == NULL) {
223: error = EOPNOTSUPP;
1.3 pooka 224: return error;
1.1 pooka 225: }
226:
1.15 pooka 227: /*
228: * Check for previous node with the same designation.
1.20 pooka 229: * Explicitly check the root node cookie, since it might be
230: * reclaimed from the kernel when this check is made.
1.15 pooka 231: *
232: * XXX: technically this error check should punish the fs,
233: * not the caller.
234: */
1.26 pooka 235: mutex_enter(&pmp->pmp_lock);
1.30 pooka 236: if (cookie == pmp->pmp_root_cookie
1.20 pooka 237: || puffs_cookie2pnode(pmp, cookie) != NULL) {
1.26 pooka 238: mutex_exit(&pmp->pmp_lock);
1.15 pooka 239: error = EEXIST;
240: return error;
241: }
1.26 pooka 242: mutex_exit(&pmp->pmp_lock);
1.15 pooka 243:
1.7 pooka 244: error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
1.1 pooka 245: if (error)
1.3 pooka 246: return error;
1.1 pooka 247:
248: vp->v_type = type;
249: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
250: *vpp = vp;
251:
1.35 pooka 252: if ((cnp->cn_flags & MAKEENTRY) && PUFFS_USE_NAMECACHE(pmp))
1.13 pooka 253: cache_enter(dvp, vp, cnp);
254:
1.3 pooka 255: return 0;
1.1 pooka 256: }
257:
1.31 pooka 258: /*
259: * Release pnode structure which dealing with references to the
260: * puffs_node instead of the vnode. Can't use vref()/vrele() on
261: * the vnode there, since that causes the lovely VOP_INACTIVE(),
262: * which in turn causes the lovely deadlock when called by the one
263: * who is supposed to handle it.
264: */
265: void
266: puffs_releasenode(struct puffs_node *pn)
267: {
268:
269: mutex_enter(&pn->pn_mtx);
270: if (--pn->pn_refcount == 0) {
271: mutex_exit(&pn->pn_mtx);
272: mutex_destroy(&pn->pn_mtx);
273: pool_put(&puffs_pnpool, pn);
274: } else {
275: mutex_exit(&pn->pn_mtx);
276: }
277: }
278:
279: /*
280: * Add reference to node.
281: * mutex held on entry and return
282: */
283: void
284: puffs_referencenode(struct puffs_node *pn)
285: {
286:
287: KASSERT(mutex_owned(&pn->pn_mtx));
288: pn->pn_refcount++;
289: }
290:
1.1 pooka 291: void
292: puffs_putvnode(struct vnode *vp)
293: {
294: struct puffs_mount *pmp;
295: struct puffs_node *pnode;
296:
297: pmp = VPTOPUFFSMP(vp);
298: pnode = VPTOPP(vp);
299:
300: #ifdef DIAGNOSTIC
301: if (vp->v_tag != VT_PUFFS)
302: panic("puffs_putvnode: %p not a puffs vnode", vp);
303: #endif
304:
1.16 pooka 305: LIST_REMOVE(pnode, pn_hashent);
1.21 ad 306: genfs_node_destroy(vp);
1.31 pooka 307: puffs_releasenode(pnode);
1.1 pooka 308: vp->v_data = NULL;
309:
310: return;
311: }
312:
1.16 pooka 313: static __inline struct puffs_node_hashlist *
314: puffs_cookie2hashlist(struct puffs_mount *pmp, void *cookie)
315: {
316: uint32_t hash;
317:
318: hash = hash32_buf(&cookie, sizeof(void *), HASH32_BUF_INIT);
319: return &pmp->pmp_pnodehash[hash % pmp->pmp_npnodehash];
320: }
321:
1.1 pooka 322: /*
1.15 pooka 323: * Translate cookie to puffs_node. Caller must hold mountpoint
324: * lock and it will be held upon return.
325: */
1.16 pooka 326: static struct puffs_node *
1.15 pooka 327: puffs_cookie2pnode(struct puffs_mount *pmp, void *cookie)
328: {
1.16 pooka 329: struct puffs_node_hashlist *plist;
1.15 pooka 330: struct puffs_node *pnode;
331:
1.16 pooka 332: plist = puffs_cookie2hashlist(pmp, cookie);
333: LIST_FOREACH(pnode, plist, pn_hashent) {
1.15 pooka 334: if (pnode->pn_cookie == cookie)
335: break;
336: }
337:
338: return pnode;
339: }
340:
341: /*
1.33 pooka 342: * Make sure root vnode exists and reference it. Does NOT lock.
343: */
1.34 pooka 344: static int
1.33 pooka 345: puffs_makeroot(struct puffs_mount *pmp)
346: {
347: struct vnode *vp;
348: int rv;
349:
350: /*
351: * pmp_lock must be held if vref()'ing or vrele()'ing the
352: * root vnode. the latter is controlled by puffs_inactive().
353: *
354: * pmp_root is set here and cleared in puffs_reclaim().
355: */
356: retry:
357: mutex_enter(&pmp->pmp_lock);
358: vp = pmp->pmp_root;
359: if (vp) {
360: simple_lock(&vp->v_interlock);
361: mutex_exit(&pmp->pmp_lock);
362: if (vget(vp, LK_INTERLOCK) == 0)
363: return 0;
364: } else
365: mutex_exit(&pmp->pmp_lock);
366:
367: /*
368: * So, didn't have the magic root vnode available.
369: * No matter, grab another an stuff it with the cookie.
370: */
371: if ((rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie,
372: pmp->pmp_root_vtype, pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp)))
373: return rv;
374:
375: /*
376: * Someone magically managed to race us into puffs_getvnode?
377: * Put our previous new vnode back and retry.
378: */
379: mutex_enter(&pmp->pmp_lock);
380: if (pmp->pmp_root) {
381: mutex_exit(&pmp->pmp_lock);
382: puffs_putvnode(vp);
383: goto retry;
384: }
385:
386: /* store cache */
387: vp->v_flag = VROOT;
388: pmp->pmp_root = vp;
389: mutex_exit(&pmp->pmp_lock);
390:
391: return 0;
392: }
393:
394: /*
1.1 pooka 395: * Locate the in-kernel vnode based on the cookie received given
1.20 pooka 396: * from userspace. Returns a vnode, if found, NULL otherwise.
397: * The parameter "lock" control whether to lock the possible or
398: * not. Locking always might cause us to lock against ourselves
399: * in situations where we want the vnode but don't care for the
400: * vnode lock, e.g. file server issued putpages.
1.1 pooka 401: */
1.34 pooka 402: int
403: puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie, int lock,
404: struct vnode **vpp)
1.1 pooka 405: {
406: struct puffs_node *pnode;
407: struct vnode *vp;
1.34 pooka 408: int vgetflags, rv;
1.1 pooka 409:
1.20 pooka 410: /*
1.33 pooka 411: * Handle root in a special manner, since we want to make sure
412: * pmp_root is properly set.
1.20 pooka 413: */
1.30 pooka 414: if (cookie == pmp->pmp_root_cookie) {
1.34 pooka 415: if ((rv = puffs_makeroot(pmp)))
416: return rv;
1.33 pooka 417: if (lock)
418: vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
1.20 pooka 419:
1.34 pooka 420: *vpp = pmp->pmp_root;
421: return 0;
1.20 pooka 422: }
423:
1.26 pooka 424: mutex_enter(&pmp->pmp_lock);
1.15 pooka 425: pnode = puffs_cookie2pnode(pmp, cookie);
1.14 pooka 426:
1.15 pooka 427: if (pnode == NULL) {
1.26 pooka 428: mutex_exit(&pmp->pmp_lock);
1.34 pooka 429: return ENOENT;
1.15 pooka 430: }
1.34 pooka 431:
1.1 pooka 432: vp = pnode->pn_vp;
1.17 pooka 433: simple_lock(&vp->v_interlock);
1.26 pooka 434: mutex_exit(&pmp->pmp_lock);
1.1 pooka 435:
1.34 pooka 436: vgetflags = LK_INTERLOCK;
437: if (lock)
438: vgetflags |= LK_EXCLUSIVE | LK_RETRY;
439: if ((rv = vget(vp, vgetflags)))
440: return rv;
1.14 pooka 441:
1.34 pooka 442: *vpp = vp;
443: return 0;
1.1 pooka 444: }
445:
446: void
1.36 pooka 447: puffs_makecn(struct puffs_kcn *pkcn, struct puffs_kcred *pkcr,
1.38 pooka 448: struct puffs_kcid *pkcid, const struct componentname *cn, int full)
1.1 pooka 449: {
450:
1.12 pooka 451: pkcn->pkcn_nameiop = cn->cn_nameiop;
452: pkcn->pkcn_flags = cn->cn_flags;
1.37 pooka 453: puffs_cidcvt(pkcid, cn->cn_lwp);
1.1 pooka 454:
1.38 pooka 455: if (full) {
456: (void)strcpy(pkcn->pkcn_name, cn->cn_nameptr);
457: } else {
458: (void)memcpy(pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);
459: pkcn->pkcn_name[cn->cn_namelen] = '\0';
460: }
1.12 pooka 461: pkcn->pkcn_namelen = cn->cn_namelen;
1.38 pooka 462: pkcn->pkcn_consume = 0;
1.36 pooka 463:
464: puffs_credcvt(pkcr, cn->cn_cred);
1.1 pooka 465: }
466:
467: /*
1.36 pooka 468: * Convert given credentials to struct puffs_kcred for userspace.
1.1 pooka 469: */
470: void
1.36 pooka 471: puffs_credcvt(struct puffs_kcred *pkcr, const kauth_cred_t cred)
1.1 pooka 472: {
473:
1.36 pooka 474: memset(pkcr, 0, sizeof(struct puffs_kcred));
1.1 pooka 475:
476: if (cred == NOCRED || cred == FSCRED) {
1.36 pooka 477: pkcr->pkcr_type = PUFFCRED_TYPE_INTERNAL;
1.1 pooka 478: if (cred == NOCRED)
1.36 pooka 479: pkcr->pkcr_internal = PUFFCRED_CRED_NOCRED;
1.1 pooka 480: if (cred == FSCRED)
1.36 pooka 481: pkcr->pkcr_internal = PUFFCRED_CRED_FSCRED;
1.1 pooka 482: } else {
1.36 pooka 483: pkcr->pkcr_type = PUFFCRED_TYPE_UUC;
484: kauth_cred_to_uucred(&pkcr->pkcr_uuc, cred);
1.1 pooka 485: }
486: }
487:
1.37 pooka 488: void
489: puffs_cidcvt(struct puffs_kcid *pkcid, const struct lwp *l)
1.1 pooka 490: {
491:
1.37 pooka 492: if (l) {
493: pkcid->pkcid_type = PUFFCID_TYPE_REAL;
494: pkcid->pkcid_pid = l->l_proc->p_pid;
495: pkcid->pkcid_lwpid = l->l_lid;
496: } else {
497: pkcid->pkcid_type = PUFFCID_TYPE_FAKE;
498: pkcid->pkcid_pid = 0;
499: pkcid->pkcid_lwpid = 0;
500: }
1.1 pooka 501: }
1.7 pooka 502:
503: static void
1.8 christos 504: puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
505: int flags)
1.7 pooka 506: {
507:
508: *eobp = size;
509: }
510:
511: static void
512: puffs_gop_markupdate(struct vnode *vp, int flags)
513: {
514: int uflags = 0;
515:
516: if (flags & GOP_UPDATE_ACCESSED)
517: uflags |= PUFFS_UPDATEATIME;
518: if (flags & GOP_UPDATE_MODIFIED)
519: uflags |= PUFFS_UPDATEMTIME;
520:
521: puffs_updatenode(vp, uflags);
522: }
523:
524: void
525: puffs_updatenode(struct vnode *vp, int flags)
526: {
1.25 pooka 527: struct puffs_node *pn;
1.7 pooka 528: struct timespec ts;
529:
530: if (flags == 0)
531: return;
532:
1.25 pooka 533: pn = VPTOPP(vp);
1.7 pooka 534: nanotime(&ts);
535:
1.25 pooka 536: if (flags & PUFFS_UPDATEATIME) {
537: pn->pn_mc_atime = ts;
538: pn->pn_stat |= PNODE_METACACHE_ATIME;
539: }
540: if (flags & PUFFS_UPDATECTIME) {
541: pn->pn_mc_ctime = ts;
542: pn->pn_stat |= PNODE_METACACHE_CTIME;
543: }
544: if (flags & PUFFS_UPDATEMTIME) {
545: pn->pn_mc_mtime = ts;
546: pn->pn_stat |= PNODE_METACACHE_MTIME;
547: }
548: if (flags & PUFFS_UPDATESIZE) {
549: pn->pn_mc_size = vp->v_size;
550: pn->pn_stat |= PNODE_METACACHE_SIZE;
551: }
1.7 pooka 552: }
1.9 pooka 553:
554: void
555: puffs_updatevpsize(struct vnode *vp)
556: {
557: struct vattr va;
558:
559: if (VOP_GETATTR(vp, &va, FSCRED, NULL))
560: return;
561:
562: if (va.va_size != VNOVAL)
563: vp->v_size = va.va_size;
564: }
1.27 pooka 565:
566: void
567: puffs_parkdone_asyncbioread(struct puffs_req *preq, void *arg)
568: {
569: struct puffs_vnreq_read *read_argp = (void *)preq;
570: struct buf *bp = arg;
571: size_t moved;
572:
573: bp->b_error = preq->preq_rv;
574: if (bp->b_error == 0) {
575: moved = bp->b_bcount - read_argp->pvnr_resid;
576: bp->b_resid = read_argp->pvnr_resid;
577:
578: memcpy(bp->b_data, read_argp->pvnr_data, moved);
579: } else {
580: bp->b_flags |= B_ERROR;
581: }
582:
583: biodone(bp);
584: free(preq, M_PUFFS);
585: }
1.28 pooka 586:
587: void
1.31 pooka 588: puffs_parkdone_poll(struct puffs_req *preq, void *arg)
589: {
590: struct puffs_vnreq_poll *poll_argp = (void *)preq;
591: struct puffs_node *pn = arg;
592: int revents;
593:
594: if (preq->preq_rv == 0)
595: revents = poll_argp->pvnr_events;
596: else
597: revents = POLLERR;
598:
599: mutex_enter(&pn->pn_mtx);
600: pn->pn_revents |= revents;
601: mutex_exit(&pn->pn_mtx);
602:
603: selnotify(&pn->pn_sel, 0);
604: free(preq, M_PUFFS);
605:
606: puffs_releasenode(pn);
607: }
608:
609: void
1.28 pooka 610: puffs_mp_reference(struct puffs_mount *pmp)
611: {
612:
613: KASSERT(mutex_owned(&pmp->pmp_lock));
614: pmp->pmp_refcount++;
615: }
616:
617: void
618: puffs_mp_release(struct puffs_mount *pmp)
619: {
620:
621: KASSERT(mutex_owned(&pmp->pmp_lock));
622: if (--pmp->pmp_refcount == 0)
623: cv_broadcast(&pmp->pmp_refcount_cv);
624: }
CVSweb <webmaster@jp.NetBSD.org>