Annotation of src/sys/fs/puffs/puffs_subr.c, Revision 1.27
1.27 ! pooka 1: /* $NetBSD: puffs_subr.c,v 1.26 2007/03/29 16:04:26 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: * 3. The name of the company nor the name of the author may be used to
19: * endorse or promote products derived from this software without specific
20: * prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
35: #include <sys/cdefs.h>
1.27 ! pooka 36: __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.26 2007/03/29 16:04:26 pooka Exp $");
1.1 pooka 37:
38: #include <sys/param.h>
39: #include <sys/conf.h>
1.16 pooka 40: #include <sys/hash.h>
1.1 pooka 41: #include <sys/malloc.h>
42: #include <sys/mount.h>
43: #include <sys/socketvar.h>
44: #include <sys/vnode.h>
45: #include <sys/kauth.h>
46: #include <sys/namei.h>
47:
48: #include <fs/puffs/puffs_msgif.h>
49: #include <fs/puffs/puffs_sys.h>
50:
1.7 pooka 51: #include <miscfs/genfs/genfs_node.h>
1.4 pooka 52: #include <miscfs/specfs/specdev.h>
53:
1.26 pooka 54: struct pool puffs_pnpool;
1.1 pooka 55:
1.19 pooka 56: #ifdef PUFFSDEBUG
1.10 pooka 57: int puffsdebug;
58: #endif
59:
1.16 pooka 60: static __inline struct puffs_node_hashlist
61: *puffs_cookie2hashlist(struct puffs_mount *, void *);
62: static struct puffs_node *puffs_cookie2pnode(struct puffs_mount *, void *);
1.7 pooka 63:
64: static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
65: static void puffs_gop_markupdate(struct vnode *, int);
66:
67: static const struct genfs_ops puffs_genfsops = {
68: .gop_size = puffs_gop_size,
69: .gop_write = genfs_gop_write,
70: .gop_markupdate = puffs_gop_markupdate,
71: #if 0
72: .gop_alloc, should ask userspace
73: #endif
74: };
75:
1.1 pooka 76: /*
77: * Grab a vnode, intialize all the puffs-dependant stuff.
78: */
79: int
1.4 pooka 80: puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
1.7 pooka 81: voff_t vsize, dev_t rdev, struct vnode **vpp)
1.1 pooka 82: {
83: struct puffs_mount *pmp;
1.4 pooka 84: struct vnode *vp, *nvp;
1.1 pooka 85: struct puffs_node *pnode;
1.16 pooka 86: struct puffs_node_hashlist *plist;
1.1 pooka 87: int error;
88:
89: pmp = MPTOPUFFSMP(mp);
90:
1.2 pooka 91: /*
92: * XXX: there is a deadlock condition between vfs_busy() and
93: * vnode locks. For an unmounting file system the mountpoint
94: * is frozen, but in unmount(FORCE) vflush() wants to access all
95: * of the vnodes. If we are here waiting for the mountpoint
96: * lock while holding on to a vnode lock, well, we ain't
97: * just pining for the fjords anymore. If we release the
98: * vnode lock, we will be in the situation "mount point
99: * is dying" and panic() will ensue in insmntque. So as a
100: * temporary workaround, get a vnode without putting it on
101: * the mount point list, check if mount point is still alive
102: * and kicking and only then add the vnode to the list.
103: */
104: error = getnewvnode(VT_PUFFS, NULL, puffs_vnodeop_p, &vp);
105: if (error)
1.1 pooka 106: return error;
1.2 pooka 107: vp->v_vnlock = NULL;
1.4 pooka 108: vp->v_type = type;
1.2 pooka 109:
110: /*
111: * Check what mount point isn't going away. This will work
112: * until we decide to remove biglock or make the kernel
113: * preemptive. But hopefully the real problem will be fixed
114: * by then.
115: *
116: * XXX: yes, should call vfs_busy(), but thar be rabbits with
117: * vicious streaks a mile wide ...
118: */
119: if (mp->mnt_iflag & IMNT_UNMOUNT) {
120: DPRINTF(("puffs_getvnode: mp %p unmount, unable to create "
121: "vnode for cookie %p\n", mp, cookie));
122: ungetnewvnode(vp);
123: return ENXIO;
1.1 pooka 124: }
125:
1.2 pooka 126: /* So it's not dead yet.. good.. inform new vnode of its master */
127: simple_lock(&mntvnode_slock);
1.16 pooka 128: TAILQ_INSERT_TAIL(&mp->mnt_vnodelist, vp, v_mntvnodes);
1.2 pooka 129: simple_unlock(&mntvnode_slock);
130: vp->v_mount = mp;
131:
1.4 pooka 132: /*
133: * clerical tasks & footwork
134: */
135:
136: /* dances based on vnode type. almost ufs_vinit(), but not quite */
137: switch (type) {
138: case VCHR:
139: case VBLK:
140: /*
141: * replace vnode operation vector with the specops vector.
142: * our user server has very little control over the node
143: * if it decides its a character or block special file
144: */
145: vp->v_op = puffs_specop_p;
146:
147: /* do the standard checkalias-dance */
148: if ((nvp = checkalias(vp, rdev, mp)) != NULL) {
149: /*
1.6 pooka 150: * found: release & unallocate aliased
1.4 pooka 151: * old (well, actually, new) node
152: */
153: vp->v_op = spec_vnodeop_p;
154: vp->v_flag &= ~VLOCKSWORK;
155: vrele(vp);
156: vgone(vp); /* cya */
157:
158: /* init "new" vnode */
159: vp = nvp;
160: vp->v_vnlock = NULL;
161: vp->v_mount = mp;
162: }
163: break;
1.7 pooka 164:
1.5 pooka 165: case VFIFO:
166: vp->v_op = puffs_fifoop_p;
167: break;
1.7 pooka 168:
169: case VREG:
170: uvm_vnp_setsize(vp, vsize);
171: break;
172:
1.5 pooka 173: case VDIR:
174: case VLNK:
175: case VSOCK:
176: break;
1.4 pooka 177: default:
1.5 pooka 178: #ifdef DIAGNOSTIC
179: panic("puffs_getvnode: invalid vtype %d", type);
180: #endif
1.4 pooka 181: break;
182: }
183:
1.2 pooka 184: pnode = pool_get(&puffs_pnpool, PR_WAITOK);
1.1 pooka 185: pnode->pn_cookie = cookie;
186: pnode->pn_stat = 0;
1.16 pooka 187: plist = puffs_cookie2hashlist(pmp, cookie);
188: LIST_INSERT_HEAD(plist, pnode, pn_hashent);
1.1 pooka 189: vp->v_data = pnode;
1.4 pooka 190: vp->v_type = type;
1.1 pooka 191: pnode->pn_vp = vp;
192:
1.7 pooka 193: genfs_node_init(vp, &puffs_genfsops);
1.1 pooka 194: *vpp = vp;
195:
196: DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
197: pnode, pnode->pn_cookie));
198:
199: return 0;
200: }
201:
202: /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
203: int
204: puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
1.4 pooka 205: void *cookie, struct componentname *cnp, enum vtype type, dev_t rdev)
1.1 pooka 206: {
1.13 pooka 207: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.1 pooka 208: struct vnode *vp;
209: int error;
210:
211: /* userspace probably has this as a NULL op */
212: if (cookie == NULL) {
213: error = EOPNOTSUPP;
1.3 pooka 214: return error;
1.1 pooka 215: }
216:
1.15 pooka 217: /*
218: * Check for previous node with the same designation.
1.20 pooka 219: * Explicitly check the root node cookie, since it might be
220: * reclaimed from the kernel when this check is made.
1.15 pooka 221: *
222: * XXX: technically this error check should punish the fs,
223: * not the caller.
224: */
1.26 pooka 225: mutex_enter(&pmp->pmp_lock);
1.20 pooka 226: if (cookie == pmp->pmp_rootcookie
227: || puffs_cookie2pnode(pmp, cookie) != NULL) {
1.26 pooka 228: mutex_exit(&pmp->pmp_lock);
1.15 pooka 229: error = EEXIST;
230: return error;
231: }
1.26 pooka 232: mutex_exit(&pmp->pmp_lock);
1.15 pooka 233:
1.7 pooka 234: error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
1.1 pooka 235: if (error)
1.3 pooka 236: return error;
1.1 pooka 237:
238: vp->v_type = type;
239: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
240: *vpp = vp;
241:
1.13 pooka 242: if ((cnp->cn_flags & MAKEENTRY) && PUFFS_DOCACHE(pmp))
243: cache_enter(dvp, vp, cnp);
244:
1.3 pooka 245: return 0;
1.1 pooka 246: }
247:
248: void
249: puffs_putvnode(struct vnode *vp)
250: {
251: struct puffs_mount *pmp;
252: struct puffs_node *pnode;
253:
254: pmp = VPTOPUFFSMP(vp);
255: pnode = VPTOPP(vp);
256:
257: #ifdef DIAGNOSTIC
258: if (vp->v_tag != VT_PUFFS)
259: panic("puffs_putvnode: %p not a puffs vnode", vp);
260: #endif
261:
1.16 pooka 262: LIST_REMOVE(pnode, pn_hashent);
1.21 ad 263: genfs_node_destroy(vp);
1.1 pooka 264: pool_put(&puffs_pnpool, vp->v_data);
265: vp->v_data = NULL;
266:
267: return;
268: }
269:
1.16 pooka 270: static __inline struct puffs_node_hashlist *
271: puffs_cookie2hashlist(struct puffs_mount *pmp, void *cookie)
272: {
273: uint32_t hash;
274:
275: hash = hash32_buf(&cookie, sizeof(void *), HASH32_BUF_INIT);
276: return &pmp->pmp_pnodehash[hash % pmp->pmp_npnodehash];
277: }
278:
1.1 pooka 279: /*
1.15 pooka 280: * Translate cookie to puffs_node. Caller must hold mountpoint
281: * lock and it will be held upon return.
282: */
1.16 pooka 283: static struct puffs_node *
1.15 pooka 284: puffs_cookie2pnode(struct puffs_mount *pmp, void *cookie)
285: {
1.16 pooka 286: struct puffs_node_hashlist *plist;
1.15 pooka 287: struct puffs_node *pnode;
288:
1.16 pooka 289: plist = puffs_cookie2hashlist(pmp, cookie);
290: LIST_FOREACH(pnode, plist, pn_hashent) {
1.15 pooka 291: if (pnode->pn_cookie == cookie)
292: break;
293: }
294:
295: return pnode;
296: }
297:
298: /*
1.1 pooka 299: * Locate the in-kernel vnode based on the cookie received given
1.20 pooka 300: * from userspace. Returns a vnode, if found, NULL otherwise.
301: * The parameter "lock" control whether to lock the possible or
302: * not. Locking always might cause us to lock against ourselves
303: * in situations where we want the vnode but don't care for the
304: * vnode lock, e.g. file server issued putpages.
1.1 pooka 305: */
306: struct vnode *
1.14 pooka 307: puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie, int lock)
1.1 pooka 308: {
309: struct puffs_node *pnode;
310: struct vnode *vp;
1.14 pooka 311: int vgetflags;
1.1 pooka 312:
1.20 pooka 313: /*
314: * If we're trying to get the root vnode, return it through
315: * puffs_root() to get all the right things set. Lock must
316: * be set, since VFS_ROOT() always locks the returned vnode.
317: */
318: if (cookie == pmp->pmp_rootcookie) {
319: if (!lock)
320: return NULL;
321: if (VFS_ROOT(pmp->pmp_mp, &vp))
322: return NULL;
323:
324: return vp;
325: }
326:
1.17 pooka 327: vgetflags = LK_INTERLOCK;
328: if (lock)
329: vgetflags |= LK_EXCLUSIVE | LK_RETRY;
330:
1.26 pooka 331: mutex_enter(&pmp->pmp_lock);
1.15 pooka 332: pnode = puffs_cookie2pnode(pmp, cookie);
1.14 pooka 333:
1.15 pooka 334: if (pnode == NULL) {
1.26 pooka 335: mutex_exit(&pmp->pmp_lock);
1.1 pooka 336: return NULL;
1.15 pooka 337: }
1.1 pooka 338: vp = pnode->pn_vp;
1.17 pooka 339:
340: simple_lock(&vp->v_interlock);
1.26 pooka 341: mutex_exit(&pmp->pmp_lock);
1.1 pooka 342:
1.14 pooka 343: if (vget(vp, vgetflags))
344: return NULL;
345:
1.1 pooka 346: return vp;
347: }
348:
349: void
1.12 pooka 350: puffs_makecn(struct puffs_kcn *pkcn, const struct componentname *cn)
1.1 pooka 351: {
352:
1.12 pooka 353: pkcn->pkcn_nameiop = cn->cn_nameiop;
354: pkcn->pkcn_flags = cn->cn_flags;
355: pkcn->pkcn_pid = cn->cn_lwp->l_proc->p_pid;
356: puffs_credcvt(&pkcn->pkcn_cred, cn->cn_cred);
1.1 pooka 357:
1.12 pooka 358: (void)memcpy(&pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);
359: pkcn->pkcn_name[cn->cn_namelen] = '\0';
360: pkcn->pkcn_namelen = cn->cn_namelen;
1.1 pooka 361: }
362:
363: /*
364: * Convert given credentials to struct puffs_cred for userspace.
365: */
366: void
367: puffs_credcvt(struct puffs_cred *pcr, const kauth_cred_t cred)
368: {
369:
370: memset(pcr, 0, sizeof(struct puffs_cred));
371:
372: if (cred == NOCRED || cred == FSCRED) {
373: pcr->pcr_type = PUFFCRED_TYPE_INTERNAL;
374: if (cred == NOCRED)
375: pcr->pcr_internal = PUFFCRED_CRED_NOCRED;
376: if (cred == FSCRED)
377: pcr->pcr_internal = PUFFCRED_CRED_FSCRED;
378: } else {
379: pcr->pcr_type = PUFFCRED_TYPE_UUC;
380: kauth_cred_to_uucred(&pcr->pcr_uuc, cred);
381: }
382: }
383:
384: /*
385: * Return pid. In case the operation is coming from within the
386: * kernel without any process context, borrow the swapper's pid.
387: */
388: pid_t
389: puffs_lwp2pid(struct lwp *l)
390: {
391:
392: return l ? l->l_proc->p_pid : 0;
393: }
1.7 pooka 394:
395:
396: static void
1.8 christos 397: puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
398: int flags)
1.7 pooka 399: {
400:
401: *eobp = size;
402: }
403:
404: static void
405: puffs_gop_markupdate(struct vnode *vp, int flags)
406: {
407: int uflags = 0;
408:
409: if (flags & GOP_UPDATE_ACCESSED)
410: uflags |= PUFFS_UPDATEATIME;
411: if (flags & GOP_UPDATE_MODIFIED)
412: uflags |= PUFFS_UPDATEMTIME;
413:
414: puffs_updatenode(vp, uflags);
415: }
416:
417: void
418: puffs_updatenode(struct vnode *vp, int flags)
419: {
1.25 pooka 420: struct puffs_node *pn;
1.7 pooka 421: struct timespec ts;
422:
423: if (flags == 0)
424: return;
425:
1.25 pooka 426: pn = VPTOPP(vp);
1.7 pooka 427: nanotime(&ts);
428:
1.25 pooka 429: if (flags & PUFFS_UPDATEATIME) {
430: pn->pn_mc_atime = ts;
431: pn->pn_stat |= PNODE_METACACHE_ATIME;
432: }
433: if (flags & PUFFS_UPDATECTIME) {
434: pn->pn_mc_ctime = ts;
435: pn->pn_stat |= PNODE_METACACHE_CTIME;
436: }
437: if (flags & PUFFS_UPDATEMTIME) {
438: pn->pn_mc_mtime = ts;
439: pn->pn_stat |= PNODE_METACACHE_MTIME;
440: }
441: if (flags & PUFFS_UPDATESIZE) {
442: pn->pn_mc_size = vp->v_size;
443: pn->pn_stat |= PNODE_METACACHE_SIZE;
444: }
1.7 pooka 445: }
1.9 pooka 446:
447: void
448: puffs_updatevpsize(struct vnode *vp)
449: {
450: struct vattr va;
451:
452: if (VOP_GETATTR(vp, &va, FSCRED, NULL))
453: return;
454:
455: if (va.va_size != VNOVAL)
456: vp->v_size = va.va_size;
457: }
1.27 ! pooka 458:
! 459: void
! 460: puffs_parkdone_asyncbioread(struct puffs_req *preq, void *arg)
! 461: {
! 462: struct puffs_vnreq_read *read_argp = (void *)preq;
! 463: struct buf *bp = arg;
! 464: size_t moved;
! 465:
! 466: bp->b_error = preq->preq_rv;
! 467: if (bp->b_error == 0) {
! 468: moved = bp->b_bcount - read_argp->pvnr_resid;
! 469: bp->b_resid = read_argp->pvnr_resid;
! 470:
! 471: memcpy(bp->b_data, read_argp->pvnr_data, moved);
! 472: } else {
! 473: bp->b_flags |= B_ERROR;
! 474: }
! 475:
! 476: biodone(bp);
! 477: free(preq, M_PUFFS);
! 478: }
CVSweb <webmaster@jp.NetBSD.org>