hammer2 - Remote xop implementation part 1
[dragonfly.git] / sys / vfs / puffs / puffs_vfsops.c
blob23357916e409bf45a16c0d48d2871fdc3ca304e6
1 /* $NetBSD: puffs_vfsops.c,v 1.96 2011/06/12 03:35:54 rmind Exp $ */
3 /*
4 * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
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.
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.
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.
32 #include <sys/param.h>
33 #include <sys/mount.h>
34 #include <sys/malloc.h>
35 #include <sys/extattr.h>
36 #include <sys/queue.h>
37 #include <sys/vnode.h>
38 #include <sys/dirent.h>
39 #include <sys/proc.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/kthread.h>
43 #include <sys/libkern.h>
44 #include <sys/sysctl.h>
46 #include <vfs/nfs/nfsproto.h>
48 #include <dev/misc/putter/putter_sys.h>
50 #include <vfs/puffs/puffs_msgif.h>
51 #include <vfs/puffs/puffs_sys.h>
53 #ifndef PUFFS_PNODEBUCKETS
54 #define PUFFS_PNODEBUCKETS 256
55 #endif
56 #ifndef PUFFS_MAXPNODEBUCKETS
57 #define PUFFS_MAXPNODEBUCKETS 8192
58 #endif
59 int puffs_pnodebuckets_default = PUFFS_PNODEBUCKETS;
60 int puffs_maxpnodebuckets = PUFFS_MAXPNODEBUCKETS;
62 #define BUCKETALLOC(a) (sizeof(struct puffs_pnode_hashlist *) * (a))
64 #ifndef __arraycount
65 #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0]))
66 #endif
68 SYSCTL_NODE(_vfs, OID_AUTO, puffs, CTLFLAG_RW, 0, "PUFFS filesystem");
70 static int puffs_use_pagecache = 0;
71 SYSCTL_INT(_vfs_puffs, OID_AUTO, pagecache, CTLFLAG_RW, &puffs_use_pagecache,
72 0, "Enable page cache");
74 static struct putter_ops puffs_putter = {
75 .pop_getout = puffs_msgif_getout,
76 .pop_releaseout = puffs_msgif_releaseout,
77 .pop_waitcount = puffs_msgif_waitcount,
78 .pop_dispatch = puffs_msgif_dispatch,
79 .pop_close = puffs_msgif_close,
82 static int
83 puffs_vfsop_mount(struct mount *mp, char *path, char *data,
84 struct ucred *cred)
86 struct puffs_mount *pmp = NULL;
87 struct puffs_kargs *args, kargs;
88 char *p;
89 int error = 0, i;
90 pid_t mntpid = curproc->p_pid;
92 /* update is not supported currently */
93 if (mp->mnt_flag & MNT_UPDATE)
94 return EOPNOTSUPP;
97 * We need the file system name
99 if (!data)
100 return EINVAL;
102 copyin(data, &kargs, sizeof(kargs));
103 args = &kargs;
105 if (args->pa_vers != PUFFSVERSION) {
106 kprintf("puffs_mount: development version mismatch: "
107 "kernel %d, lib %d\n", PUFFSVERSION, args->pa_vers);
108 error = EINVAL;
109 goto out;
112 if ((args->pa_flags & ~PUFFS_KFLAG_MASK) != 0) {
113 kprintf("puffs_mount: invalid KFLAGs 0x%x\n", args->pa_flags);
114 error = EINVAL;
115 goto out;
117 if ((args->pa_fhflags & ~PUFFS_FHFLAG_MASK) != 0) {
118 kprintf("puffs_mount: invalid FHFLAGs 0x%x\n", args->pa_fhflags);
119 error = EINVAL;
120 goto out;
123 for (i = 0; i < __arraycount(args->pa_spare); i++) {
124 if (args->pa_spare[i] != 0) {
125 kprintf("puffs_mount: pa_spare[%d] = 0x%x\n",
126 i, args->pa_spare[i]);
127 error = EINVAL;
128 goto out;
132 /* use dummy value for passthrough */
133 if (args->pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
134 args->pa_fhsize = MAXFIDSZ;
136 /* sanitize file handle length */
137 if (PUFFS_TOFHSIZE(args->pa_fhsize) > sizeof(struct fid)) {
138 kprintf("puffs_mount: handle size %zu too large\n",
139 args->pa_fhsize);
140 error = EINVAL;
141 goto out;
143 /* sanity check file handle max sizes */
144 if (args->pa_fhsize && args->pa_fhflags & PUFFS_FHFLAG_PROTOMASK) {
145 size_t kfhsize = PUFFS_TOFHSIZE(args->pa_fhsize);
147 if (args->pa_fhflags & PUFFS_FHFLAG_NFSV2) {
148 if (kfhsize > NFSX_FH(0)) {
149 kprintf("puffs_mount: fhsize larger than "
150 "NFSv2 max %d\n",
151 PUFFS_FROMFHSIZE(NFSX_V2FH));
152 error = EINVAL;
153 goto out;
157 if (args->pa_fhflags & PUFFS_FHFLAG_NFSV3) {
158 if (kfhsize > NFSX_FH(1)) {
159 kprintf("puffs_mount: fhsize larger than "
160 "NFSv3 max %d\n",
161 PUFFS_FROMFHSIZE(NFSX_V3FHMAX));
162 error = EINVAL;
163 goto out;
168 /* don't allow non-printing characters (like my sweet umlauts.. snif) */
169 args->pa_typename[sizeof(args->pa_typename)-1] = '\0';
170 for (p = args->pa_typename; *p; p++)
171 if (*p < ' ' || *p > '~')
172 *p = '.';
174 args->pa_mntfromname[sizeof(args->pa_mntfromname)-1] = '\0';
175 for (p = args->pa_mntfromname; *p; p++)
176 if (*p < ' ' || *p > '~')
177 *p = '.';
179 /* build real name */
180 bzero(mp->mnt_stat.f_fstypename, MFSNAMELEN);
181 (void)strlcpy(mp->mnt_stat.f_fstypename, PUFFS_TYPEPREFIX, MFSNAMELEN);
182 (void)strlcat(mp->mnt_stat.f_fstypename, args->pa_typename, MFSNAMELEN);
184 bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
185 strlcpy(mp->mnt_stat.f_mntfromname, args->pa_mntfromname, MFSNAMELEN);
186 bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
187 copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN, NULL);
189 /* inform user server if it got the max request size it wanted */
190 if (args->pa_maxmsglen == 0 || args->pa_maxmsglen > PUFFS_MSG_MAXSIZE)
191 args->pa_maxmsglen = PUFFS_MSG_MAXSIZE;
192 else if (args->pa_maxmsglen < 2*PUFFS_MSGSTRUCT_MAX)
193 args->pa_maxmsglen = 2*PUFFS_MSGSTRUCT_MAX;
195 if (args->pa_nhashbuckets == 0)
196 args->pa_nhashbuckets = puffs_pnodebuckets_default;
197 if (args->pa_nhashbuckets < 1)
198 args->pa_nhashbuckets = 1;
199 if (args->pa_nhashbuckets > PUFFS_MAXPNODEBUCKETS) {
200 args->pa_nhashbuckets = puffs_maxpnodebuckets;
201 kprintf("puffs_mount: using %d hash buckets. "
202 "adjust puffs_maxpnodebuckets for more\n",
203 puffs_maxpnodebuckets);
206 mp->mnt_stat.f_iosize = DEV_BSIZE;
207 mp->mnt_stat.f_bsize = DEV_BSIZE;
208 mp->mnt_vstat.f_frsize = DEV_BSIZE;
209 mp->mnt_vstat.f_bsize = DEV_BSIZE;
210 mp->mnt_vstat.f_namemax = args->pa_svfsb.f_namemax;
212 pmp = kmalloc(sizeof(struct puffs_mount), M_PUFFS, M_ZERO | M_WAITOK);
214 mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
215 mp->mnt_data = (qaddr_t)pmp;
217 #if 0
219 * XXX: puffs code is MPSAFE. However, VFS really isn't.
220 * Currently, there is nothing which protects an inode from
221 * reclaim while there are threads inside the file system.
222 * This means that in the event of a server crash, an MPSAFE
223 * mount is likely to end up accessing invalid memory. For the
224 * non-mpsafe case, the kernel lock, general structure of
225 * puffs and pmp_refcount protect the threads during escape.
227 * Fixing this will require:
228 * a) fixing vfs
229 * OR
230 * b) adding a small sleep to puffs_msgif_close() between
231 * userdead() and dounmount().
232 * (well, this isn't really a fix, but would solve
233 * 99.999% of the race conditions).
235 * Also, in the event of "b", unmount -f should be used,
236 * like with any other file system, sparingly and only when
237 * it is "known" to be safe.
239 mp->mnt_iflags |= IMNT_MPSAFE;
240 #endif
242 pmp->pmp_status = PUFFSTAT_MOUNTING;
243 pmp->pmp_mp = mp;
244 pmp->pmp_msg_maxsize = args->pa_maxmsglen;
245 pmp->pmp_args = *args;
247 if (puffs_use_pagecache == 0)
248 pmp->pmp_flags |= PUFFS_KFLAG_NOCACHE_PAGE;
250 pmp->pmp_npnodehash = args->pa_nhashbuckets;
251 pmp->pmp_pnodehash = kmalloc(BUCKETALLOC(pmp->pmp_npnodehash),
252 M_PUFFS, M_WAITOK);
253 for (i = 0; i < pmp->pmp_npnodehash; i++)
254 LIST_INIT(&pmp->pmp_pnodehash[i]);
255 LIST_INIT(&pmp->pmp_newcookie);
258 * Inform the fileops processing code that we have a mountpoint.
259 * If it doesn't know about anyone with our pid/fd having the
260 * device open, punt
262 if ((pmp->pmp_pi
263 = putter_attach(mntpid, args->pa_minor, pmp, &puffs_putter)) == NULL) {
264 error = ENOENT;
265 goto out;
268 /* XXX: check parameters */
269 pmp->pmp_root_cookie = args->pa_root_cookie;
270 pmp->pmp_root_vtype = args->pa_root_vtype;
271 pmp->pmp_root_vsize = args->pa_root_vsize;
272 pmp->pmp_root_rdev = args->pa_root_rdev;
274 lockinit(&pmp->pmp_lock, "puffs pmp_lock", 0, 0);
275 lockinit(&pmp->pmp_sopmtx, "puffs pmp_sopmtx", 0, 0);
276 cv_init(&pmp->pmp_msg_waiter_cv, "puffsget");
277 cv_init(&pmp->pmp_refcount_cv, "puffsref");
278 cv_init(&pmp->pmp_unmounting_cv, "puffsum");
279 cv_init(&pmp->pmp_sopcv, "puffsop");
280 TAILQ_INIT(&pmp->pmp_msg_touser);
281 TAILQ_INIT(&pmp->pmp_msg_replywait);
282 TAILQ_INIT(&pmp->pmp_sopreqs);
284 if ((error = kthread_create(puffs_sop_thread, pmp, NULL,
285 "puffsop")) != 0)
286 goto out;
287 pmp->pmp_sopthrcount = 1;
289 DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
290 mp, MPTOPUFFSMP(mp)));
292 vfs_getnewfsid(mp);
294 vfs_add_vnodeops(mp, &puffs_vnode_vops, &mp->mnt_vn_norm_ops);
295 vfs_add_vnodeops(mp, &puffs_fifo_vops, &mp->mnt_vn_fifo_ops);
297 out:
298 if (error && pmp && pmp->pmp_pi)
299 putter_detach(pmp->pmp_pi);
300 if (error && pmp && pmp->pmp_pnodehash)
301 kfree(pmp->pmp_pnodehash, M_PUFFS);
302 if (error && pmp)
303 kfree(pmp, M_PUFFS);
304 return error;
307 static int
308 puffs_vfsop_unmount(struct mount *mp, int mntflags)
310 PUFFS_MSG_VARS(vfs, unmount);
311 struct puffs_mount *pmp;
312 int error, force;
314 error = 0;
315 force = mntflags & MNT_FORCE;
316 pmp = MPTOPUFFSMP(mp);
318 DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
319 "status 0x%x\n", pmp->pmp_status));
322 * flush all the vnodes. VOP_RECLAIM() takes care that the
323 * root vnode does not get flushed until unmount. The
324 * userspace root node cookie is stored in the mount
325 * structure, so we can always re-instantiate a root vnode,
326 * should userspace unmount decide it doesn't want to
327 * cooperate.
329 error = vflush(mp, 1, force ? FORCECLOSE : 0);
330 if (error)
331 goto out;
334 * If we are not DYING, we should ask userspace's opinion
335 * about the situation
337 lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
338 if (pmp->pmp_status != PUFFSTAT_DYING) {
339 pmp->pmp_unmounting = 1;
340 lockmgr(&pmp->pmp_lock, LK_RELEASE);
342 PUFFS_MSG_ALLOC(vfs, unmount);
343 puffs_msg_setinfo(park_unmount,
344 PUFFSOP_VFS, PUFFS_VFS_UNMOUNT, NULL);
345 unmount_msg->pvfsr_flags = mntflags;
347 PUFFS_MSG_ENQUEUEWAIT(pmp, park_unmount, error);
348 PUFFS_MSG_RELEASE(unmount);
350 error = checkerr(pmp, error, __func__);
351 DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
353 lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
354 pmp->pmp_unmounting = 0;
355 cv_broadcast(&pmp->pmp_unmounting_cv);
359 * if userspace cooperated or we really need to die,
360 * screw what userland thinks and just die.
362 if (error == 0 || force) {
363 struct puffs_sopreq *psopr;
365 /* tell waiters & other resources to go unwait themselves */
366 puffs_userdead(pmp);
367 putter_detach(pmp->pmp_pi);
370 * Wait until there are no more users for the mount resource.
371 * Notice that this is hooked against transport_close
372 * and return from touser. In an ideal world, it would
373 * be hooked against final return from all operations.
374 * But currently it works well enough, since nobody
375 * does weird blocking voodoo after return from touser().
377 while (pmp->pmp_refcount != 0)
378 cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock);
379 lockmgr(&pmp->pmp_lock, LK_RELEASE);
382 * Release kernel thread now that there is nothing
383 * it would be wanting to lock.
385 psopr = kmalloc(sizeof(*psopr), M_PUFFS, M_WAITOK);
386 psopr->psopr_sopreq = PUFFS_SOPREQSYS_EXIT;
387 lockmgr(&pmp->pmp_sopmtx, LK_EXCLUSIVE);
388 if (pmp->pmp_sopthrcount == 0) {
389 lockmgr(&pmp->pmp_sopmtx, LK_RELEASE);
390 kfree(psopr, M_PUFFS);
391 lockmgr(&pmp->pmp_sopmtx, LK_EXCLUSIVE);
392 KKASSERT(pmp->pmp_sopthrcount == 0);
393 } else {
394 TAILQ_INSERT_TAIL(&pmp->pmp_sopreqs,
395 psopr, psopr_entries);
396 cv_signal(&pmp->pmp_sopcv);
398 while (pmp->pmp_sopthrcount > 0)
399 cv_wait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx);
400 lockmgr(&pmp->pmp_sopmtx, LK_RELEASE);
402 /* free resources now that we hopefully have no waiters left */
403 cv_destroy(&pmp->pmp_unmounting_cv);
404 cv_destroy(&pmp->pmp_refcount_cv);
405 cv_destroy(&pmp->pmp_msg_waiter_cv);
406 cv_destroy(&pmp->pmp_sopcv);
407 lockuninit(&pmp->pmp_lock);
408 lockuninit(&pmp->pmp_sopmtx);
410 kfree(pmp->pmp_pnodehash, M_PUFFS);
411 kfree(pmp, M_PUFFS);
412 error = 0;
413 } else {
414 lockmgr(&pmp->pmp_lock, LK_RELEASE);
417 out:
418 DPRINTF(("puffs_unmount: return %d\n", error));
419 return error;
423 * This doesn't need to travel to userspace
425 static int
426 puffs_vfsop_root(struct mount *mp, struct vnode **vpp)
428 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
429 int rv;
431 rv = puffs_cookie2vnode(pmp, pmp->pmp_root_cookie, 1, vpp);
432 KKASSERT(rv != PUFFS_NOSUCHCOOKIE);
434 return rv;
437 static int
438 puffs_vfsop_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
440 PUFFS_MSG_VARS(vfs, statvfs);
441 struct puffs_mount *pmp;
442 int error = 0;
444 pmp = MPTOPUFFSMP(mp);
447 * If we are mounting, it means that the userspace counterpart
448 * is calling mount(2), but mount(2) also calls statvfs. So
449 * requesting statvfs from userspace would mean a deadlock.
450 * Compensate.
452 if (__predict_false(pmp->pmp_status == PUFFSTAT_MOUNTING))
453 return EINPROGRESS;
455 PUFFS_MSG_ALLOC(vfs, statvfs);
456 puffs_msg_setinfo(park_statvfs, PUFFSOP_VFS, PUFFS_VFS_STATVFS, NULL);
458 PUFFS_MSG_ENQUEUEWAIT(pmp, park_statvfs, error);
459 error = checkerr(pmp, error, __func__);
460 statvfs_msg->pvfsr_sb.f_bsize = DEV_BSIZE;
463 * Try to produce a sensible result even in the event
464 * of userspace error.
466 * XXX: cache the copy in non-error case
468 if (!error) {
469 (void)memcpy(sbp, &statvfs_msg->pvfsr_sb,
470 sizeof(struct statvfs));
471 } else {
472 (void)memcpy(sbp, &mp->mnt_stat,
473 sizeof(struct statvfs));
476 PUFFS_MSG_RELEASE(statvfs);
477 return error;
480 #ifdef XXXDF
481 static int
482 pageflush(struct mount *mp, kauth_cred_t cred, int waitfor)
484 struct puffs_node *pn;
485 struct vnode *vp, *mvp;
486 int error, rv;
488 error = 0;
490 /* Allocate a marker vnode. */
491 if ((mvp = vnalloc(mp)) == NULL)
492 return ENOMEM;
495 * Sync all cached data from regular vnodes (which are not
496 * currently locked, see below). After this we call VFS_SYNC
497 * for the fs server, which should handle data and metadata for
498 * all the nodes it knows to exist.
500 lockmgr(&mntvnode_lock, LK_EXCLUSIVE);
501 loop:
502 for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
503 vmark(mvp, vp);
504 if (vp->v_mount != mp || vismarker(vp))
505 continue;
507 lockmgr(&vp->v_interlock, LK_EXCLUSIVE);
508 pn = VPTOPP(vp);
509 if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) {
510 lockmgr(&vp->v_interlock, LK_RELEASE);
511 continue;
514 lockmgr(&mntvnode_lock, LK_RELEASE);
517 * Here we try to get a reference to the vnode and to
518 * lock it. This is mostly cargo-culted, but I will
519 * offer an explanation to why I believe this might
520 * actually do the right thing.
522 * If the vnode is a goner, we quite obviously don't need
523 * to sync it.
525 * If the vnode was busy, we don't need to sync it because
526 * this is never called with MNT_WAIT except from
527 * dounmount(), when we are wait-flushing all the dirty
528 * vnodes through other routes in any case. So there,
529 * sync() doesn't actually sync. Happy now?
531 rv = vget(vp, LK_EXCLUSIVE | LK_NOWAIT);
532 if (rv) {
533 lockmgr(&mntvnode_lock, LK_EXCLUSIVE);
534 if (rv == ENOENT) {
535 (void)vunmark(mvp);
536 goto loop;
538 continue;
541 /* hmm.. is the FAF thing entirely sensible? */
542 if (waitfor == MNT_LAZY) {
543 lockmgr(&vp->v_interlock, LK_EXCLUSIVE);
544 pn->pn_stat |= PNODE_FAF;
545 lockmgr(&vp->v_interlock, LK_RELEASE);
547 rv = VOP_FSYNC(vp, cred, waitfor, 0, 0);
548 if (waitfor == MNT_LAZY) {
549 lockmgr(&vp->v_interlock, LK_EXCLUSIVE);
550 pn->pn_stat &= ~PNODE_FAF;
551 lockmgr(&vp->v_interlock, LK_RELEASE);
553 if (rv)
554 error = rv;
555 vput(vp);
556 lockmgr(&mntvnode_lock, LK_EXCLUSIVE);
558 lockmgr(&mntvnode_lock, LK_RELEASE);
559 vnfree(mvp);
561 return error;
563 #endif
565 static int
566 puffs_vfsop_sync(struct mount *mp, int waitfor)
568 PUFFS_MSG_VARS(vfs, sync);
569 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
570 int error, rv;
572 #ifdef XXXDF
573 error = pageflush(mp, cred, waitfor);
574 #endif
576 /* sync fs */
577 PUFFS_MSG_ALLOC(vfs, sync);
578 sync_msg->pvfsr_waitfor = waitfor;
579 puffs_msg_setinfo(park_sync, PUFFSOP_VFS, PUFFS_VFS_SYNC, NULL);
581 PUFFS_MSG_ENQUEUEWAIT(pmp, park_sync, rv);
582 error = checkerr(pmp, rv, __func__);
584 PUFFS_MSG_RELEASE(sync);
585 DPRINTF(("puffs_vfsop_sync: result %d\n", error));
586 return error;
589 #ifdef XXXDF
590 static int
591 puffs_vfsop_fhtovp(struct mount *mp, struct vnode *rootvp, struct fid *fhp,
592 struct vnode **vpp)
594 PUFFS_MSG_VARS(vfs, fhtonode);
595 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
596 struct vnode *vp;
597 void *fhdata;
598 size_t argsize, fhlen;
599 int error;
601 if (pmp->pmp_args.pa_fhsize == 0)
602 return EOPNOTSUPP;
604 if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) {
605 fhlen = fhp->fid_len;
606 fhdata = fhp;
607 } else {
608 fhlen = PUFFS_FROMFHSIZE(fhp->fid_len);
609 fhdata = fhp->fid_data;
611 if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) {
612 if (pmp->pmp_args.pa_fhsize < fhlen)
613 return EINVAL;
614 } else {
615 if (pmp->pmp_args.pa_fhsize != fhlen)
616 return EINVAL;
620 argsize = sizeof(struct puffs_vfsmsg_fhtonode) + fhlen;
621 puffs_msgmem_alloc(argsize, &park_fhtonode, (void *)&fhtonode_msg, 1);
622 fhtonode_msg->pvfsr_dsize = fhlen;
623 memcpy(fhtonode_msg->pvfsr_data, fhdata, fhlen);
624 puffs_msg_setinfo(park_fhtonode, PUFFSOP_VFS, PUFFS_VFS_FHTOVP, NULL);
626 PUFFS_MSG_ENQUEUEWAIT(pmp, park_fhtonode, error);
627 error = checkerr(pmp, error, __func__);
628 if (error)
629 goto out;
631 error = puffs_cookie2vnode(pmp, fhtonode_msg->pvfsr_fhcookie, 1,1,&vp);
632 DPRINTF(("puffs_fhtovp: got cookie %p, existing vnode %p\n",
633 fhtonode_msg->pvfsr_fhcookie, vp));
634 if (error == PUFFS_NOSUCHCOOKIE) {
635 error = puffs_getvnode(mp, fhtonode_msg->pvfsr_fhcookie,
636 fhtonode_msg->pvfsr_vtype, fhtonode_msg->pvfsr_size,
637 fhtonode_msg->pvfsr_rdev, &vp);
638 if (error)
639 goto out;
640 } else if (error) {
641 goto out;
644 *vpp = vp;
645 out:
646 puffs_msgmem_release(park_fhtonode);
647 return error;
650 static int
651 puffs_vfsop_vptofh(struct vnode *vp, struct fid *fhp)
653 PUFFS_MSG_VARS(vfs, nodetofh);
654 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
655 size_t argsize, fhlen;
656 int error;
658 if (pmp->pmp_args.pa_fhsize == 0)
659 return EOPNOTSUPP;
661 /* if file handles are static len, we can test len immediately */
662 if (((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) == 0)
663 && ((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) == 0)
664 && (PUFFS_FROMFHSIZE(*fh_size) < pmp->pmp_args.pa_fhsize)) {
665 *fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
666 return E2BIG;
669 if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
670 fhlen = *fh_size;
671 else
672 fhlen = PUFFS_FROMFHSIZE(*fh_size);
674 argsize = sizeof(struct puffs_vfsmsg_nodetofh) + fhlen;
675 puffs_msgmem_alloc(argsize, &park_nodetofh, (void *)&nodetofh_msg, 1);
676 nodetofh_msg->pvfsr_fhcookie = VPTOPNC(vp);
677 nodetofh_msg->pvfsr_dsize = fhlen;
678 puffs_msg_setinfo(park_nodetofh, PUFFSOP_VFS, PUFFS_VFS_VPTOFH, NULL);
680 PUFFS_MSG_ENQUEUEWAIT(pmp, park_nodetofh, error);
681 error = checkerr(pmp, error, __func__);
683 if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
684 fhlen = nodetofh_msg->pvfsr_dsize;
685 else if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC)
686 fhlen = PUFFS_TOFHSIZE(nodetofh_msg->pvfsr_dsize);
687 else
688 fhlen = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
690 if (error) {
691 if (error == E2BIG)
692 *fh_size = fhlen;
693 goto out;
696 if (fhlen > FHANDLE_SIZE_MAX) {
697 puffs_senderr(pmp, PUFFS_ERR_VPTOFH, E2BIG,
698 "file handle too big", VPTOPNC(vp));
699 error = EPROTO;
700 goto out;
703 if (*fh_size < fhlen) {
704 *fh_size = fhlen;
705 error = E2BIG;
706 goto out;
708 *fh_size = fhlen;
710 if (fhp) {
711 if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) {
712 memcpy(fhp, nodetofh_msg->pvfsr_data, fhlen);
713 } else {
714 fhp->fid_len = *fh_size;
715 memcpy(fhp->fid_data, nodetofh_msg->pvfsr_data,
716 nodetofh_msg->pvfsr_dsize);
720 out:
721 puffs_msgmem_release(park_nodetofh);
722 return error;
724 #endif
726 static int
727 puffs_vfsop_start(struct mount *mp, int flags)
729 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
731 KKASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING);
732 pmp->pmp_status = PUFFSTAT_RUNNING;
734 return 0;
737 static int
738 puffs_vfsop_init(struct vfsconf *vfc)
741 puffs_msgif_init();
742 return 0;
745 static int
746 puffs_vfsop_uninit(struct vfsconf *vfc)
749 puffs_msgif_destroy();
750 return 0;
753 #ifdef XXXDF
754 static int
755 puffs_vfsop_extattrctl(struct mount *mp, int cmd, struct vnode *vp,
756 int attrnamespace, const char *attrname, struct ucred *cred)
758 PUFFS_MSG_VARS(vfs, extattrctl);
759 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
760 struct puffs_node *pnp;
761 puffs_cookie_t pnc;
762 int error, flags;
764 if (vp) {
765 /* doesn't make sense for puffs servers */
766 if (vp->v_mount != mp)
767 return EXDEV;
768 pnp = VPTOPP(vp);
769 pnc = pnp->pn_cookie;
770 flags = PUFFS_EXTATTRCTL_HASNODE;
771 } else {
772 pnp = pnc = NULL;
773 flags = 0;
776 PUFFS_MSG_ALLOC(vfs, extattrctl);
777 extattrctl_msg->pvfsr_cmd = cmd;
778 extattrctl_msg->pvfsr_attrnamespace = attrnamespace;
779 extattrctl_msg->pvfsr_flags = flags;
780 if (attrname) {
781 strlcpy(extattrctl_msg->pvfsr_attrname, attrname,
782 sizeof(extattrctl_msg->pvfsr_attrname));
783 extattrctl_msg->pvfsr_flags |= PUFFS_EXTATTRCTL_HASATTRNAME;
785 puffs_msg_setinfo(park_extattrctl,
786 PUFFSOP_VFS, PUFFS_VFS_EXTATTRCTL, pnc);
788 puffs_msg_enqueue(pmp, park_extattrctl);
789 if (vp) {
790 lockmgr(&pnp->pn_mtx, LK_EXCLUSIVE);
791 puffs_referencenode(pnp);
792 lockmgr(&pnp->pn_mtx, LK_RELEASE);
793 VOP_UNLOCK(vp);
795 error = puffs_msg_wait2(pmp, park_extattrctl, pnp, NULL);
796 PUFFS_MSG_RELEASE(extattrctl);
797 if (vp) {
798 puffs_releasenode(pnp);
801 return checkerr(pmp, error, __func__);
803 #endif
805 static struct vfsops puffs_vfsops = {
806 .vfs_mount = puffs_vfsop_mount,
807 .vfs_unmount = puffs_vfsop_unmount,
808 .vfs_root = puffs_vfsop_root,
809 .vfs_statvfs = puffs_vfsop_statvfs,
810 .vfs_sync = puffs_vfsop_sync,
811 #ifdef XXXFD
812 .vfs_fhtovp = puffs_vfsop_fhtovp,
813 .vfs_vptofh = puffs_vfsop_vptofh,
814 .vfs_extattrctl = puffs_vfsop_extattrctl,
815 #endif
816 .vfs_start = puffs_vfsop_start,
817 .vfs_init = puffs_vfsop_init,
818 .vfs_uninit = puffs_vfsop_uninit,
821 VFS_SET(puffs_vfsops, puffs, 0);
822 MODULE_DEPEND(puffs, putter, 1, 1, 1);