Annotation of src/sys/fs/puffs/puffs_vfsops.c, Revision 1.25
1.25 ! pooka 1: /* $NetBSD: puffs_vfsops.c,v 1.24 2007/01/23 18:27:50 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.25 ! pooka 36: __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.24 2007/01/23 18:27:50 pooka Exp $");
1.1 pooka 37:
38: #include <sys/param.h>
39: #include <sys/mount.h>
40: #include <sys/malloc.h>
41: #include <sys/extattr.h>
42: #include <sys/queue.h>
43: #include <sys/vnode.h>
44: #include <sys/dirent.h>
45: #include <sys/kauth.h>
46:
47: #include <lib/libkern/libkern.h>
48:
49: #include <fs/puffs/puffs_msgif.h>
50: #include <fs/puffs/puffs_sys.h>
51:
52: VFS_PROTOS(puffs);
53:
54: MALLOC_DEFINE(M_PUFFS, "puffs", "pass-to-userspace file system structures");
55:
1.22 pooka 56: #ifndef PUFFS_PNODEBUCKETS
57: #define PUFFS_PNODEBUCKETS 256
58: #endif
59: #ifndef PUFFS_MAXPNODEBUCKETS
60: #define PUFFS_MAXPNODEBUCKETS 65536
61: #endif
62: int puffs_pnodebuckets = PUFFS_PNODEBUCKETS;
63:
1.1 pooka 64: int
65: puffs_mount(struct mount *mp, const char *path, void *data,
66: struct nameidata *ndp, struct lwp *l)
67: {
1.22 pooka 68: struct puffs_mount *pmp = NULL;
1.17 pooka 69: struct puffs_args *args;
70: char namebuf[PUFFSNAMESIZE+sizeof(PUFFS_NAMEPREFIX)+1]; /* spooky */
1.22 pooka 71: int error = 0, i;
1.1 pooka 72:
73: if (mp->mnt_flag & MNT_GETARGS) {
74: pmp = MPTOPUFFSMP(mp);
75: return copyout(&pmp->pmp_args, data, sizeof(struct puffs_args));
76: }
77:
78: /* update is not supported currently */
79: if (mp->mnt_flag & MNT_UPDATE)
80: return EOPNOTSUPP;
81:
82: /*
83: * We need the file system name
84: */
85: if (!data)
86: return EINVAL;
87:
1.17 pooka 88: MALLOC(args, struct puffs_args *, sizeof(struct puffs_args),
89: M_PUFFS, M_WAITOK);
90:
91: error = copyin(data, args, sizeof(struct puffs_args));
1.1 pooka 92: if (error)
1.17 pooka 93: goto out;
94:
95: /* devel phase */
96: if (args->pa_vers != (PUFFSVERSION | PUFFSDEVELVERS)) {
97: printf("puffs_mount: development version mismatch\n");
98: error = EINVAL;
99: goto out;
100: }
1.1 pooka 101:
1.8 pooka 102: /* nuke spy bits */
1.17 pooka 103: args->pa_flags &= PUFFS_KFLAG_MASK;
1.8 pooka 104:
1.1 pooka 105: /* build real name */
1.17 pooka 106: (void)strlcpy(namebuf, PUFFS_NAMEPREFIX, sizeof(namebuf));
107: (void)strlcat(namebuf, args->pa_name, sizeof(namebuf));
1.1 pooka 108:
109: /* inform user server if it got the max request size it wanted */
1.17 pooka 110: if (args->pa_maxreqlen == 0 || args->pa_maxreqlen > PUFFS_REQ_MAXSIZE)
111: args->pa_maxreqlen = PUFFS_REQ_MAXSIZE;
112: else if (args->pa_maxreqlen < PUFFS_REQSTRUCT_MAX)
113: args->pa_maxreqlen = PUFFS_REQSTRUCT_MAX;
114: (void)strlcpy(args->pa_name, namebuf, sizeof(args->pa_name));
1.1 pooka 115:
1.17 pooka 116: error = copyout(args, data, sizeof(struct puffs_args));
1.1 pooka 117: if (error)
1.17 pooka 118: goto out;
1.1 pooka 119:
120: error = set_statvfs_info(path, UIO_USERSPACE, namebuf,
121: UIO_SYSSPACE, mp, l);
122: if (error)
1.17 pooka 123: goto out;
1.10 pooka 124: mp->mnt_stat.f_iosize = DEV_BSIZE;
1.1 pooka 125:
126: MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount),
127: M_PUFFS, M_WAITOK | M_ZERO);
128:
1.6 pooka 129: mp->mnt_fs_bshift = DEV_BSHIFT;
130: mp->mnt_dev_bshift = DEV_BSHIFT;
131: mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
1.1 pooka 132: mp->mnt_data = pmp;
1.6 pooka 133:
1.1 pooka 134: pmp->pmp_status = PUFFSTAT_MOUNTING;
135: pmp->pmp_nextreq = 0;
136: pmp->pmp_mp = mp;
1.17 pooka 137: pmp->pmp_req_maxsize = args->pa_maxreqlen;
138: pmp->pmp_args = *args;
1.1 pooka 139:
1.22 pooka 140: /* puffs_node hash buckets */
141: pmp->pmp_npnodehash = puffs_pnodebuckets;
142: if (pmp->pmp_npnodehash < 1)
143: pmp->pmp_npnodehash = 1;
144: if (pmp->pmp_npnodehash > PUFFS_MAXPNODEBUCKETS)
145: pmp->pmp_npnodehash = PUFFS_MAXPNODEBUCKETS;
146: pmp->pmp_pnodehash = malloc
147: (sizeof(struct puffs_pnode_hashlist *) * pmp->pmp_npnodehash,
148: M_PUFFS, M_WAITOK);
149: for (i = 0; i < pmp->pmp_npnodehash; i++)
150: LIST_INIT(&pmp->pmp_pnodehash[i]);
151:
1.1 pooka 152: /*
153: * Inform the fileops processing code that we have a mountpoint.
154: * If it doesn't know about anyone with our pid/fd having the
155: * device open, punt
156: */
1.17 pooka 157: if (puffs_setpmp(l->l_proc->p_pid, args->pa_fd, pmp)) {
158: error = ENOENT;
159: goto out;
1.1 pooka 160: }
161:
162: simple_lock_init(&pmp->pmp_lock);
163: TAILQ_INIT(&pmp->pmp_req_touser);
164: TAILQ_INIT(&pmp->pmp_req_replywait);
165: TAILQ_INIT(&pmp->pmp_req_sizepark);
166:
167: DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
168: mp, MPTOPUFFSMP(mp)));
169:
170: vfs_getnewfsid(mp);
171:
1.17 pooka 172: out:
1.22 pooka 173: if (error && pmp && pmp->pmp_pnodehash)
174: free(pmp->pmp_pnodehash, M_PUFFS);
175: if (error && pmp)
176: FREE(pmp, M_PUFFS);
1.17 pooka 177: FREE(args, M_PUFFS);
178: return error;
1.1 pooka 179: }
180:
181: /*
182: * This is called from the first "Hello, I'm alive" ioctl
183: * from userspace.
184: */
185: int
1.7 pooka 186: puffs_start2(struct puffs_mount *pmp, struct puffs_startreq *sreq)
1.1 pooka 187: {
188: struct puffs_node *pn;
189: struct mount *mp;
190:
191: mp = PMPTOMP(pmp);
192:
193: simple_lock(&pmp->pmp_lock);
194:
195: /*
196: * if someone has issued a VFS_ROOT() already, fill in the
197: * vnode cookie.
198: */
1.2 pooka 199: pn = NULL;
1.1 pooka 200: if (pmp->pmp_root) {
201: pn = VPTOPP(pmp->pmp_root);
202: pn->pn_cookie = sreq->psr_cookie;
203: }
204:
205: /* We're good to fly */
206: pmp->pmp_rootcookie = sreq->psr_cookie;
207: pmp->pmp_status = PUFFSTAT_RUNNING;
1.9 pooka 208: simple_unlock(&pmp->pmp_lock);
1.1 pooka 209:
1.9 pooka 210: /* do the VFS_STATVFS() we missed out on in sys_mount() */
211: copy_statvfs_info(&sreq->psr_sb, mp);
212: (void)memcpy(&mp->mnt_stat, &sreq->psr_sb, sizeof(mp->mnt_stat));
1.11 pooka 213: mp->mnt_stat.f_iosize = DEV_BSIZE;
1.1 pooka 214:
1.2 pooka 215: DPRINTF(("puffs_start2: root vp %p, cur root pnode %p, cookie %p\n",
1.1 pooka 216: pmp->pmp_root, pn, sreq->psr_cookie));
217:
218: return 0;
219: }
220:
221: int
222: puffs_start(struct mount *mp, int flags, struct lwp *l)
223: {
224:
225: /*
226: * This cannot travel to userspace, as this is called from
227: * the kernel context of the process doing mount(2). But
228: * it's probably a safe bet that the process doing mount(2)
229: * realizes it needs to start the filesystem also...
230: */
231: return 0;
232: }
233:
234: int
235: puffs_unmount(struct mount *mp, int mntflags, struct lwp *l)
236: {
237: struct puffs_mount *pmp;
238: int error, force;
239:
240: PUFFS_VFSREQ(unmount);
241:
242: error = 0;
243: force = mntflags & MNT_FORCE;
244: pmp = MPTOPUFFSMP(mp);
245:
246: DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
247: "status 0x%x\n", pmp->pmp_status));
248:
249: /*
250: * flush all the vnodes. VOP_RECLAIM() takes care that the
251: * root vnode does not get flushed until unmount. The
252: * userspace root node cookie is stored in the mount
253: * structure, so we can always re-instantiate a root vnode,
254: * should userspace unmount decide it doesn't want to
255: * cooperate.
256: */
257: error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
258: if (error)
259: goto out;
260:
261: /*
262: * If we are not DYING, we should ask userspace's opinion
263: * about the situation
264: */
1.16 pooka 265: simple_lock(&pmp->pmp_lock);
1.1 pooka 266: if (pmp->pmp_status != PUFFSTAT_DYING) {
1.16 pooka 267: pmp->pmp_unmounting = 1;
268: simple_unlock(&pmp->pmp_lock);
269:
1.1 pooka 270: unmount_arg.pvfsr_flags = mntflags;
271: unmount_arg.pvfsr_pid = puffs_lwp2pid(l);
1.16 pooka 272:
1.1 pooka 273: error = puffs_vfstouser(pmp, PUFFS_VFS_UNMOUNT,
274: &unmount_arg, sizeof(unmount_arg));
1.16 pooka 275: DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
276:
277: simple_lock(&pmp->pmp_lock);
278: pmp->pmp_unmounting = 0;
279: wakeup(&pmp->pmp_unmounting);
1.1 pooka 280: }
281:
282: /*
283: * if userspace cooperated or we really need to die,
284: * screw what userland thinks and just die.
285: */
286: if (error == 0 || force) {
287: pmp->pmp_status = PUFFSTAT_DYING;
288: puffs_nukebypmp(pmp);
1.16 pooka 289: simple_unlock(&pmp->pmp_lock);
1.22 pooka 290: free(pmp->pmp_pnodehash, M_PUFFS);
1.1 pooka 291: FREE(pmp, M_PUFFS);
292: error = 0;
1.16 pooka 293: } else {
294: simple_unlock(&pmp->pmp_lock);
1.1 pooka 295: }
296:
297: out:
1.2 pooka 298: DPRINTF(("puffs_unmount: return %d\n", error));
1.1 pooka 299: return error;
300: }
301:
302: /*
303: * This doesn't need to travel to userspace
304: */
305: int
306: puffs_root(struct mount *mp, struct vnode **vpp)
307: {
308: struct puffs_mount *pmp;
309: struct puffs_node *pn;
310: struct vnode *vp;
311:
312: pmp = MPTOPUFFSMP(mp);
313:
314: /*
315: * pmp_lock must be held if vref()'ing or vrele()'ing the
1.20 pooka 316: * root vnode. the latter is controlled by puffs_inactive().
1.1 pooka 317: */
318: simple_lock(&pmp->pmp_lock);
319: vp = pmp->pmp_root;
320: if (vp) {
1.25 ! pooka 321: simple_lock(&vp->v_interlock);
! 322: simple_unlock(&pmp->pmp_lock);
1.1 pooka 323: pn = VPTOPP(vp);
1.25 ! pooka 324: if (vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK))
1.20 pooka 325: goto grabnew;
1.1 pooka 326: *vpp = vp;
327: return 0;
1.25 ! pooka 328: } else
! 329: simple_unlock(&pmp->pmp_lock);
! 330:
! 331: /* XXX: this is wrong, so FIXME */
1.1 pooka 332: grabnew:
333:
334: /*
335: * So, didn't have the magic root vnode available.
336: * No matter, grab another an stuff it with the cookie.
337: */
1.6 pooka 338: if (puffs_getvnode(mp, pmp->pmp_rootcookie, VDIR, 0, 0, &vp))
1.1 pooka 339: panic("sloppy programming");
340:
341: simple_lock(&pmp->pmp_lock);
342: /*
343: * check if by mysterious force someone else created a root
344: * vnode while we were executing.
345: */
346: if (pmp->pmp_root) {
347: vref(pmp->pmp_root);
348: simple_unlock(&pmp->pmp_lock);
349: puffs_putvnode(vp);
350: vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
351: *vpp = pmp->pmp_root;
352: return 0;
353: }
354:
355: /* store cache */
356: vp->v_flag = VROOT;
357: pmp->pmp_root = vp;
358: simple_unlock(&pmp->pmp_lock);
359:
360: vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
361:
362: *vpp = vp;
363: return 0;
364: }
365:
366: int
367: puffs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, struct lwp *l)
368: {
369:
370: return EOPNOTSUPP;
371: }
372:
373: int
374: puffs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
375: {
376: struct puffs_vfsreq_statvfs *statvfs_arg; /* too big for stack */
377: struct puffs_mount *pmp;
378: int error = 0;
379:
380: pmp = MPTOPUFFSMP(mp);
381:
382: /*
383: * If we are mounting, it means that the userspace counterpart
384: * is calling mount(2), but mount(2) also calls statvfs. So
385: * requesting statvfs from userspace would mean a deadlock.
386: * Compensate.
387: */
388: if (pmp->pmp_status == PUFFSTAT_MOUNTING)
389: return EINPROGRESS;
390:
391: /* too big for stack */
392: MALLOC(statvfs_arg, struct puffs_vfsreq_statvfs *,
393: sizeof(struct puffs_vfsreq_statvfs), M_PUFFS, M_WAITOK | M_ZERO);
394: statvfs_arg->pvfsr_pid = puffs_lwp2pid(l);
395:
396: error = puffs_vfstouser(pmp, PUFFS_VFS_STATVFS,
397: statvfs_arg, sizeof(*statvfs_arg));
1.11 pooka 398: statvfs_arg->pvfsr_sb.f_iosize = DEV_BSIZE;
1.10 pooka 399:
1.1 pooka 400: /*
401: * Try to produce a sensible result even in the event
402: * of userspace error.
403: *
404: * XXX: cache the copy in non-error case
405: */
406: if (!error) {
407: copy_statvfs_info(&statvfs_arg->pvfsr_sb, mp);
408: (void)memcpy(sbp, &statvfs_arg->pvfsr_sb,
409: sizeof(struct statvfs));
410: } else {
411: copy_statvfs_info(sbp, mp);
412: }
413:
414: FREE(statvfs_arg, M_PUFFS);
1.14 pooka 415: return error;
1.1 pooka 416: }
417:
418: int
419: puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
420: struct lwp *l)
421: {
1.18 pooka 422: struct vnode *vp, *nvp;
423: int error, rv;
1.21 pooka 424: int ppflags;
1.1 pooka 425:
426: PUFFS_VFSREQ(sync);
427:
1.18 pooka 428: error = 0;
1.21 pooka 429: ppflags = PGO_CLEANIT | PGO_ALLPAGES;
430: if (waitfor == MNT_WAIT)
431: ppflags |= PGO_SYNCIO;
1.18 pooka 432:
433: /*
1.24 pooka 434: * Sync all cached data from regular vnodes (which are not
435: * currently locked, see below). After this we call VFS_SYNC
436: * for the fs server, which should handle data and metadata for
437: * all the nodes it knows to exist.
1.18 pooka 438: */
439: simple_lock(&mntvnode_slock);
440: loop:
441: for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
442: /* check if we're on the right list */
443: if (vp->v_mount != mp)
444: goto loop;
445:
446: simple_lock(&vp->v_interlock);
447: nvp = TAILQ_NEXT(vp, v_mntvnodes);
448:
1.19 pooka 449: if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) {
1.18 pooka 450: simple_unlock(&vp->v_interlock);
451: continue;
452: }
453:
454: simple_unlock(&mntvnode_slock);
1.21 pooka 455:
456: /*
457: * Here we try to get a reference to the vnode and to
458: * lock it. This is mostly cargo-culted, but I will
459: * offer an explanation to why I believe this might
460: * actually do the right thing.
461: *
462: * If the vnode is a goner, we quite obviously don't need
463: * to sync it.
464: *
465: * If the vnode was busy, we don't need to sync it because
466: * this is never called with MNT_WAIT except from
467: * dounmount(), when we are wait-flushing all the dirty
468: * vnodes through other routes in any case. So there,
469: * sync() doesn't actually sync. Happy now?
470: */
1.18 pooka 471: rv = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
472: if (rv) {
473: simple_lock(&mntvnode_slock);
474: if (rv == ENOENT)
475: goto loop;
476: continue;
477: }
478:
1.21 pooka 479: simple_lock(&vp->v_interlock);
480: rv = VOP_PUTPAGES(vp, 0, 0, ppflags);
481: if (rv)
1.18 pooka 482: error = rv;
483: vput(vp);
484: simple_lock(&mntvnode_slock);
485: }
486: simple_unlock(&mntvnode_slock);
487:
488: /* sync fs */
1.1 pooka 489: sync_arg.pvfsr_waitfor = waitfor;
490: puffs_credcvt(&sync_arg.pvfsr_cred, cred);
491: sync_arg.pvfsr_pid = puffs_lwp2pid(l);
492:
1.18 pooka 493: rv = puffs_vfstouser(MPTOPUFFSMP(mp), PUFFS_VFS_SYNC,
1.1 pooka 494: &sync_arg, sizeof(sync_arg));
1.18 pooka 495: if (rv)
496: error = rv;
1.1 pooka 497:
498: return error;
499: }
500:
501: int
502: puffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
503: {
504:
505: return EOPNOTSUPP;
506: }
507:
508: #if 0
509: /*ARGSUSED*/
510: int
511: puffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
512: {
513:
514: return EOPNOTSUPP;
515: }
516:
517: /*ARGSUSED*/
518: int
519: puffs_vptofh(struct vnode *vp, struct fid *fhp)
520: {
521:
522: return EOPNOTSUPP;
523: }
524: #endif
525:
526: void
527: puffs_init()
528: {
529:
1.5 pooka 530: #ifdef _LKM
531: malloc_type_attach(M_PUFFS);
532: pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
533: "puffspnpl", &pool_allocator_nointr);
534: #endif
535:
1.1 pooka 536: return;
537: }
538:
539: void
540: puffs_done()
541: {
542:
1.5 pooka 543: #ifdef _LKM
544: pool_destroy(&puffs_pnpool);
545: malloc_type_detach(M_PUFFS);
546: #endif
547:
1.1 pooka 548: return;
549: }
550:
551: int
552: puffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
553: {
554:
555: return EOPNOTSUPP;
556: }
557:
558: const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
559: &puffs_vnodeop_opv_desc,
1.3 pooka 560: &puffs_specop_opv_desc,
1.4 pooka 561: &puffs_fifoop_opv_desc,
1.12 pooka 562: &puffs_msgop_opv_desc,
1.1 pooka 563: NULL,
564: };
565:
566: struct vfsops puffs_vfsops = {
567: MOUNT_PUFFS,
568: puffs_mount, /* mount */
569: puffs_start, /* start */
570: puffs_unmount, /* unmount */
571: puffs_root, /* root */
572: puffs_quotactl, /* quotactl */
573: puffs_statvfs, /* statvfs */
574: puffs_sync, /* sync */
575: puffs_vget, /* vget */
1.15 chs 576: (void *)eopnotsupp, /* fhtovp */
577: (void *)eopnotsupp, /* vptofh */
1.1 pooka 578: puffs_init, /* init */
579: NULL, /* reinit */
580: puffs_done, /* done */
581: NULL, /* mountroot */
582: puffs_snapshot, /* snapshot */
583: vfs_stdextattrctl, /* extattrctl */
1.23 hannken 584: vfs_stdsuspendctl, /* suspendctl */
1.1 pooka 585: puffs_vnodeopv_descs, /* vnodeops */
586: 0, /* refcount */
587: { NULL, NULL }
588: };
589: VFS_ATTACH(puffs_vfsops);
CVSweb <webmaster@jp.NetBSD.org>