Annotation of src/sys/fs/puffs/puffs_vfsops.c, Revision 1.100.8.1
1.100.8.1! riz 1: /* $NetBSD$ */
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.100.8.1! riz 33: __KERNEL_RCSID(0, "$NetBSD$");
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.47 ad 43: #include <sys/proc.h>
1.80 rumble 44: #include <sys/module.h>
1.84 pooka 45: #include <sys/kthread.h>
1.1 pooka 46:
1.99 manu 47: #include <uvm/uvm.h>
48:
1.68 pooka 49: #include <dev/putter/putter_sys.h>
1.1 pooka 50:
1.78 dholland 51: #include <miscfs/genfs/genfs.h>
52:
1.1 pooka 53: #include <fs/puffs/puffs_msgif.h>
54: #include <fs/puffs/puffs_sys.h>
55:
1.66 pooka 56: #include <lib/libkern/libkern.h>
57:
1.38 pooka 58: #include <nfs/nfsproto.h> /* for fh sizes */
59:
1.81 jmcneill 60: MODULE(MODULE_CLASS_VFS, puffs, "putter");
1.80 rumble 61:
1.73 pooka 62: VFS_PROTOS(puffs_vfsop);
1.1 pooka 63:
1.22 pooka 64: #ifndef PUFFS_PNODEBUCKETS
65: #define PUFFS_PNODEBUCKETS 256
66: #endif
67: #ifndef PUFFS_MAXPNODEBUCKETS
1.35 pooka 68: #define PUFFS_MAXPNODEBUCKETS 8192
1.22 pooka 69: #endif
1.35 pooka 70: int puffs_pnodebuckets_default = PUFFS_PNODEBUCKETS;
71: int puffs_maxpnodebuckets = PUFFS_MAXPNODEBUCKETS;
1.22 pooka 72:
1.70 pooka 73: #define BUCKETALLOC(a) (sizeof(struct puffs_pnode_hashlist *) * (a))
74:
1.66 pooka 75: static struct putter_ops puffs_putter = {
76: .pop_getout = puffs_msgif_getout,
77: .pop_releaseout = puffs_msgif_releaseout,
78: .pop_waitcount = puffs_msgif_waitcount,
79: .pop_dispatch = puffs_msgif_dispatch,
80: .pop_close = puffs_msgif_close,
81: };
82:
1.92 pooka 83: /*
84: * Try to ensure data structures used by the puffs protocol
85: * do not unexpectedly change.
86: */
87: #ifdef __i386__
88: CTASSERT(sizeof(struct puffs_kargs) == 3928);
89: CTASSERT(sizeof(struct vattr) == 136);
90: CTASSERT(sizeof(struct puffs_req) == 44);
91: #endif
92:
1.1 pooka 93: int
1.73 pooka 94: puffs_vfsop_mount(struct mount *mp, const char *path, void *data,
95: size_t *data_len)
1.1 pooka 96: {
1.22 pooka 97: struct puffs_mount *pmp = NULL;
1.34 pooka 98: struct puffs_kargs *args;
1.51 pooka 99: char fstype[_VFS_NAMELEN];
100: char *p;
1.22 pooka 101: int error = 0, i;
1.71 pooka 102: pid_t mntpid = curlwp->l_proc->p_pid;
1.1 pooka 103:
1.48 dsl 104: if (*data_len < sizeof *args)
105: return EINVAL;
106:
1.1 pooka 107: if (mp->mnt_flag & MNT_GETARGS) {
108: pmp = MPTOPUFFSMP(mp);
1.48 dsl 109: *(struct puffs_kargs *)data = pmp->pmp_args;
110: *data_len = sizeof *args;
111: return 0;
1.1 pooka 112: }
113:
114: /* update is not supported currently */
115: if (mp->mnt_flag & MNT_UPDATE)
116: return EOPNOTSUPP;
117:
118: /*
119: * We need the file system name
120: */
121: if (!data)
122: return EINVAL;
123:
1.70 pooka 124: args = (struct puffs_kargs *)data;
1.17 pooka 125:
1.89 pooka 126: if (args->pa_vers != PUFFSVERSION) {
1.64 pooka 127: printf("puffs_mount: development version mismatch: "
1.89 pooka 128: "kernel %d, lib %d\n", PUFFSVERSION, args->pa_vers);
1.17 pooka 129: error = EINVAL;
130: goto out;
131: }
1.1 pooka 132:
1.54 pooka 133: if ((args->pa_flags & ~PUFFS_KFLAG_MASK) != 0) {
134: printf("puffs_mount: invalid KFLAGs 0x%x\n", args->pa_flags);
135: error = EINVAL;
136: goto out;
137: }
138: if ((args->pa_fhflags & ~PUFFS_FHFLAG_MASK) != 0) {
139: printf("puffs_mount: invalid FHFLAGs 0x%x\n", args->pa_fhflags);
140: error = EINVAL;
141: goto out;
142: }
143:
1.91 pooka 144: for (i = 0; i < __arraycount(args->pa_spare); i++) {
145: if (args->pa_spare[i] != 0) {
146: printf("puffs_mount: pa_spare[%d] = 0x%x\n",
147: i, args->pa_spare[i]);
148: error = EINVAL;
149: goto out;
150: }
151: }
152:
1.54 pooka 153: /* use dummy value for passthrough */
154: if (args->pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
155: args->pa_fhsize = sizeof(struct fid);
1.8 pooka 156:
1.38 pooka 157: /* sanitize file handle length */
158: if (PUFFS_TOFHSIZE(args->pa_fhsize) > FHANDLE_SIZE_MAX) {
159: printf("puffs_mount: handle size %zu too large\n",
160: args->pa_fhsize);
161: error = EINVAL;
162: goto out;
163: }
164: /* sanity check file handle max sizes */
165: if (args->pa_fhsize && args->pa_fhflags & PUFFS_FHFLAG_PROTOMASK) {
166: size_t kfhsize = PUFFS_TOFHSIZE(args->pa_fhsize);
167:
168: if (args->pa_fhflags & PUFFS_FHFLAG_NFSV2) {
169: if (NFSX_FHTOOBIG_P(kfhsize, 0)) {
170: printf("puffs_mount: fhsize larger than "
171: "NFSv2 max %d\n",
172: PUFFS_FROMFHSIZE(NFSX_V2FH));
173: error = EINVAL;
174: goto out;
175: }
176: }
177:
178: if (args->pa_fhflags & PUFFS_FHFLAG_NFSV3) {
179: if (NFSX_FHTOOBIG_P(kfhsize, 1)) {
180: printf("puffs_mount: fhsize larger than "
181: "NFSv3 max %d\n",
182: PUFFS_FROMFHSIZE(NFSX_V3FHMAX));
183: error = EINVAL;
184: goto out;
185: }
186: }
187: }
188:
1.51 pooka 189: /* don't allow non-printing characters (like my sweet umlauts.. snif) */
190: args->pa_typename[sizeof(args->pa_typename)-1] = '\0';
191: for (p = args->pa_typename; *p; p++)
192: if (*p < ' ' || *p > '~')
193: *p = '.';
194:
195: args->pa_mntfromname[sizeof(args->pa_mntfromname)-1] = '\0';
196: for (p = args->pa_mntfromname; *p; p++)
197: if (*p < ' ' || *p > '~')
198: *p = '.';
199:
1.1 pooka 200: /* build real name */
1.51 pooka 201: (void)strlcpy(fstype, PUFFS_TYPEPREFIX, sizeof(fstype));
202: (void)strlcat(fstype, args->pa_typename, sizeof(fstype));
1.1 pooka 203:
204: /* inform user server if it got the max request size it wanted */
1.63 pooka 205: if (args->pa_maxmsglen == 0 || args->pa_maxmsglen > PUFFS_MSG_MAXSIZE)
206: args->pa_maxmsglen = PUFFS_MSG_MAXSIZE;
207: else if (args->pa_maxmsglen < 2*PUFFS_MSGSTRUCT_MAX)
208: args->pa_maxmsglen = 2*PUFFS_MSGSTRUCT_MAX;
209:
1.51 pooka 210: (void)strlcpy(args->pa_typename, fstype, sizeof(args->pa_typename));
1.1 pooka 211:
1.40 pooka 212: if (args->pa_nhashbuckets == 0)
213: args->pa_nhashbuckets = puffs_pnodebuckets_default;
214: if (args->pa_nhashbuckets < 1)
215: args->pa_nhashbuckets = 1;
216: if (args->pa_nhashbuckets > PUFFS_MAXPNODEBUCKETS) {
217: args->pa_nhashbuckets = puffs_maxpnodebuckets;
218: printf("puffs_mount: using %d hash buckets. "
219: "adjust puffs_maxpnodebuckets for more\n",
220: puffs_maxpnodebuckets);
221: }
222:
1.51 pooka 223: error = set_statvfs_info(path, UIO_USERSPACE, args->pa_mntfromname,
1.71 pooka 224: UIO_SYSSPACE, fstype, mp, curlwp);
1.1 pooka 225: if (error)
1.17 pooka 226: goto out;
1.10 pooka 227: mp->mnt_stat.f_iosize = DEV_BSIZE;
1.94 pooka 228: mp->mnt_stat.f_namemax = args->pa_svfsb.f_namemax;
1.1 pooka 229:
1.42 pooka 230: /*
231: * We can't handle the VFS_STATVFS() mount_domount() does
232: * after VFS_MOUNT() because we'd deadlock, so handle it
233: * here already.
234: */
235: copy_statvfs_info(&args->pa_svfsb, mp);
236: (void)memcpy(&mp->mnt_stat, &args->pa_svfsb, sizeof(mp->mnt_stat));
237:
1.99 manu 238: KASSERT(curlwp != uvm.pagedaemon_lwp);
1.70 pooka 239: pmp = kmem_zalloc(sizeof(struct puffs_mount), KM_SLEEP);
1.1 pooka 240:
1.6 pooka 241: mp->mnt_fs_bshift = DEV_BSHIFT;
242: mp->mnt_dev_bshift = DEV_BSHIFT;
243: mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
1.1 pooka 244: mp->mnt_data = pmp;
1.6 pooka 245:
1.87 pooka 246: #if 0
247: /*
248: * XXX: puffs code is MPSAFE. However, VFS really isn't.
249: * Currently, there is nothing which protects an inode from
250: * reclaim while there are threads inside the file system.
251: * This means that in the event of a server crash, an MPSAFE
252: * mount is likely to end up accessing invalid memory. For the
253: * non-mpsafe case, the kernel lock, general structure of
254: * puffs and pmp_refcount protect the threads during escape.
255: *
256: * Fixing this will require:
257: * a) fixing vfs
258: * OR
259: * b) adding a small sleep to puffs_msgif_close() between
260: * userdead() and dounmount().
261: * (well, this isn't really a fix, but would solve
262: * 99.999% of the race conditions).
263: *
264: * Also, in the event of "b", unmount -f should be used,
265: * like with any other file system, sparingly and only when
266: * it is "known" to be safe.
267: */
268: mp->mnt_iflags |= IMNT_MPSAFE;
269: #endif
270:
1.1 pooka 271: pmp->pmp_status = PUFFSTAT_MOUNTING;
272: pmp->pmp_mp = mp;
1.63 pooka 273: pmp->pmp_msg_maxsize = args->pa_maxmsglen;
1.17 pooka 274: pmp->pmp_args = *args;
1.1 pooka 275:
1.40 pooka 276: pmp->pmp_npnodehash = args->pa_nhashbuckets;
1.87 pooka 277: pmp->pmp_pnodehash = kmem_alloc(BUCKETALLOC(pmp->pmp_npnodehash),
278: KM_SLEEP);
1.22 pooka 279: for (i = 0; i < pmp->pmp_npnodehash; i++)
280: LIST_INIT(&pmp->pmp_pnodehash[i]);
1.57 pooka 281: LIST_INIT(&pmp->pmp_newcookie);
1.22 pooka 282:
1.1 pooka 283: /*
284: * Inform the fileops processing code that we have a mountpoint.
285: * If it doesn't know about anyone with our pid/fd having the
286: * device open, punt
287: */
1.66 pooka 288: if ((pmp->pmp_pi
289: = putter_attach(mntpid, args->pa_fd, pmp, &puffs_putter)) == NULL) {
1.17 pooka 290: error = ENOENT;
291: goto out;
1.1 pooka 292: }
293:
1.42 pooka 294: /* XXX: check parameters */
295: pmp->pmp_root_cookie = args->pa_root_cookie;
296: pmp->pmp_root_vtype = args->pa_root_vtype;
297: pmp->pmp_root_vsize = args->pa_root_vsize;
298: pmp->pmp_root_rdev = args->pa_root_rdev;
1.93 pooka 299: pmp->pmp_docompat = args->pa_time32;
1.42 pooka 300:
1.31 pooka 301: mutex_init(&pmp->pmp_lock, MUTEX_DEFAULT, IPL_NONE);
1.84 pooka 302: mutex_init(&pmp->pmp_sopmtx, MUTEX_DEFAULT, IPL_NONE);
1.63 pooka 303: cv_init(&pmp->pmp_msg_waiter_cv, "puffsget");
1.41 pooka 304: cv_init(&pmp->pmp_refcount_cv, "puffsref");
1.31 pooka 305: cv_init(&pmp->pmp_unmounting_cv, "puffsum");
1.84 pooka 306: cv_init(&pmp->pmp_sopcv, "puffsop");
1.63 pooka 307: TAILQ_INIT(&pmp->pmp_msg_touser);
308: TAILQ_INIT(&pmp->pmp_msg_replywait);
1.84 pooka 309: TAILQ_INIT(&pmp->pmp_sopreqs);
310:
311: if ((error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
312: puffs_sop_thread, pmp, NULL, "puffsop")) != 0)
313: goto out;
314: pmp->pmp_sopthrcount = 1;
1.1 pooka 315:
316: DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
317: mp, MPTOPUFFSMP(mp)));
318:
319: vfs_getnewfsid(mp);
320:
1.17 pooka 321: out:
1.84 pooka 322: if (error && pmp && pmp->pmp_pi)
323: putter_detach(pmp->pmp_pi);
1.22 pooka 324: if (error && pmp && pmp->pmp_pnodehash)
1.70 pooka 325: kmem_free(pmp->pmp_pnodehash, BUCKETALLOC(pmp->pmp_npnodehash));
1.22 pooka 326: if (error && pmp)
1.70 pooka 327: kmem_free(pmp, sizeof(struct puffs_mount));
1.17 pooka 328: return error;
1.1 pooka 329: }
330:
331: int
1.73 pooka 332: puffs_vfsop_start(struct mount *mp, int flags)
1.1 pooka 333: {
1.42 pooka 334: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.1 pooka 335:
1.42 pooka 336: KASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING);
1.1 pooka 337: pmp->pmp_status = PUFFSTAT_RUNNING;
338:
339: return 0;
340: }
341:
342: int
1.73 pooka 343: puffs_vfsop_unmount(struct mount *mp, int mntflags)
1.1 pooka 344: {
1.63 pooka 345: PUFFS_MSG_VARS(vfs, unmount);
1.1 pooka 346: struct puffs_mount *pmp;
347: int error, force;
348:
349: error = 0;
350: force = mntflags & MNT_FORCE;
351: pmp = MPTOPUFFSMP(mp);
352:
353: DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
354: "status 0x%x\n", pmp->pmp_status));
355:
356: /*
357: * flush all the vnodes. VOP_RECLAIM() takes care that the
358: * root vnode does not get flushed until unmount. The
359: * userspace root node cookie is stored in the mount
360: * structure, so we can always re-instantiate a root vnode,
361: * should userspace unmount decide it doesn't want to
362: * cooperate.
363: */
364: error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
365: if (error)
366: goto out;
367:
368: /*
369: * If we are not DYING, we should ask userspace's opinion
370: * about the situation
371: */
1.31 pooka 372: mutex_enter(&pmp->pmp_lock);
1.1 pooka 373: if (pmp->pmp_status != PUFFSTAT_DYING) {
1.16 pooka 374: pmp->pmp_unmounting = 1;
1.31 pooka 375: mutex_exit(&pmp->pmp_lock);
1.16 pooka 376:
1.63 pooka 377: PUFFS_MSG_ALLOC(vfs, unmount);
1.69 pooka 378: puffs_msg_setinfo(park_unmount,
379: PUFFSOP_VFS, PUFFS_VFS_UNMOUNT, NULL);
1.63 pooka 380: unmount_msg->pvfsr_flags = mntflags;
381:
1.69 pooka 382: PUFFS_MSG_ENQUEUEWAIT(pmp, park_unmount, error);
1.63 pooka 383: PUFFS_MSG_RELEASE(unmount);
1.16 pooka 384:
1.60 pooka 385: error = checkerr(pmp, error, __func__);
1.16 pooka 386: DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
387:
1.31 pooka 388: mutex_enter(&pmp->pmp_lock);
1.16 pooka 389: pmp->pmp_unmounting = 0;
1.31 pooka 390: cv_broadcast(&pmp->pmp_unmounting_cv);
1.1 pooka 391: }
392:
393: /*
394: * if userspace cooperated or we really need to die,
395: * screw what userland thinks and just die.
396: */
397: if (error == 0 || force) {
1.84 pooka 398: struct puffs_sopreq *psopr;
399:
1.26 pooka 400: /* tell waiters & other resources to go unwait themselves */
401: puffs_userdead(pmp);
1.66 pooka 402: putter_detach(pmp->pmp_pi);
1.26 pooka 403:
404: /*
1.41 pooka 405: * Wait until there are no more users for the mount resource.
406: * Notice that this is hooked against transport_close
407: * and return from touser. In an ideal world, it would
408: * be hooked against final return from all operations.
409: * But currently it works well enough, since nobody
410: * does weird blocking voodoo after return from touser().
1.26 pooka 411: */
1.41 pooka 412: while (pmp->pmp_refcount != 0)
413: cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock);
1.31 pooka 414: mutex_exit(&pmp->pmp_lock);
1.26 pooka 415:
1.84 pooka 416: /*
417: * Release kernel thread now that there is nothing
418: * it would be wanting to lock.
419: */
1.99 manu 420: KASSERT(curlwp != uvm.pagedaemon_lwp);
1.84 pooka 421: psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP);
1.85 pooka 422: psopr->psopr_sopreq = PUFFS_SOPREQSYS_EXIT;
1.84 pooka 423: mutex_enter(&pmp->pmp_sopmtx);
1.86 pooka 424: if (pmp->pmp_sopthrcount == 0) {
425: mutex_exit(&pmp->pmp_sopmtx);
426: kmem_free(psopr, sizeof(*psopr));
427: mutex_enter(&pmp->pmp_sopmtx);
428: KASSERT(pmp->pmp_sopthrcount == 0);
429: } else {
430: TAILQ_INSERT_TAIL(&pmp->pmp_sopreqs,
431: psopr, psopr_entries);
432: cv_signal(&pmp->pmp_sopcv);
433: }
1.84 pooka 434: while (pmp->pmp_sopthrcount > 0)
435: cv_wait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx);
436: mutex_exit(&pmp->pmp_sopmtx);
437:
1.26 pooka 438: /* free resources now that we hopefully have no waiters left */
1.41 pooka 439: cv_destroy(&pmp->pmp_unmounting_cv);
440: cv_destroy(&pmp->pmp_refcount_cv);
1.63 pooka 441: cv_destroy(&pmp->pmp_msg_waiter_cv);
1.84 pooka 442: cv_destroy(&pmp->pmp_sopcv);
1.31 pooka 443: mutex_destroy(&pmp->pmp_lock);
1.84 pooka 444: mutex_destroy(&pmp->pmp_sopmtx);
1.31 pooka 445:
1.70 pooka 446: kmem_free(pmp->pmp_pnodehash, BUCKETALLOC(pmp->pmp_npnodehash));
447: kmem_free(pmp, sizeof(struct puffs_mount));
1.1 pooka 448: error = 0;
1.16 pooka 449: } else {
1.31 pooka 450: mutex_exit(&pmp->pmp_lock);
1.1 pooka 451: }
452:
453: out:
1.2 pooka 454: DPRINTF(("puffs_unmount: return %d\n", error));
1.1 pooka 455: return error;
456: }
457:
458: /*
459: * This doesn't need to travel to userspace
460: */
461: int
1.73 pooka 462: puffs_vfsop_root(struct mount *mp, struct vnode **vpp)
1.1 pooka 463: {
1.45 pooka 464: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.59 pooka 465: int rv;
1.1 pooka 466:
1.59 pooka 467: rv = puffs_cookie2vnode(pmp, pmp->pmp_root_cookie, 1, 1, vpp);
468: KASSERT(rv != PUFFS_NOSUCHCOOKIE);
469: return rv;
1.1 pooka 470: }
471:
472: int
1.73 pooka 473: puffs_vfsop_statvfs(struct mount *mp, struct statvfs *sbp)
1.1 pooka 474: {
1.63 pooka 475: PUFFS_MSG_VARS(vfs, statvfs);
1.1 pooka 476: struct puffs_mount *pmp;
477: int error = 0;
478:
479: pmp = MPTOPUFFSMP(mp);
480:
481: /*
482: * If we are mounting, it means that the userspace counterpart
483: * is calling mount(2), but mount(2) also calls statvfs. So
484: * requesting statvfs from userspace would mean a deadlock.
485: * Compensate.
486: */
1.87 pooka 487: if (__predict_false(pmp->pmp_status == PUFFSTAT_MOUNTING))
1.1 pooka 488: return EINPROGRESS;
489:
1.63 pooka 490: PUFFS_MSG_ALLOC(vfs, statvfs);
1.69 pooka 491: puffs_msg_setinfo(park_statvfs, PUFFSOP_VFS, PUFFS_VFS_STATVFS, NULL);
1.1 pooka 492:
1.69 pooka 493: PUFFS_MSG_ENQUEUEWAIT(pmp, park_statvfs, error);
1.60 pooka 494: error = checkerr(pmp, error, __func__);
1.63 pooka 495: statvfs_msg->pvfsr_sb.f_iosize = DEV_BSIZE;
1.10 pooka 496:
1.1 pooka 497: /*
498: * Try to produce a sensible result even in the event
499: * of userspace error.
500: *
501: * XXX: cache the copy in non-error case
502: */
503: if (!error) {
1.63 pooka 504: copy_statvfs_info(&statvfs_msg->pvfsr_sb, mp);
505: (void)memcpy(sbp, &statvfs_msg->pvfsr_sb,
1.1 pooka 506: sizeof(struct statvfs));
507: } else {
508: copy_statvfs_info(sbp, mp);
509: }
510:
1.63 pooka 511: PUFFS_MSG_RELEASE(statvfs);
1.14 pooka 512: return error;
1.1 pooka 513: }
514:
1.26 pooka 515: static int
1.83 pooka 516: pageflush(struct mount *mp, kauth_cred_t cred, int waitfor)
1.1 pooka 517: {
1.26 pooka 518: struct puffs_node *pn;
1.74 ad 519: struct vnode *vp, *mvp;
1.97 manu 520: int error, rv, fsyncwait;
1.1 pooka 521:
1.18 pooka 522: error = 0;
1.97 manu 523: fsyncwait = (waitfor == MNT_WAIT) ? FSYNC_WAIT : 0;
1.18 pooka 524:
1.74 ad 525: /* Allocate a marker vnode. */
1.98 hannken 526: mvp = vnalloc(mp);
1.74 ad 527:
1.18 pooka 528: /*
1.24 pooka 529: * Sync all cached data from regular vnodes (which are not
530: * currently locked, see below). After this we call VFS_SYNC
531: * for the fs server, which should handle data and metadata for
532: * all the nodes it knows to exist.
1.18 pooka 533: */
1.74 ad 534: mutex_enter(&mntvnode_lock);
1.18 pooka 535: loop:
1.74 ad 536: for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
537: vmark(mvp, vp);
538: if (vp->v_mount != mp || vismarker(vp))
539: continue;
1.18 pooka 540:
1.96 rmind 541: mutex_enter(vp->v_interlock);
1.26 pooka 542: pn = VPTOPP(vp);
1.19 pooka 543: if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) {
1.96 rmind 544: mutex_exit(vp->v_interlock);
1.18 pooka 545: continue;
546: }
547:
1.74 ad 548: mutex_exit(&mntvnode_lock);
1.21 pooka 549:
550: /*
551: * Here we try to get a reference to the vnode and to
552: * lock it. This is mostly cargo-culted, but I will
553: * offer an explanation to why I believe this might
554: * actually do the right thing.
555: *
556: * If the vnode is a goner, we quite obviously don't need
557: * to sync it.
558: *
559: * If the vnode was busy, we don't need to sync it because
560: * this is never called with MNT_WAIT except from
561: * dounmount(), when we are wait-flushing all the dirty
562: * vnodes through other routes in any case. So there,
563: * sync() doesn't actually sync. Happy now?
564: */
1.95 hannken 565: rv = vget(vp, LK_EXCLUSIVE | LK_NOWAIT);
1.18 pooka 566: if (rv) {
1.74 ad 567: mutex_enter(&mntvnode_lock);
568: if (rv == ENOENT) {
569: (void)vunmark(mvp);
1.18 pooka 570: goto loop;
1.74 ad 571: }
1.18 pooka 572: continue;
573: }
574:
1.83 pooka 575: /* hmm.. is the FAF thing entirely sensible? */
576: if (waitfor == MNT_LAZY) {
1.96 rmind 577: mutex_enter(vp->v_interlock);
1.83 pooka 578: pn->pn_stat |= PNODE_FAF;
1.96 rmind 579: mutex_exit(vp->v_interlock);
1.30 pooka 580: }
1.97 manu 581: rv = VOP_FSYNC(vp, cred, fsyncwait, 0, 0);
1.83 pooka 582: if (waitfor == MNT_LAZY) {
1.96 rmind 583: mutex_enter(vp->v_interlock);
1.83 pooka 584: pn->pn_stat &= ~PNODE_FAF;
1.96 rmind 585: mutex_exit(vp->v_interlock);
1.26 pooka 586: }
1.21 pooka 587: if (rv)
1.18 pooka 588: error = rv;
589: vput(vp);
1.74 ad 590: mutex_enter(&mntvnode_lock);
1.18 pooka 591: }
1.74 ad 592: mutex_exit(&mntvnode_lock);
1.76 pooka 593: vnfree(mvp);
1.18 pooka 594:
1.26 pooka 595: return error;
596: }
597:
598: int
1.73 pooka 599: puffs_vfsop_sync(struct mount *mp, int waitfor, struct kauth_cred *cred)
1.26 pooka 600: {
1.63 pooka 601: PUFFS_MSG_VARS(vfs, sync);
1.62 pooka 602: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1.26 pooka 603: int error, rv;
604:
1.83 pooka 605: error = pageflush(mp, cred, waitfor);
1.26 pooka 606:
1.18 pooka 607: /* sync fs */
1.63 pooka 608: PUFFS_MSG_ALLOC(vfs, sync);
609: sync_msg->pvfsr_waitfor = waitfor;
610: puffs_credcvt(&sync_msg->pvfsr_cred, cred);
1.69 pooka 611: puffs_msg_setinfo(park_sync, PUFFSOP_VFS, PUFFS_VFS_SYNC, NULL);
1.1 pooka 612:
1.69 pooka 613: PUFFS_MSG_ENQUEUEWAIT(pmp, park_sync, rv);
1.62 pooka 614: rv = checkerr(pmp, rv, __func__);
1.18 pooka 615: if (rv)
616: error = rv;
1.1 pooka 617:
1.63 pooka 618: PUFFS_MSG_RELEASE(sync);
1.1 pooka 619: return error;
620: }
621:
622: int
1.73 pooka 623: puffs_vfsop_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1.1 pooka 624: {
1.63 pooka 625: PUFFS_MSG_VARS(vfs, fhtonode);
1.33 pooka 626: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
627: struct vnode *vp;
1.54 pooka 628: void *fhdata;
629: size_t argsize, fhlen;
1.33 pooka 630: int error;
631:
1.38 pooka 632: if (pmp->pmp_args.pa_fhsize == 0)
1.33 pooka 633: return EOPNOTSUPP;
634:
1.54 pooka 635: if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) {
636: fhlen = fhp->fid_len;
637: fhdata = fhp;
1.39 pooka 638: } else {
1.54 pooka 639: fhlen = PUFFS_FROMFHSIZE(fhp->fid_len);
640: fhdata = fhp->fid_data;
641:
642: if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) {
643: if (pmp->pmp_args.pa_fhsize < fhlen)
644: return EINVAL;
645: } else {
646: if (pmp->pmp_args.pa_fhsize != fhlen)
647: return EINVAL;
648: }
1.39 pooka 649: }
1.33 pooka 650:
1.63 pooka 651: argsize = sizeof(struct puffs_vfsmsg_fhtonode) + fhlen;
1.75 pooka 652: puffs_msgmem_alloc(argsize, &park_fhtonode, (void *)&fhtonode_msg, 1);
1.63 pooka 653: fhtonode_msg->pvfsr_dsize = fhlen;
654: memcpy(fhtonode_msg->pvfsr_data, fhdata, fhlen);
1.69 pooka 655: puffs_msg_setinfo(park_fhtonode, PUFFSOP_VFS, PUFFS_VFS_FHTOVP, NULL);
1.33 pooka 656:
1.69 pooka 657: PUFFS_MSG_ENQUEUEWAIT(pmp, park_fhtonode, error);
1.60 pooka 658: error = checkerr(pmp, error, __func__);
1.33 pooka 659: if (error)
1.38 pooka 660: goto out;
1.33 pooka 661:
1.63 pooka 662: error = puffs_cookie2vnode(pmp, fhtonode_msg->pvfsr_fhcookie, 1,1,&vp);
1.33 pooka 663: DPRINTF(("puffs_fhtovp: got cookie %p, existing vnode %p\n",
1.63 pooka 664: fhtonode_msg->pvfsr_fhcookie, vp));
1.59 pooka 665: if (error == PUFFS_NOSUCHCOOKIE) {
1.63 pooka 666: error = puffs_getvnode(mp, fhtonode_msg->pvfsr_fhcookie,
667: fhtonode_msg->pvfsr_vtype, fhtonode_msg->pvfsr_size,
668: fhtonode_msg->pvfsr_rdev, &vp);
1.33 pooka 669: if (error)
1.38 pooka 670: goto out;
1.33 pooka 671: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.59 pooka 672: } else if (error) {
673: goto out;
1.33 pooka 674: }
1.1 pooka 675:
1.33 pooka 676: *vpp = vp;
1.38 pooka 677: out:
1.63 pooka 678: puffs_msgmem_release(park_fhtonode);
1.38 pooka 679: return error;
1.1 pooka 680: }
681:
682: int
1.73 pooka 683: puffs_vfsop_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1 pooka 684: {
1.63 pooka 685: PUFFS_MSG_VARS(vfs, nodetofh);
1.33 pooka 686: struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1.54 pooka 687: size_t argsize, fhlen;
1.33 pooka 688: int error;
689:
1.38 pooka 690: if (pmp->pmp_args.pa_fhsize == 0)
1.33 pooka 691: return EOPNOTSUPP;
692:
1.54 pooka 693: /* if file handles are static len, we can test len immediately */
1.38 pooka 694: if (((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) == 0)
1.54 pooka 695: && ((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) == 0)
1.38 pooka 696: && (PUFFS_FROMFHSIZE(*fh_size) < pmp->pmp_args.pa_fhsize)) {
697: *fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
1.33 pooka 698: return E2BIG;
699: }
1.1 pooka 700:
1.54 pooka 701: if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
702: fhlen = *fh_size;
703: else
704: fhlen = PUFFS_FROMFHSIZE(*fh_size);
705:
1.63 pooka 706: argsize = sizeof(struct puffs_vfsmsg_nodetofh) + fhlen;
1.75 pooka 707: puffs_msgmem_alloc(argsize, &park_nodetofh, (void *)&nodetofh_msg, 1);
1.63 pooka 708: nodetofh_msg->pvfsr_fhcookie = VPTOPNC(vp);
709: nodetofh_msg->pvfsr_dsize = fhlen;
1.69 pooka 710: puffs_msg_setinfo(park_nodetofh, PUFFSOP_VFS, PUFFS_VFS_VPTOFH, NULL);
1.38 pooka 711:
1.69 pooka 712: PUFFS_MSG_ENQUEUEWAIT(pmp, park_nodetofh, error);
1.60 pooka 713: error = checkerr(pmp, error, __func__);
1.54 pooka 714:
715: if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
1.63 pooka 716: fhlen = nodetofh_msg->pvfsr_dsize;
1.54 pooka 717: else if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC)
1.63 pooka 718: fhlen = PUFFS_TOFHSIZE(nodetofh_msg->pvfsr_dsize);
1.54 pooka 719: else
720: fhlen = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
721:
1.38 pooka 722: if (error) {
723: if (error == E2BIG)
1.54 pooka 724: *fh_size = fhlen;
1.38 pooka 725: goto out;
726: }
727:
1.54 pooka 728: if (fhlen > FHANDLE_SIZE_MAX) {
1.69 pooka 729: puffs_senderr(pmp, PUFFS_ERR_VPTOFH, E2BIG,
1.60 pooka 730: "file handle too big", VPTOPNC(vp));
1.58 pooka 731: error = EPROTO;
1.38 pooka 732: goto out;
733: }
1.33 pooka 734:
1.54 pooka 735: if (*fh_size < fhlen) {
736: *fh_size = fhlen;
1.38 pooka 737: error = E2BIG;
738: goto out;
739: }
1.54 pooka 740: *fh_size = fhlen;
1.1 pooka 741:
1.38 pooka 742: if (fhp) {
1.54 pooka 743: if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) {
1.63 pooka 744: memcpy(fhp, nodetofh_msg->pvfsr_data, fhlen);
1.54 pooka 745: } else {
746: fhp->fid_len = *fh_size;
1.63 pooka 747: memcpy(fhp->fid_data, nodetofh_msg->pvfsr_data,
748: nodetofh_msg->pvfsr_dsize);
1.54 pooka 749: }
1.38 pooka 750: }
1.1 pooka 751:
1.38 pooka 752: out:
1.63 pooka 753: puffs_msgmem_release(park_nodetofh);
1.38 pooka 754: return error;
1.1 pooka 755: }
756:
757: void
1.82 cegger 758: puffs_vfsop_init(void)
1.1 pooka 759: {
760:
1.56 pooka 761: /* some checks depend on this */
762: KASSERT(VNOVAL == VSIZENOTSET);
763:
1.31 pooka 764: pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
765: "puffpnpl", &pool_allocator_nointr, IPL_NONE);
1.100.8.1! riz 766: pool_init(&puffs_vapool, sizeof(struct vattr), 0, 0, 0,
! 767: "puffvapl", &pool_allocator_nointr, IPL_NONE);
1.31 pooka 768: puffs_msgif_init();
1.1 pooka 769: }
770:
771: void
1.82 cegger 772: puffs_vfsop_done(void)
1.1 pooka 773: {
774:
1.31 pooka 775: puffs_msgif_destroy();
776: pool_destroy(&puffs_pnpool);
1.100.8.1! riz 777: pool_destroy(&puffs_vapool);
1.1 pooka 778: }
779:
780: int
1.73 pooka 781: puffs_vfsop_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
1.1 pooka 782: {
783:
784: return EOPNOTSUPP;
785: }
786:
1.88 pooka 787: int
788: puffs_vfsop_extattrctl(struct mount *mp, int cmd, struct vnode *vp,
789: int attrnamespace, const char *attrname)
790: {
791: PUFFS_MSG_VARS(vfs, extattrctl);
792: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
793: struct puffs_node *pnp;
794: puffs_cookie_t pnc;
795: int error, flags;
796:
797: if (vp) {
798: /* doesn't make sense for puffs servers */
799: if (vp->v_mount != mp)
800: return EXDEV;
801: pnp = vp->v_data;
802: pnc = pnp->pn_cookie;
803: flags = PUFFS_EXTATTRCTL_HASNODE;
804: } else {
805: pnp = pnc = NULL;
806: flags = 0;
807: }
808:
809: PUFFS_MSG_ALLOC(vfs, extattrctl);
810: extattrctl_msg->pvfsr_cmd = cmd;
811: extattrctl_msg->pvfsr_attrnamespace = attrnamespace;
812: extattrctl_msg->pvfsr_flags = flags;
813: if (attrname) {
814: strlcpy(extattrctl_msg->pvfsr_attrname, attrname,
815: sizeof(extattrctl_msg->pvfsr_attrname));
816: extattrctl_msg->pvfsr_flags |= PUFFS_EXTATTRCTL_HASATTRNAME;
817: }
818: puffs_msg_setinfo(park_extattrctl,
819: PUFFSOP_VFS, PUFFS_VFS_EXTATTRCTL, pnc);
820:
821: puffs_msg_enqueue(pmp, park_extattrctl);
822: if (vp) {
823: mutex_enter(&pnp->pn_mtx);
824: puffs_referencenode(pnp);
825: mutex_exit(&pnp->pn_mtx);
1.90 hannken 826: VOP_UNLOCK(vp);
1.88 pooka 827: }
828: error = puffs_msg_wait2(pmp, park_extattrctl, pnp, NULL);
829: PUFFS_MSG_RELEASE(extattrctl);
830: if (vp) {
831: puffs_releasenode(pnp);
832: }
833:
834: return checkerr(pmp, error, __func__);
835: }
836:
1.1 pooka 837: const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
838: &puffs_vnodeop_opv_desc,
1.3 pooka 839: &puffs_specop_opv_desc,
1.4 pooka 840: &puffs_fifoop_opv_desc,
1.12 pooka 841: &puffs_msgop_opv_desc,
1.1 pooka 842: NULL,
843: };
844:
845: struct vfsops puffs_vfsops = {
846: MOUNT_PUFFS,
1.48 dsl 847: sizeof (struct puffs_kargs),
1.73 pooka 848: puffs_vfsop_mount, /* mount */
849: puffs_vfsop_start, /* start */
850: puffs_vfsop_unmount, /* unmount */
851: puffs_vfsop_root, /* root */
852: (void *)eopnotsupp, /* quotactl */
853: puffs_vfsop_statvfs, /* statvfs */
854: puffs_vfsop_sync, /* sync */
855: (void *)eopnotsupp, /* vget */
856: puffs_vfsop_fhtovp, /* fhtovp */
857: puffs_vfsop_vptofh, /* vptofh */
858: puffs_vfsop_init, /* init */
859: NULL, /* reinit */
860: puffs_vfsop_done, /* done */
861: NULL, /* mountroot */
862: puffs_vfsop_snapshot, /* snapshot */
1.88 pooka 863: puffs_vfsop_extattrctl, /* extattrctl */
1.83 pooka 864: (void *)eopnotsupp, /* suspendctl */
1.78 dholland 865: genfs_renamelock_enter,
866: genfs_renamelock_exit,
1.79 ad 867: (void *)eopnotsupp,
1.73 pooka 868: puffs_vnodeopv_descs, /* vnodeops */
869: 0, /* refcount */
1.1 pooka 870: { NULL, NULL }
871: };
1.80 rumble 872:
873: static int
874: puffs_modcmd(modcmd_t cmd, void *arg)
875: {
876:
877: switch (cmd) {
878: case MODULE_CMD_INIT:
879: return vfs_attach(&puffs_vfsops);
880: case MODULE_CMD_FINI:
881: return vfs_detach(&puffs_vfsops);
882: default:
883: return ENOTTY;
884: }
885: }
CVSweb <webmaster@jp.NetBSD.org>