Merge branch 'vendor/BINUTILS225'
[dragonfly.git] / sys / vfs / puffs / puffs_vfsops.c
1 /*      $NetBSD: puffs_vfsops.c,v 1.96 2011/06/12 03:35:54 rmind Exp $  */
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/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>
45
46 #include <vfs/nfs/nfsproto.h>
47
48 #include <dev/misc/putter/putter_sys.h>
49
50 #include <vfs/puffs/puffs_msgif.h>
51 #include <vfs/puffs/puffs_sys.h>
52
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;
61
62 #define BUCKETALLOC(a) (sizeof(struct puffs_pnode_hashlist *) * (a))
63
64 #ifndef __arraycount
65 #define __arraycount(__x)       (sizeof(__x) / sizeof(__x[0]))
66 #endif
67
68 SYSCTL_NODE(_vfs, OID_AUTO, puffs, CTLFLAG_RW, 0, "PUFFS filesystem");
69
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");
73
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,
80 };
81
82 static int
83 puffs_vfsop_mount(struct mount *mp, char *path, char *data,
84         struct ucred *cred)
85 {
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;
91
92         /* update is not supported currently */
93         if (mp->mnt_flag & MNT_UPDATE)
94                 return EOPNOTSUPP;
95
96         /*
97          * We need the file system name
98          */
99         if (!data)
100                 return EINVAL;
101
102         copyin(data, &kargs, sizeof(kargs));
103         args = &kargs;
104
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;
110         }
111
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;
116         }
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;
121         }
122
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;
129                 }
130         }
131
132         /* use dummy value for passthrough */
133         if (args->pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
134                 args->pa_fhsize = MAXFIDSZ;
135
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;
142         }
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);
146
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;
154                         }
155                 }
156
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;
164                         }
165                 }
166         }
167
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 = '.';
173
174         args->pa_mntfromname[sizeof(args->pa_mntfromname)-1] = '\0';
175         for (p = args->pa_mntfromname; *p; p++)
176                 if (*p < ' ' || *p > '~')
177                         *p = '.';
178
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);
183
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);
188
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;
194
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);
204         }
205
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;
211
212         pmp = kmalloc(sizeof(struct puffs_mount), M_PUFFS, M_ZERO | M_WAITOK);
213
214         mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
215         mp->mnt_data = (qaddr_t)pmp;
216
217 #if 0
218         /*
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.
226          *
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).
234          *
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.
238          */
239         mp->mnt_iflags |= IMNT_MPSAFE;
240 #endif
241
242         pmp->pmp_status = PUFFSTAT_MOUNTING;
243         pmp->pmp_mp = mp;
244         pmp->pmp_msg_maxsize = args->pa_maxmsglen;
245         pmp->pmp_args = *args;
246
247         if (puffs_use_pagecache == 0)
248                 pmp->pmp_flags |= PUFFS_KFLAG_NOCACHE_PAGE;
249
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);
256
257         /*
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
261          */
262         if ((pmp->pmp_pi
263             = putter_attach(mntpid, args->pa_minor, pmp, &puffs_putter)) == NULL) {
264                 error = ENOENT;
265                 goto out;
266         }
267
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;
273
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);
283
284         if ((error = kthread_create(puffs_sop_thread, pmp, NULL,
285             "puffsop")) != 0)
286                 goto out;
287         pmp->pmp_sopthrcount = 1;
288
289         DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
290             mp, MPTOPUFFSMP(mp)));
291
292         vfs_getnewfsid(mp);
293
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);
296
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;
305 }
306
307 static int
308 puffs_vfsop_unmount(struct mount *mp, int mntflags)
309 {
310         PUFFS_MSG_VARS(vfs, unmount);
311         struct puffs_mount *pmp;
312         int error, force;
313
314         error = 0;
315         force = mntflags & MNT_FORCE;
316         pmp = MPTOPUFFSMP(mp);
317
318         DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
319             "status 0x%x\n", pmp->pmp_status));
320
321         /*
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.
328          */
329         error = vflush(mp, 1, force ? FORCECLOSE : 0);
330         if (error)
331                 goto out;
332
333         /*
334          * If we are not DYING, we should ask userspace's opinion
335          * about the situation
336          */
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);
341
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;
346
347                 PUFFS_MSG_ENQUEUEWAIT(pmp, park_unmount, error);
348                 PUFFS_MSG_RELEASE(unmount);
349
350                 error = checkerr(pmp, error, __func__);
351                 DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
352
353                 lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
354                 pmp->pmp_unmounting = 0;
355                 cv_broadcast(&pmp->pmp_unmounting_cv);
356         }
357
358         /*
359          * if userspace cooperated or we really need to die,
360          * screw what userland thinks and just die.
361          */
362         if (error == 0 || force) {
363                 struct puffs_sopreq *psopr;
364
365                 /* tell waiters & other resources to go unwait themselves */
366                 puffs_userdead(pmp);
367                 putter_detach(pmp->pmp_pi);
368
369                 /*
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().
376                  */
377                 while (pmp->pmp_refcount != 0)
378                         cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock);
379                 lockmgr(&pmp->pmp_lock, LK_RELEASE);
380
381                 /*
382                  * Release kernel thread now that there is nothing
383                  * it would be wanting to lock.
384                  */
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);
397                 }
398                 while (pmp->pmp_sopthrcount > 0)
399                         cv_wait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx);
400                 lockmgr(&pmp->pmp_sopmtx, LK_RELEASE);
401
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);
409
410                 kfree(pmp->pmp_pnodehash, M_PUFFS);
411                 kfree(pmp, M_PUFFS);
412                 error = 0;
413         } else {
414                 lockmgr(&pmp->pmp_lock, LK_RELEASE);
415         }
416
417  out:
418         DPRINTF(("puffs_unmount: return %d\n", error));
419         return error;
420 }
421
422 /*
423  * This doesn't need to travel to userspace
424  */
425 static int
426 puffs_vfsop_root(struct mount *mp, struct vnode **vpp)
427 {
428         struct puffs_mount *pmp = MPTOPUFFSMP(mp);
429         int rv;
430
431         rv = puffs_cookie2vnode(pmp, pmp->pmp_root_cookie, 1, vpp);
432         KKASSERT(rv != PUFFS_NOSUCHCOOKIE);
433
434         return rv;
435 }
436
437 static int
438 puffs_vfsop_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
439 {
440         PUFFS_MSG_VARS(vfs, statvfs);
441         struct puffs_mount *pmp;
442         int error = 0;
443
444         pmp = MPTOPUFFSMP(mp);
445
446         /*
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.
451          */
452         if (__predict_false(pmp->pmp_status == PUFFSTAT_MOUNTING))
453                 return EINPROGRESS;
454
455         PUFFS_MSG_ALLOC(vfs, statvfs);
456         puffs_msg_setinfo(park_statvfs, PUFFSOP_VFS, PUFFS_VFS_STATVFS, NULL);
457
458         PUFFS_MSG_ENQUEUEWAIT(pmp, park_statvfs, error);
459         error = checkerr(pmp, error, __func__);
460         statvfs_msg->pvfsr_sb.f_bsize = DEV_BSIZE;
461
462         /*
463          * Try to produce a sensible result even in the event
464          * of userspace error.
465          *
466          * XXX: cache the copy in non-error case
467          */
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));
474         }
475
476         PUFFS_MSG_RELEASE(statvfs);
477         return error;
478 }
479
480 #ifdef XXXDF
481 static int
482 pageflush(struct mount *mp, kauth_cred_t cred, int waitfor)
483 {
484         struct puffs_node *pn;
485         struct vnode *vp, *mvp;
486         int error, rv;
487
488         error = 0;
489
490         /* Allocate a marker vnode. */
491         if ((mvp = vnalloc(mp)) == NULL)
492                 return ENOMEM;
493
494         /*
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.
499          */
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;
506
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;
512                 }
513
514                 lockmgr(&mntvnode_lock, LK_RELEASE);
515
516                 /*
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.
521                  *
522                  * If the vnode is a goner, we quite obviously don't need
523                  * to sync it.
524                  *
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?
530                  */
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;
537                         }
538                         continue;
539                 }
540
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);
546                 }
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);
552                 }
553                 if (rv)
554                         error = rv;
555                 vput(vp);
556                 lockmgr(&mntvnode_lock, LK_EXCLUSIVE);
557         }
558         lockmgr(&mntvnode_lock, LK_RELEASE);
559         vnfree(mvp);
560
561         return error;
562 }
563 #endif
564
565 static int
566 puffs_vfsop_sync(struct mount *mp, int waitfor)
567 {
568         PUFFS_MSG_VARS(vfs, sync);
569         struct puffs_mount *pmp = MPTOPUFFSMP(mp);
570         int error, rv;
571
572 #ifdef XXXDF
573         error = pageflush(mp, cred, waitfor);
574 #endif
575
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);
580
581         PUFFS_MSG_ENQUEUEWAIT(pmp, park_sync, rv);
582         error = checkerr(pmp, rv, __func__);
583
584         PUFFS_MSG_RELEASE(sync);
585         DPRINTF(("puffs_vfsop_sync: result %d\n", error));
586         return error;
587 }
588
589 #ifdef XXXDF
590 static int
591 puffs_vfsop_fhtovp(struct mount *mp, struct vnode *rootvp, struct fid *fhp,
592     struct vnode **vpp)
593 {
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;
600
601         if (pmp->pmp_args.pa_fhsize == 0)
602                 return EOPNOTSUPP;
603
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;
610
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;
617                 }
618         }
619
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);
625
626         PUFFS_MSG_ENQUEUEWAIT(pmp, park_fhtonode, error);
627         error = checkerr(pmp, error, __func__);
628         if (error)
629                 goto out;
630
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;
642         }
643
644         *vpp = vp;
645  out:
646         puffs_msgmem_release(park_fhtonode);
647         return error;
648 }
649
650 static int
651 puffs_vfsop_vptofh(struct vnode *vp, struct fid *fhp)
652 {
653         PUFFS_MSG_VARS(vfs, nodetofh);
654         struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
655         size_t argsize, fhlen;
656         int error;
657
658         if (pmp->pmp_args.pa_fhsize == 0)
659                 return EOPNOTSUPP;
660
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;
667         }
668
669         if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
670                 fhlen = *fh_size;
671         else
672                 fhlen = PUFFS_FROMFHSIZE(*fh_size);
673
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);
679
680         PUFFS_MSG_ENQUEUEWAIT(pmp, park_nodetofh, error);
681         error = checkerr(pmp, error, __func__);
682
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);
689
690         if (error) {
691                 if (error == E2BIG)
692                         *fh_size = fhlen;
693                 goto out;
694         }
695
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;
701         }
702
703         if (*fh_size < fhlen) {
704                 *fh_size = fhlen;
705                 error = E2BIG;
706                 goto out;
707         }
708         *fh_size = fhlen;
709
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);
717                 }
718         }
719
720  out:
721         puffs_msgmem_release(park_nodetofh);
722         return error;
723 }
724 #endif
725
726 static int
727 puffs_vfsop_start(struct mount *mp, int flags)
728 {
729         struct puffs_mount *pmp = MPTOPUFFSMP(mp);
730
731         KKASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING);
732         pmp->pmp_status = PUFFSTAT_RUNNING;
733
734         return 0;
735 }
736
737 static int
738 puffs_vfsop_init(struct vfsconf *vfc)
739 {
740
741         puffs_msgif_init();
742         return 0;
743 }
744
745 static int
746 puffs_vfsop_uninit(struct vfsconf *vfc)
747 {
748
749         puffs_msgif_destroy();
750         return 0;
751 }
752
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)
757 {
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;
763
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;
774         }
775
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;
784         }
785         puffs_msg_setinfo(park_extattrctl,
786             PUFFSOP_VFS, PUFFS_VFS_EXTATTRCTL, pnc);
787
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);
794         }
795         error = puffs_msg_wait2(pmp, park_extattrctl, pnp, NULL);
796         PUFFS_MSG_RELEASE(extattrctl);
797         if (vp) {
798                 puffs_releasenode(pnp);
799         }
800
801         return checkerr(pmp, error, __func__);
802 }
803 #endif
804
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,
819 };
820
821 VFS_SET(puffs_vfsops, puffs, 0);
822 MODULE_DEPEND(puffs, putter, 1, 1, 1);