Annotation of src/sys/fs/puffs/puffs_vfsops.c, Revision 1.43
1.43 ! pooka 1: /* $NetBSD: puffs_vfsops.c,v 1.42 2007/05/17 13:59:22 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.43 ! pooka 33: __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.42 2007/05/17 13:59:22 pooka Exp $");
1.1 pooka 34:
35: #include <sys/param.h>
36: #include <sys/mount.h>
37: #include <sys/malloc.h>
38: #include <sys/extattr.h>
39: #include <sys/queue.h>
40: #include <sys/vnode.h>
41: #include <sys/dirent.h>
42: #include <sys/kauth.h>
1.26 pooka 43: #include <sys/fstrans.h>
1.1 pooka 44:
45: #include <lib/libkern/libkern.h>
46:
47: #include <fs/puffs/puffs_msgif.h>
48: #include <fs/puffs/puffs_sys.h>
49:
1.38 pooka 50: #include <nfs/nfsproto.h> /* for fh sizes */
51:
1.1 pooka 52: VFS_PROTOS(puffs);
53:
1.32 pooka 54: MALLOC_JUSTDEFINE(M_PUFFS, "puffs", "Pass-to-Userspace Framework File System");
1.1 pooka 55:
1.22 pooka 56: #ifndef PUFFS_PNODEBUCKETS
57: #define PUFFS_PNODEBUCKETS 256
58: #endif
59: #ifndef PUFFS_MAXPNODEBUCKETS
1.35 pooka 60: #define PUFFS_MAXPNODEBUCKETS 8192
1.22 pooka 61: #endif
1.35 pooka 62: int puffs_pnodebuckets_default = PUFFS_PNODEBUCKETS;
63: int puffs_maxpnodebuckets = PUFFS_MAXPNODEBUCKETS;
1.22 pooka 64:
1.1 pooka 65: int
66: puffs_mount(struct mount *mp, const char *path, void *data,
67: struct nameidata *ndp, struct lwp *l)
68: {
1.22 pooka 69: struct puffs_mount *pmp = NULL;
1.34 pooka 70: struct puffs_kargs *args;
1.17 pooka 71: char namebuf[PUFFSNAMESIZE+sizeof(PUFFS_NAMEPREFIX)+1]; /* spooky */
1.22 pooka 72: int error = 0, i;
1.1 pooka 73:
74: if (mp->mnt_flag & MNT_GETARGS) {
75: pmp = MPTOPUFFSMP(mp);
1.34 pooka 76: return copyout(&pmp->pmp_args,data,sizeof(struct puffs_kargs));
1.1 pooka 77: }
78:
79: /* update is not supported currently */
80: if (mp->mnt_flag & MNT_UPDATE)
81: return EOPNOTSUPP;
82:
83: /*
84: * We need the file system name
85: */
86: if (!data)
87: return EINVAL;
88:
1.34 pooka 89: MALLOC(args, struct puffs_kargs *, sizeof(struct puffs_kargs),
1.17 pooka 90: M_PUFFS, M_WAITOK);
91:
1.34 pooka 92: error = copyin(data, args, sizeof(struct puffs_kargs));
1.1 pooka 93: if (error)
1.17 pooka 94: goto out;
95:
96: /* devel phase */
97: if (args->pa_vers != (PUFFSVERSION | PUFFSDEVELVERS)) {
98: printf("puffs_mount: development version mismatch\n");
99: error = EINVAL;
100: goto out;
101: }
1.1 pooka 102:
1.8 pooka 103: /* nuke spy bits */
1.17 pooka 104: args->pa_flags &= PUFFS_KFLAG_MASK;
1.8 pooka 105:
1.38 pooka 106: /* sanitize file handle length */
107: if (PUFFS_TOFHSIZE(args->pa_fhsize) > FHANDLE_SIZE_MAX) {
108: printf("puffs_mount: handle size %zu too large\n",
109: args->pa_fhsize);
110: error = EINVAL;
111: goto out;
112: }
113: /* sanity check file handle max sizes */
114: if (args->pa_fhsize && args->pa_fhflags & PUFFS_FHFLAG_PROTOMASK) {
115: size_t kfhsize = PUFFS_TOFHSIZE(args->pa_fhsize);
116:
117: if (args->pa_fhflags & PUFFS_FHFLAG_NFSV2) {
118: if (NFSX_FHTOOBIG_P(kfhsize, 0)) {
119: printf("puffs_mount: fhsize larger than "
120: "NFSv2 max %d\n",
121: PUFFS_FROMFHSIZE(NFSX_V2FH));
122: error = EINVAL;
123: goto out;
124: }
125: }
126:
127: if (args->pa_fhflags & PUFFS_FHFLAG_NFSV3) {
128: if (NFSX_FHTOOBIG_P(kfhsize, 1)) {
129: printf("puffs_mount: fhsize larger than "
130: "NFSv3 max %d\n",
131: PUFFS_FROMFHSIZE(NFSX_V3FHMAX));
132: error = EINVAL;
133: goto out;
134: }
135: }
136: }
137:
1.1 pooka 138: /* build real name */
1.17 pooka 139: (void)strlcpy(namebuf, PUFFS_NAMEPREFIX, sizeof(namebuf));
140: (void)strlcat(namebuf, args->pa_name, sizeof(namebuf));
1.1 pooka 141:
142: /* inform user server if it got the max request size it wanted */
1.17 pooka 143: if (args->pa_maxreqlen == 0 || args->pa_maxreqlen > PUFFS_REQ_MAXSIZE)
144: args->pa_maxreqlen = PUFFS_REQ_MAXSIZE;
145: else if (args->pa_maxreqlen < PUFFS_REQSTRUCT_MAX)
146: args->pa_maxreqlen = PUFFS_REQSTRUCT_MAX;
147: (void)strlcpy(args->pa_name, namebuf, sizeof(args->pa_name));
1.1 pooka 148:
1.40 pooka 149: if (args->pa_nhashbuckets == 0)
150: args->pa_nhashbuckets = puffs_pnodebuckets_default;
151: if (args->pa_nhashbuckets < 1)
152: args->pa_nhashbuckets = 1;
153: if (args->pa_nhashbuckets > PUFFS_MAXPNODEBUCKETS) {
154: args->pa_nhashbuckets = puffs_maxpnodebuckets;
155: printf("puffs_mount: using %d hash buckets. "
156: "adjust puffs_maxpnodebuckets for more\n",
157: puffs_maxpnodebuckets);
158: }
159:
1.34 pooka 160: error = copyout(args, data, sizeof(struct puffs_kargs));
1.1 pooka 161: if (error)
1.17 pooka 162: goto out;
1.1 pooka 163:
164: error = set_statvfs_info(path, UIO_USERSPACE, namebuf,
165: UIO_SYSSPACE, mp, l);
166: if (error)
1.17 pooka 167: goto out;
1.10 pooka 168: mp->mnt_stat.f_iosize = DEV_BSIZE;
1.1 pooka 169:
1.42 pooka 170: /*
171: * We can't handle the VFS_STATVFS() mount_domount() does
172: * after VFS_MOUNT() because we'd deadlock, so handle it
173: * here already.
174: */
175: copy_statvfs_info(&args->pa_svfsb, mp);
176: (void)memcpy(&mp->mnt_stat, &args->pa_svfsb, sizeof(mp->mnt_stat));
177:
1.1 pooka 178: MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount),
179: M_PUFFS, M_WAITOK | M_ZERO);
180:
1.6 pooka 181: mp->mnt_fs_bshift = DEV_BSHIFT;
182: mp->mnt_dev_bshift = DEV_BSHIFT;
183: mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
1.1 pooka 184: mp->mnt_data = pmp;
1.26 pooka 185: mp->mnt_iflag |= IMNT_HAS_TRANS;
1.6 pooka 186:
1.1 pooka 187: pmp->pmp_status = PUFFSTAT_MOUNTING;
188: pmp->pmp_nextreq = 0;
189: pmp->pmp_mp = mp;
1.17 pooka 190: pmp->pmp_req_maxsize = args->pa_maxreqlen;
191: pmp->pmp_args = *args;
1.1 pooka 192:
1.40 pooka 193: pmp->pmp_npnodehash = args->pa_nhashbuckets;
1.22 pooka 194: pmp->pmp_pnodehash = malloc
195: (sizeof(struct puffs_pnode_hashlist *) * pmp->pmp_npnodehash,
196: M_PUFFS, M_WAITOK);
197: for (i = 0; i < pmp->pmp_npnodehash; i++)
198: LIST_INIT(&pmp->pmp_pnodehash[i]);
199:
1.1 pooka 200: /*
201: * Inform the fileops processing code that we have a mountpoint.
202: * If it doesn't know about anyone with our pid/fd having the
203: * device open, punt
204: */
1.17 pooka 205: if (puffs_setpmp(l->l_proc->p_pid, args->pa_fd, pmp)) {
206: error = ENOENT;
207: goto out;
1.1 pooka 208: }
209:
1.42 pooka 210: /* XXX: check parameters */
211: pmp->pmp_root_cookie = args->pa_root_cookie;
212: pmp->pmp_root_vtype = args->pa_root_vtype;
213: pmp->pmp_root_vsize = args->pa_root_vsize;
214: pmp->pmp_root_rdev = args->pa_root_rdev;
215:
1.31 pooka 216: mutex_init(&pmp->pmp_lock, MUTEX_DEFAULT, IPL_NONE);
217: cv_init(&pmp->pmp_req_waiter_cv, "puffsget");
1.41 pooka 218: cv_init(&pmp->pmp_refcount_cv, "puffsref");
1.31 pooka 219: cv_init(&pmp->pmp_unmounting_cv, "puffsum");
1.1 pooka 220: TAILQ_INIT(&pmp->pmp_req_touser);
221: TAILQ_INIT(&pmp->pmp_req_replywait);
222: TAILQ_INIT(&pmp->pmp_req_sizepark);
223:
224: DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
225: mp, MPTOPUFFSMP(mp)));
226:
227: vfs_getnewfsid(mp);
228:
1.17 pooka 229: out:
1.22 pooka 230: if (error && pmp && pmp->pmp_pnodehash)
231: free(pmp->pmp_pnodehash, M_PUFFS);
232: if (error && pmp)
233: FREE(pmp, M_PUFFS);
1.17 pooka 234: FREE(args, M_PUFFS);
235: return error;
1.1 pooka 236: }
237:
238: int
1.42 pooka 239: puffs_start(struct mount *mp, int flags, struct lwp *l)
1.1 pooka 240: {
1.42 pooka 241: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.1 pooka 242:
1.42 pooka 243: KASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING);
1.1 pooka 244: pmp->pmp_status = PUFFSTAT_RUNNING;
245:
246: return 0;
247: }
248:
249: int
250: puffs_unmount(struct mount *mp, int mntflags, struct lwp *l)
251: {
252: struct puffs_mount *pmp;
253: int error, force;
254:
255: PUFFS_VFSREQ(unmount);
256:
257: error = 0;
258: force = mntflags & MNT_FORCE;
259: pmp = MPTOPUFFSMP(mp);
260:
261: DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
262: "status 0x%x\n", pmp->pmp_status));
263:
264: /*
265: * flush all the vnodes. VOP_RECLAIM() takes care that the
266: * root vnode does not get flushed until unmount. The
267: * userspace root node cookie is stored in the mount
268: * structure, so we can always re-instantiate a root vnode,
269: * should userspace unmount decide it doesn't want to
270: * cooperate.
271: */
272: error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
273: if (error)
274: goto out;
275:
276: /*
277: * If we are not DYING, we should ask userspace's opinion
278: * about the situation
279: */
1.31 pooka 280: mutex_enter(&pmp->pmp_lock);
1.1 pooka 281: if (pmp->pmp_status != PUFFSTAT_DYING) {
1.16 pooka 282: pmp->pmp_unmounting = 1;
1.31 pooka 283: mutex_exit(&pmp->pmp_lock);
1.16 pooka 284:
1.1 pooka 285: unmount_arg.pvfsr_flags = mntflags;
286: unmount_arg.pvfsr_pid = puffs_lwp2pid(l);
1.16 pooka 287:
1.1 pooka 288: error = puffs_vfstouser(pmp, PUFFS_VFS_UNMOUNT,
289: &unmount_arg, sizeof(unmount_arg));
1.16 pooka 290: DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
291:
1.31 pooka 292: mutex_enter(&pmp->pmp_lock);
1.16 pooka 293: pmp->pmp_unmounting = 0;
1.31 pooka 294: cv_broadcast(&pmp->pmp_unmounting_cv);
1.1 pooka 295: }
296:
297: /*
298: * if userspace cooperated or we really need to die,
299: * screw what userland thinks and just die.
300: */
301: if (error == 0 || force) {
1.26 pooka 302: /* tell waiters & other resources to go unwait themselves */
303: puffs_userdead(pmp);
1.1 pooka 304: puffs_nukebypmp(pmp);
1.26 pooka 305:
306: /*
1.41 pooka 307: * Wait until there are no more users for the mount resource.
308: * Notice that this is hooked against transport_close
309: * and return from touser. In an ideal world, it would
310: * be hooked against final return from all operations.
311: * But currently it works well enough, since nobody
312: * does weird blocking voodoo after return from touser().
1.26 pooka 313: */
1.41 pooka 314: while (pmp->pmp_refcount != 0)
315: cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock);
1.31 pooka 316: mutex_exit(&pmp->pmp_lock);
1.26 pooka 317:
318: /* free resources now that we hopefully have no waiters left */
1.41 pooka 319: cv_destroy(&pmp->pmp_unmounting_cv);
320: cv_destroy(&pmp->pmp_refcount_cv);
1.31 pooka 321: cv_destroy(&pmp->pmp_req_waiter_cv);
322: mutex_destroy(&pmp->pmp_lock);
323:
1.22 pooka 324: free(pmp->pmp_pnodehash, M_PUFFS);
1.1 pooka 325: FREE(pmp, M_PUFFS);
326: error = 0;
1.16 pooka 327: } else {
1.31 pooka 328: mutex_exit(&pmp->pmp_lock);
1.1 pooka 329: }
330:
331: out:
1.2 pooka 332: DPRINTF(("puffs_unmount: return %d\n", error));
1.1 pooka 333: return error;
334: }
335:
336: /*
337: * This doesn't need to travel to userspace
338: */
339: int
340: puffs_root(struct mount *mp, struct vnode **vpp)
341: {
342: struct puffs_mount *pmp;
343: struct puffs_node *pn;
344: struct vnode *vp;
345:
346: pmp = MPTOPUFFSMP(mp);
347:
348: /*
349: * pmp_lock must be held if vref()'ing or vrele()'ing the
1.20 pooka 350: * root vnode. the latter is controlled by puffs_inactive().
1.1 pooka 351: */
1.31 pooka 352: mutex_enter(&pmp->pmp_lock);
1.1 pooka 353: vp = pmp->pmp_root;
354: if (vp) {
1.25 pooka 355: simple_lock(&vp->v_interlock);
1.31 pooka 356: mutex_exit(&pmp->pmp_lock);
1.1 pooka 357: pn = VPTOPP(vp);
1.25 pooka 358: if (vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK))
1.20 pooka 359: goto grabnew;
1.1 pooka 360: *vpp = vp;
361: return 0;
1.25 pooka 362: } else
1.31 pooka 363: mutex_exit(&pmp->pmp_lock);
1.25 pooka 364:
365: /* XXX: this is wrong, so FIXME */
1.1 pooka 366: grabnew:
367:
368: /*
369: * So, didn't have the magic root vnode available.
370: * No matter, grab another an stuff it with the cookie.
371: */
1.42 pooka 372: if (puffs_getvnode(mp, pmp->pmp_root_cookie, pmp->pmp_root_vtype,
373: pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp))
1.1 pooka 374: panic("sloppy programming");
375:
1.31 pooka 376: mutex_enter(&pmp->pmp_lock);
1.1 pooka 377: /*
378: * check if by mysterious force someone else created a root
379: * vnode while we were executing.
380: */
381: if (pmp->pmp_root) {
382: vref(pmp->pmp_root);
1.31 pooka 383: mutex_exit(&pmp->pmp_lock);
1.1 pooka 384: puffs_putvnode(vp);
385: vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
386: *vpp = pmp->pmp_root;
387: return 0;
388: }
389:
390: /* store cache */
391: vp->v_flag = VROOT;
392: pmp->pmp_root = vp;
1.31 pooka 393: mutex_exit(&pmp->pmp_lock);
1.1 pooka 394:
395: vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
396:
397: *vpp = vp;
398: return 0;
399: }
400:
401: int
402: puffs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
403: {
404: struct puffs_vfsreq_statvfs *statvfs_arg; /* too big for stack */
405: struct puffs_mount *pmp;
406: int error = 0;
407:
408: pmp = MPTOPUFFSMP(mp);
409:
410: /*
411: * If we are mounting, it means that the userspace counterpart
412: * is calling mount(2), but mount(2) also calls statvfs. So
413: * requesting statvfs from userspace would mean a deadlock.
414: * Compensate.
415: */
416: if (pmp->pmp_status == PUFFSTAT_MOUNTING)
417: return EINPROGRESS;
418:
419: /* too big for stack */
420: MALLOC(statvfs_arg, struct puffs_vfsreq_statvfs *,
421: sizeof(struct puffs_vfsreq_statvfs), M_PUFFS, M_WAITOK | M_ZERO);
422: statvfs_arg->pvfsr_pid = puffs_lwp2pid(l);
423:
424: error = puffs_vfstouser(pmp, PUFFS_VFS_STATVFS,
425: statvfs_arg, sizeof(*statvfs_arg));
1.11 pooka 426: statvfs_arg->pvfsr_sb.f_iosize = DEV_BSIZE;
1.10 pooka 427:
1.1 pooka 428: /*
429: * Try to produce a sensible result even in the event
430: * of userspace error.
431: *
432: * XXX: cache the copy in non-error case
433: */
434: if (!error) {
435: copy_statvfs_info(&statvfs_arg->pvfsr_sb, mp);
436: (void)memcpy(sbp, &statvfs_arg->pvfsr_sb,
437: sizeof(struct statvfs));
438: } else {
439: copy_statvfs_info(sbp, mp);
440: }
441:
442: FREE(statvfs_arg, M_PUFFS);
1.14 pooka 443: return error;
1.1 pooka 444: }
445:
1.26 pooka 446: static int
1.30 pooka 447: pageflush(struct mount *mp, kauth_cred_t cred,
448: int waitfor, int suspending, struct lwp *l)
1.1 pooka 449: {
1.26 pooka 450: struct puffs_node *pn;
1.18 pooka 451: struct vnode *vp, *nvp;
1.30 pooka 452: int error, rv;
1.1 pooka 453:
1.26 pooka 454: KASSERT(((waitfor == MNT_WAIT) && suspending) == 0);
455: KASSERT((suspending == 0)
456: || (fstrans_is_owner(mp)
1.27 hannken 457: && fstrans_getstate(mp) == FSTRANS_SUSPENDING));
1.1 pooka 458:
1.18 pooka 459: error = 0;
460:
461: /*
1.24 pooka 462: * Sync all cached data from regular vnodes (which are not
463: * currently locked, see below). After this we call VFS_SYNC
464: * for the fs server, which should handle data and metadata for
465: * all the nodes it knows to exist.
1.18 pooka 466: */
467: simple_lock(&mntvnode_slock);
468: loop:
469: for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
470: /* check if we're on the right list */
471: if (vp->v_mount != mp)
472: goto loop;
473:
474: simple_lock(&vp->v_interlock);
1.26 pooka 475: pn = VPTOPP(vp);
1.18 pooka 476: nvp = TAILQ_NEXT(vp, v_mntvnodes);
477:
1.19 pooka 478: if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) {
1.18 pooka 479: simple_unlock(&vp->v_interlock);
480: continue;
481: }
482:
483: simple_unlock(&mntvnode_slock);
1.21 pooka 484:
485: /*
486: * Here we try to get a reference to the vnode and to
487: * lock it. This is mostly cargo-culted, but I will
488: * offer an explanation to why I believe this might
489: * actually do the right thing.
490: *
491: * If the vnode is a goner, we quite obviously don't need
492: * to sync it.
493: *
494: * If the vnode was busy, we don't need to sync it because
495: * this is never called with MNT_WAIT except from
496: * dounmount(), when we are wait-flushing all the dirty
497: * vnodes through other routes in any case. So there,
498: * sync() doesn't actually sync. Happy now?
1.26 pooka 499: *
500: * NOTE: if we're suspending, vget() does NOT lock.
501: * See puffs_lock() for details.
1.21 pooka 502: */
1.18 pooka 503: rv = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
504: if (rv) {
505: simple_lock(&mntvnode_slock);
506: if (rv == ENOENT)
507: goto loop;
508: continue;
509: }
510:
1.26 pooka 511: /*
512: * Thread information to puffs_strategy() through the
513: * pnode flags: we want to issue the putpages operations
514: * as FAF if we're suspending, since it's very probable
515: * that our execution context is that of the userspace
516: * daemon. We can do this because:
517: * + we send the "going to suspend" prior to this part
518: * + if any of the writes fails in userspace, it's the
519: * file system server's problem to decide if this was a
520: * failed snapshot when it gets the "snapshot complete"
521: * notification.
522: * + if any of the writes fail in the kernel already, we
523: * immediately fail *and* notify the user server of
524: * failure.
525: *
526: * We also do FAFs if we're called from the syncer. This
527: * is just general optimization for trickle sync: no need
528: * to really guarantee that the stuff ended on backing
529: * storage.
530: * TODO: Maybe also hint the user server of this twist?
531: */
1.30 pooka 532: if (suspending || waitfor == MNT_LAZY) {
533: simple_lock(&vp->v_interlock);
1.26 pooka 534: pn->pn_stat |= PNODE_SUSPEND;
1.30 pooka 535: simple_unlock(&vp->v_interlock);
536: }
537: rv = VOP_FSYNC(vp, cred, waitfor, 0, 0, l);
1.26 pooka 538: if (suspending || waitfor == MNT_LAZY) {
539: simple_lock(&vp->v_interlock);
540: pn->pn_stat &= ~PNODE_SUSPEND;
541: simple_unlock(&vp->v_interlock);
542: }
1.21 pooka 543: if (rv)
1.18 pooka 544: error = rv;
545: vput(vp);
546: simple_lock(&mntvnode_slock);
547: }
548: simple_unlock(&mntvnode_slock);
549:
1.26 pooka 550: return error;
551: }
552:
553: int
554: puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
555: struct lwp *l)
556: {
557: int error, rv;
558:
559: PUFFS_VFSREQ(sync);
560:
1.30 pooka 561: error = pageflush(mp, cred, waitfor, 0, l);
1.26 pooka 562:
1.18 pooka 563: /* sync fs */
1.1 pooka 564: sync_arg.pvfsr_waitfor = waitfor;
565: puffs_credcvt(&sync_arg.pvfsr_cred, cred);
566: sync_arg.pvfsr_pid = puffs_lwp2pid(l);
567:
1.18 pooka 568: rv = puffs_vfstouser(MPTOPUFFSMP(mp), PUFFS_VFS_SYNC,
1.1 pooka 569: &sync_arg, sizeof(sync_arg));
1.18 pooka 570: if (rv)
571: error = rv;
1.1 pooka 572:
573: return error;
574: }
575:
576: int
1.33 pooka 577: puffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1.1 pooka 578: {
1.33 pooka 579: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.38 pooka 580: struct puffs_vfsreq_fhtonode *fhtonode_argp;
1.33 pooka 581: struct vnode *vp;
1.38 pooka 582: size_t argsize;
1.33 pooka 583: int error;
584:
1.38 pooka 585: if (pmp->pmp_args.pa_fhsize == 0)
1.33 pooka 586: return EOPNOTSUPP;
587:
1.39 pooka 588: if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) {
589: if (pmp->pmp_args.pa_fhsize < PUFFS_FROMFHSIZE(fhp->fid_len))
590: return EINVAL;
591: } else {
592: if (pmp->pmp_args.pa_fhsize != PUFFS_FROMFHSIZE(fhp->fid_len))
593: return EINVAL;
594: }
1.33 pooka 595:
1.38 pooka 596: argsize = sizeof(struct puffs_vfsreq_fhtonode)
597: + PUFFS_FROMFHSIZE(fhp->fid_len);
598: fhtonode_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK);
599: fhtonode_argp->pvfsr_dsize = PUFFS_FROMFHSIZE(fhp->fid_len);
600: memcpy(fhtonode_argp->pvfsr_data, fhp->fid_data,
601: PUFFS_FROMFHSIZE(fhp->fid_len));
1.33 pooka 602:
1.38 pooka 603: error = puffs_vfstouser(pmp, PUFFS_VFS_FHTOVP, fhtonode_argp, argsize);
1.33 pooka 604: if (error)
1.38 pooka 605: goto out;
1.33 pooka 606:
1.38 pooka 607: vp = puffs_pnode2vnode(pmp, fhtonode_argp->pvfsr_fhcookie, 1);
1.33 pooka 608: DPRINTF(("puffs_fhtovp: got cookie %p, existing vnode %p\n",
1.38 pooka 609: fhtonode_argp->pvfsr_fhcookie, vp));
1.33 pooka 610: if (!vp) {
1.38 pooka 611: error = puffs_getvnode(mp, fhtonode_argp->pvfsr_fhcookie,
612: fhtonode_argp->pvfsr_vtype, fhtonode_argp->pvfsr_size,
613: fhtonode_argp->pvfsr_rdev, &vp);
1.33 pooka 614: if (error)
1.38 pooka 615: goto out;
1.33 pooka 616: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
617: }
1.1 pooka 618:
1.33 pooka 619: *vpp = vp;
1.38 pooka 620: out:
621: free(fhtonode_argp, M_PUFFS);
622: return error;
1.1 pooka 623: }
624:
625: int
1.33 pooka 626: puffs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1 pooka 627: {
1.33 pooka 628: struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1.38 pooka 629: struct puffs_vfsreq_nodetofh *nodetofh_argp;
630: size_t argsize;
1.33 pooka 631: int error;
632:
1.38 pooka 633: if (pmp->pmp_args.pa_fhsize == 0)
1.33 pooka 634: return EOPNOTSUPP;
635:
1.38 pooka 636: /* if file handles are static length, we can return immediately */
637: if (((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) == 0)
638: && (PUFFS_FROMFHSIZE(*fh_size) < pmp->pmp_args.pa_fhsize)) {
639: *fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
1.33 pooka 640: return E2BIG;
641: }
1.1 pooka 642:
1.38 pooka 643: argsize = sizeof(struct puffs_vfsreq_nodetofh)
644: + PUFFS_FROMFHSIZE(*fh_size);
645: nodetofh_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK);
646: nodetofh_argp->pvfsr_fhcookie = VPTOPNC(vp);
647: nodetofh_argp->pvfsr_dsize = PUFFS_FROMFHSIZE(*fh_size);
648:
649: error = puffs_vfstouser(pmp, PUFFS_VFS_VPTOFH, nodetofh_argp, argsize);
650: if (error) {
651: if (error == E2BIG)
652: *fh_size = PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize);
653: goto out;
654: }
655:
656: if (PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize) > FHANDLE_SIZE_MAX) {
657: /* XXX: wrong direction */
658: error = EINVAL;
659: goto out;
660: }
1.33 pooka 661:
1.38 pooka 662: if (*fh_size < PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize)) {
663: *fh_size = PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize);
664: error = E2BIG;
665: goto out;
666: }
667: if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) {
668: *fh_size = PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize);
669: } else {
670: *fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
671: }
1.1 pooka 672:
1.38 pooka 673: if (fhp) {
674: fhp->fid_len = *fh_size;
675: memcpy(fhp->fid_data,
676: nodetofh_argp->pvfsr_data, nodetofh_argp->pvfsr_dsize);
677: }
1.1 pooka 678:
1.38 pooka 679: out:
680: free(nodetofh_argp, M_PUFFS);
681: return error;
1.1 pooka 682: }
683:
684: void
685: puffs_init()
686: {
687:
1.5 pooka 688: malloc_type_attach(M_PUFFS);
689:
1.31 pooka 690: pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
691: "puffpnpl", &pool_allocator_nointr, IPL_NONE);
692: puffs_transport_init();
693: puffs_msgif_init();
1.1 pooka 694: }
695:
696: void
697: puffs_done()
698: {
699:
1.31 pooka 700: puffs_msgif_destroy();
701: puffs_transport_destroy();
702: pool_destroy(&puffs_pnpool);
703:
1.5 pooka 704: malloc_type_detach(M_PUFFS);
1.1 pooka 705: }
706:
707: int
708: puffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
709: {
710:
711: return EOPNOTSUPP;
712: }
713:
1.26 pooka 714: int
715: puffs_suspendctl(struct mount *mp, int cmd)
716: {
717: struct puffs_mount *pmp;
718: int error;
719:
720: pmp = MPTOPUFFSMP(mp);
721: switch (cmd) {
722: case SUSPEND_SUSPEND:
723: DPRINTF(("puffs_suspendctl: suspending\n"));
1.27 hannken 724: if ((error = fstrans_setstate(mp, FSTRANS_SUSPENDING)) != 0)
1.26 pooka 725: break;
726: puffs_suspendtouser(pmp, PUFFS_SUSPEND_START);
727:
1.30 pooka 728: error = pageflush(mp, FSCRED, 0, 1, curlwp);
1.26 pooka 729: if (error == 0)
1.27 hannken 730: error = fstrans_setstate(mp, FSTRANS_SUSPENDED);
1.26 pooka 731:
732: if (error != 0) {
733: puffs_suspendtouser(pmp, PUFFS_SUSPEND_ERROR);
1.27 hannken 734: (void) fstrans_setstate(mp, FSTRANS_NORMAL);
1.26 pooka 735: break;
736: }
737:
738: puffs_suspendtouser(pmp, PUFFS_SUSPEND_SUSPENDED);
739:
740: break;
741:
742: case SUSPEND_RESUME:
743: DPRINTF(("puffs_suspendctl: resume\n"));
744: error = 0;
1.27 hannken 745: (void) fstrans_setstate(mp, FSTRANS_NORMAL);
1.26 pooka 746: puffs_suspendtouser(pmp, PUFFS_SUSPEND_RESUME);
747: break;
748:
749: default:
750: error = EINVAL;
751: break;
752: }
753:
754: DPRINTF(("puffs_suspendctl: return %d\n", error));
755: return error;
756: }
757:
1.1 pooka 758: const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
759: &puffs_vnodeop_opv_desc,
1.3 pooka 760: &puffs_specop_opv_desc,
1.4 pooka 761: &puffs_fifoop_opv_desc,
1.12 pooka 762: &puffs_msgop_opv_desc,
1.1 pooka 763: NULL,
764: };
765:
766: struct vfsops puffs_vfsops = {
767: MOUNT_PUFFS,
768: puffs_mount, /* mount */
769: puffs_start, /* start */
770: puffs_unmount, /* unmount */
771: puffs_root, /* root */
1.33 pooka 772: (void *)eopnotsupp, /* quotactl */
1.1 pooka 773: puffs_statvfs, /* statvfs */
774: puffs_sync, /* sync */
1.33 pooka 775: (void *)eopnotsupp, /* vget */
776: puffs_fhtovp, /* fhtovp */
777: puffs_vptofh, /* vptofh */
1.1 pooka 778: puffs_init, /* init */
779: NULL, /* reinit */
780: puffs_done, /* done */
781: NULL, /* mountroot */
782: puffs_snapshot, /* snapshot */
783: vfs_stdextattrctl, /* extattrctl */
1.26 pooka 784: puffs_suspendctl, /* suspendctl */
1.1 pooka 785: puffs_vnodeopv_descs, /* vnodeops */
786: 0, /* refcount */
787: { NULL, NULL }
788: };
789: VFS_ATTACH(puffs_vfsops);
CVSweb <webmaster@jp.NetBSD.org>