puffs.c revision 1.92.4.7 1 /* $NetBSD: puffs.c,v 1.92.4.7 2012/01/25 18:22:10 riz Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006, 2007 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>
33 #if !defined(lint)
34 __RCSID("$NetBSD: puffs.c,v 1.92.4.7 2012/01/25 18:22:10 riz Exp $");
35 #endif /* !lint */
36
37 #include <sys/param.h>
38 #include <sys/mount.h>
39
40 #include <assert.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <mntopts.h>
45 #include <paths.h>
46 #include <puffs.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <syslog.h>
51 #include <unistd.h>
52
53 #include "puffs_priv.h"
54
55 /* Most file systems want this for opts, so just give it to them */
56 const struct mntopt puffsmopts[] = {
57 MOPT_STDOPTS,
58 PUFFSMOPT_STD,
59 MOPT_NULL,
60 };
61
62 #ifdef PUFFS_WITH_THREADS
63 #include <pthread.h>
64 pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER;
65 #endif
66
67 #define FILLOP(lower, upper) \
68 do { \
69 if (pops->puffs_node_##lower) \
70 opmask[PUFFS_VN_##upper] = 1; \
71 } while (/*CONSTCOND*/0)
72 static void
73 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
74 {
75
76 memset(opmask, 0, PUFFS_VN_MAX);
77
78 FILLOP(create, CREATE);
79 FILLOP(mknod, MKNOD);
80 FILLOP(open, OPEN);
81 FILLOP(close, CLOSE);
82 FILLOP(access, ACCESS);
83 FILLOP(getattr, GETATTR);
84 FILLOP(setattr, SETATTR);
85 FILLOP(poll, POLL); /* XXX: not ready in kernel */
86 FILLOP(mmap, MMAP);
87 FILLOP(fsync, FSYNC);
88 FILLOP(seek, SEEK);
89 FILLOP(remove, REMOVE);
90 FILLOP(link, LINK);
91 FILLOP(rename, RENAME);
92 FILLOP(mkdir, MKDIR);
93 FILLOP(rmdir, RMDIR);
94 FILLOP(symlink, SYMLINK);
95 FILLOP(readdir, READDIR);
96 FILLOP(readlink, READLINK);
97 FILLOP(reclaim, RECLAIM);
98 FILLOP(inactive, INACTIVE);
99 FILLOP(print, PRINT);
100 FILLOP(read, READ);
101 FILLOP(write, WRITE);
102 FILLOP(advlock, ADVLOCK);
103 FILLOP(abortop, ABORTOP);
104 FILLOP(pathconf, PATHCONF);
105
106 FILLOP(getextattr, GETEXTATTR);
107 FILLOP(setextattr, SETEXTATTR);
108 FILLOP(listextattr, LISTEXTATTR);
109 FILLOP(deleteextattr, DELETEEXTATTR);
110 }
111 #undef FILLOP
112
113 /*
114 * Go over all framev entries and write everything we can. This is
115 * mostly for the benefit of delivering "unmount" to the kernel.
116 */
117 static void
118 finalpush(struct puffs_usermount *pu)
119 {
120 struct puffs_fctrl_io *fio;
121
122 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
123 if (fio->stat & FIO_WRGONE)
124 continue;
125
126 puffs__framev_output(pu, fio->fctrl, fio);
127 }
128 }
129
130 /*ARGSUSED*/
131 static void
132 puffs_defaulterror(struct puffs_usermount *pu, uint8_t type,
133 int error, const char *str, puffs_cookie_t cookie)
134 {
135
136 fprintf(stderr, "abort: type %d, error %d, cookie %p (%s)\n",
137 type, error, cookie, str);
138 abort();
139 }
140
141 int
142 puffs_getselectable(struct puffs_usermount *pu)
143 {
144
145 return pu->pu_fd;
146 }
147
148 uint64_t
149 puffs__nextreq(struct puffs_usermount *pu)
150 {
151 uint64_t rv;
152
153 PU_LOCK();
154 rv = pu->pu_nextreq++;
155 PU_UNLOCK();
156
157 return rv;
158 }
159
160 int
161 puffs_setblockingmode(struct puffs_usermount *pu, int mode)
162 {
163 int rv, x;
164
165 assert(puffs_getstate(pu) == PUFFS_STATE_RUNNING);
166
167 if (mode != PUFFSDEV_BLOCK && mode != PUFFSDEV_NONBLOCK) {
168 errno = EINVAL;
169 return -1;
170 }
171
172 x = mode;
173 rv = ioctl(pu->pu_fd, FIONBIO, &x);
174
175 if (rv == 0) {
176 if (mode == PUFFSDEV_BLOCK)
177 pu->pu_state &= ~PU_ASYNCFD;
178 else
179 pu->pu_state |= PU_ASYNCFD;
180 }
181
182 return rv;
183 }
184
185 int
186 puffs_getstate(struct puffs_usermount *pu)
187 {
188
189 return pu->pu_state & PU_STATEMASK;
190 }
191
192 void
193 puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
194 {
195 long psize, minsize;
196 int stackshift;
197 int bonus;
198
199 assert(puffs_getstate(pu) == PUFFS_STATE_BEFOREMOUNT);
200
201 psize = sysconf(_SC_PAGESIZE);
202 minsize = 4*psize;
203 if (ss < minsize || ss == PUFFS_STACKSIZE_MIN) {
204 if (ss != PUFFS_STACKSIZE_MIN)
205 fprintf(stderr, "puffs_setstacksize: adjusting "
206 "stacksize to minimum %ld\n", minsize);
207 ss = 4*psize;
208 }
209
210 stackshift = -1;
211 bonus = 0;
212 while (ss) {
213 if (ss & 0x1)
214 bonus++;
215 ss >>= 1;
216 stackshift++;
217 }
218 if (bonus > 1) {
219 stackshift++;
220 fprintf(stderr, "puffs_setstacksize: using next power of two: "
221 "%d\n", 1<<stackshift);
222 }
223
224 pu->pu_cc_stackshift = stackshift;
225 }
226
227 struct puffs_pathobj *
228 puffs_getrootpathobj(struct puffs_usermount *pu)
229 {
230 struct puffs_node *pnr;
231
232 pnr = pu->pu_pn_root;
233 if (pnr == NULL) {
234 errno = ENOENT;
235 return NULL;
236 }
237
238 return &pnr->pn_po;
239 }
240
241 void
242 puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn)
243 {
244
245 pu->pu_pn_root = pn;
246 }
247
248 struct puffs_node *
249 puffs_getroot(struct puffs_usermount *pu)
250 {
251
252 return pu->pu_pn_root;
253 }
254
255 void
256 puffs_setrootinfo(struct puffs_usermount *pu, enum vtype vt,
257 vsize_t vsize, dev_t rdev)
258 {
259 struct puffs_kargs *pargs = pu->pu_kargp;
260
261 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) {
262 warnx("puffs_setrootinfo: call has effect only "
263 "before mount\n");
264 return;
265 }
266
267 pargs->pa_root_vtype = vt;
268 pargs->pa_root_vsize = vsize;
269 pargs->pa_root_rdev = rdev;
270 }
271
272 void *
273 puffs_getspecific(struct puffs_usermount *pu)
274 {
275
276 return pu->pu_privdata;
277 }
278
279 void
280 puffs_setspecific(struct puffs_usermount *pu, void *privdata)
281 {
282
283 pu->pu_privdata = privdata;
284 }
285
286 void
287 puffs_setmntinfo(struct puffs_usermount *pu,
288 const char *mntfromname, const char *puffsname)
289 {
290 struct puffs_kargs *pargs = pu->pu_kargp;
291
292 (void)strlcpy(pargs->pa_mntfromname, mntfromname,
293 sizeof(pargs->pa_mntfromname));
294 (void)strlcpy(pargs->pa_typename, puffsname,
295 sizeof(pargs->pa_typename));
296 }
297
298 size_t
299 puffs_getmaxreqlen(struct puffs_usermount *pu)
300 {
301
302 return pu->pu_maxreqlen;
303 }
304
305 void
306 puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen)
307 {
308
309 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
310 warnx("puffs_setmaxreqlen: call has effect only "
311 "before mount\n");
312
313 pu->pu_kargp->pa_maxmsglen = reqlen;
314 }
315
316 void
317 puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags)
318 {
319
320 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
321 warnx("puffs_setfhsize: call has effect only before mount\n");
322
323 pu->pu_kargp->pa_fhsize = fhsize;
324 pu->pu_kargp->pa_fhflags = flags;
325 }
326
327 void
328 puffs_setncookiehash(struct puffs_usermount *pu, int nhash)
329 {
330
331 if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
332 warnx("puffs_setfhsize: call has effect only before mount\n");
333
334 pu->pu_kargp->pa_nhashbuckets = nhash;
335 }
336
337 void
338 puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
339 {
340
341 pu->pu_pathbuild = fn;
342 }
343
344 void
345 puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
346 {
347
348 pu->pu_pathtransform = fn;
349 }
350
351 void
352 puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
353 {
354
355 pu->pu_pathcmp = fn;
356 }
357
358 void
359 puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
360 {
361
362 pu->pu_pathfree = fn;
363 }
364
365 void
366 puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
367 {
368
369 pu->pu_namemod = fn;
370 }
371
372 void
373 puffs_set_errnotify(struct puffs_usermount *pu, pu_errnotify_fn fn)
374 {
375
376 pu->pu_errnotify = fn;
377 }
378
379 void
380 puffs_set_cmap(struct puffs_usermount *pu, pu_cmap_fn fn)
381 {
382
383 pu->pu_cmap = fn;
384 }
385
386 void
387 puffs_ml_setloopfn(struct puffs_usermount *pu, puffs_ml_loop_fn lfn)
388 {
389
390 pu->pu_ml_lfn = lfn;
391 }
392
393 void
394 puffs_ml_settimeout(struct puffs_usermount *pu, struct timespec *ts)
395 {
396
397 if (ts == NULL) {
398 pu->pu_ml_timep = NULL;
399 } else {
400 pu->pu_ml_timeout = *ts;
401 pu->pu_ml_timep = &pu->pu_ml_timeout;
402 }
403 }
404
405 void
406 puffs_set_prepost(struct puffs_usermount *pu,
407 pu_prepost_fn pre, pu_prepost_fn pst)
408 {
409
410 pu->pu_oppre = pre;
411 pu->pu_oppost = pst;
412 }
413
414 void
415 puffs_setback(struct puffs_cc *pcc, int whatback)
416 {
417 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
418
419 assert(PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && (
420 preq->preq_optype == PUFFS_VN_OPEN ||
421 preq->preq_optype == PUFFS_VN_MMAP ||
422 preq->preq_optype == PUFFS_VN_REMOVE ||
423 preq->preq_optype == PUFFS_VN_RMDIR ||
424 preq->preq_optype == PUFFS_VN_INACTIVE));
425
426 preq->preq_setbacks |= whatback & PUFFS_SETBACK_MASK;
427 }
428
429 int
430 puffs_daemon(struct puffs_usermount *pu, int nochdir, int noclose)
431 {
432 ssize_t n;
433 int parent, value, fd;
434
435 if (pipe(pu->pu_dpipe) == -1)
436 return -1;
437
438 switch (fork()) {
439 case -1:
440 return -1;
441 case 0:
442 parent = 0;
443 break;
444 default:
445 parent = 1;
446 break;
447 }
448 pu->pu_state |= PU_PUFFSDAEMON;
449
450 if (parent) {
451 n = read(pu->pu_dpipe[0], &value, sizeof(int));
452 if (n == -1)
453 err(1, "puffs_daemon");
454 assert(n == sizeof(value));
455 if (value) {
456 errno = value;
457 err(1, "puffs_daemon");
458 }
459 exit(0);
460 } else {
461 if (setsid() == -1)
462 goto fail;
463
464 if (!nochdir)
465 chdir("/");
466
467 if (!noclose) {
468 fd = open(_PATH_DEVNULL, O_RDWR, 0);
469 if (fd == -1)
470 goto fail;
471 dup2(fd, STDIN_FILENO);
472 dup2(fd, STDOUT_FILENO);
473 dup2(fd, STDERR_FILENO);
474 if (fd > STDERR_FILENO)
475 close(fd);
476 }
477 return 0;
478 }
479
480 fail:
481 n = write(pu->pu_dpipe[1], &errno, sizeof(int));
482 assert(n == 4);
483 return -1;
484 }
485
486 static void
487 shutdaemon(struct puffs_usermount *pu, int error)
488 {
489 ssize_t n;
490
491 n = write(pu->pu_dpipe[1], &error, sizeof(int));
492 assert(n == 4);
493 close(pu->pu_dpipe[0]);
494 close(pu->pu_dpipe[1]);
495 pu->pu_state &= ~PU_PUFFSDAEMON;
496 }
497
498 int
499 puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags,
500 puffs_cookie_t cookie)
501 {
502 char rp[MAXPATHLEN];
503 int rv, fd, sverrno;
504 char *comfd;
505
506 pu->pu_kargp->pa_root_cookie = cookie;
507
508 /* XXXkludgehere */
509 /* kauth doesn't provide this service any longer */
510 if (geteuid() != 0)
511 mntflags |= MNT_NOSUID | MNT_NODEV;
512
513 if (realpath(dir, rp) == NULL) {
514 rv = -1;
515 goto out;
516 }
517
518 if (strcmp(dir, rp) != 0) {
519 warnx("puffs_mount: \"%s\" is a relative path.", dir);
520 warnx("puffs_mount: using \"%s\" instead.", rp);
521 }
522
523 /*
524 * Undocumented... Well, documented only here.
525 *
526 * This is used for imaginative purposes. If the env variable is
527 * set, puffs_mount() doesn't do the regular mount procedure.
528 * Rather, it crams the mount data down the comfd and sets comfd as
529 * the puffs descriptor.
530 *
531 * This shouldn't be used unless you can read my mind ( ... or write
532 * it, not to mention execute it, but that's starting to get silly).
533 */
534 if ((comfd = getenv("PUFFS_COMFD")) != NULL) {
535 size_t len;
536
537 if (sscanf(comfd, "%d", &pu->pu_fd) != 1) {
538 errno = EINVAL;
539 rv = -1;
540 goto out;
541 }
542 /* check that what we got at least resembles an fd */
543 if (fcntl(pu->pu_fd, F_GETFL) == -1) {
544 rv = -1;
545 goto out;
546 }
547
548 len = strlen(dir)+1;
549
550 #define allwrite(buf, len) \
551 do { \
552 ssize_t al_rv; \
553 al_rv = write(pu->pu_fd, buf, len); \
554 if (al_rv != len) { \
555 if (al_rv != -1) \
556 errno = EIO; \
557 rv = -1; \
558 abort();\
559 goto out; \
560 } \
561 } while (/*CONSTCOND*/0)
562 allwrite(&len, sizeof(len));
563 allwrite(dir, len);
564 len = strlen(pu->pu_kargp->pa_mntfromname)+1;
565 allwrite(&len, sizeof(len));
566 allwrite(pu->pu_kargp->pa_mntfromname, len);
567 allwrite(&mntflags, sizeof(mntflags));
568 allwrite(pu->pu_kargp, sizeof(*pu->pu_kargp));
569 allwrite(&pu->pu_flags, sizeof(pu->pu_flags));
570 #undef allwrite
571
572 rv = 0;
573 } else {
574 fd = open(_PATH_PUFFS, O_RDWR);
575 if (fd == -1) {
576 warnx("puffs_mount: cannot open %s", _PATH_PUFFS);
577 rv = -1;
578 goto out;
579 }
580 if (fd <= 2)
581 warnx("puffs_mount: device fd %d (<= 2), sure this is "
582 "what you want?", fd);
583
584 pu->pu_kargp->pa_fd = pu->pu_fd = fd;
585 if ((rv = mount(MOUNT_PUFFS, rp, mntflags,
586 pu->pu_kargp, sizeof(struct puffs_kargs))) == -1)
587 goto out;
588 }
589
590 PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
591
592 out:
593 if (rv != 0)
594 sverrno = errno;
595 else
596 sverrno = 0;
597 free(pu->pu_kargp);
598 pu->pu_kargp = NULL;
599
600 if (pu->pu_state & PU_PUFFSDAEMON)
601 shutdaemon(pu, sverrno);
602
603 errno = sverrno;
604 return rv;
605 }
606
607
608 /*ARGSUSED*/
609 struct puffs_usermount *
610 _puffs_init52(int dummy, struct puffs_ops *pops, const char *mntfromname,
611 const char *puffsname, void *priv, uint32_t pflags)
612 {
613 struct puffs_usermount *pu;
614 struct puffs_kargs *pargs;
615 int sverrno;
616
617 if (puffsname == PUFFS_DEFER)
618 puffsname = "n/a";
619 if (mntfromname == PUFFS_DEFER)
620 mntfromname = "n/a";
621 if (priv == PUFFS_DEFER)
622 priv = NULL;
623
624 pu = malloc(sizeof(struct puffs_usermount));
625 if (pu == NULL)
626 goto failfree;
627 memset(pu, 0, sizeof(struct puffs_usermount));
628
629 pargs = pu->pu_kargp = malloc(sizeof(struct puffs_kargs));
630 if (pargs == NULL)
631 goto failfree;
632 memset(pargs, 0, sizeof(struct puffs_kargs));
633
634 pargs->pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
635 pargs->pa_flags = PUFFS_FLAG_KERN(pflags);
636 fillvnopmask(pops, pargs->pa_vnopmask);
637 puffs_setmntinfo(pu, mntfromname, puffsname);
638
639 puffs_zerostatvfs(&pargs->pa_svfsb);
640 pargs->pa_root_cookie = NULL;
641 pargs->pa_root_vtype = VDIR;
642 pargs->pa_root_vsize = 0;
643 pargs->pa_root_rdev = 0;
644 pargs->pa_maxmsglen = 0;
645
646 pu->pu_flags = pflags;
647 pu->pu_ops = *pops;
648 free(pops); /* XXX */
649
650 pu->pu_privdata = priv;
651 pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT;
652 LIST_INIT(&pu->pu_pnodelst);
653 LIST_INIT(&pu->pu_ios);
654 LIST_INIT(&pu->pu_ios_rmlist);
655 LIST_INIT(&pu->pu_ccmagazin);
656 TAILQ_INIT(&pu->pu_sched);
657
658 pu->pu_framectrl[PU_FRAMECTRL_FS].rfb = puffs__fsframe_read;
659 pu->pu_framectrl[PU_FRAMECTRL_FS].wfb = puffs__fsframe_write;
660 pu->pu_framectrl[PU_FRAMECTRL_FS].cmpfb = puffs__fsframe_cmp;
661 pu->pu_framectrl[PU_FRAMECTRL_FS].gotfb = puffs__fsframe_gotframe;
662 pu->pu_framectrl[PU_FRAMECTRL_FS].fdnotfn = puffs_framev_unmountonclose;
663
664 /* defaults for some user-settable translation functions */
665 pu->pu_cmap = NULL; /* identity translation */
666
667 pu->pu_pathbuild = puffs_stdpath_buildpath;
668 pu->pu_pathfree = puffs_stdpath_freepath;
669 pu->pu_pathcmp = puffs_stdpath_cmppath;
670 pu->pu_pathtransform = NULL;
671 pu->pu_namemod = NULL;
672
673 pu->pu_errnotify = puffs_defaulterror;
674
675 PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT);
676
677 return pu;
678
679 failfree:
680 /* can't unmount() from here for obvious reasons */
681 sverrno = errno;
682 free(pu);
683 errno = sverrno;
684 return NULL;
685 }
686
687 struct puffs_usermount *
688 _puffs_init(int dummy, struct puffs_ops51 *pops51, const char *mntfromname,
689 const char *puffsname, void *priv, uint32_t pflags)
690 {
691 struct puffs_ops *pops;
692
693 PUFFSOP_INIT(pops);
694
695 pops->puffs_fs_unmount = pops51->puffs_fs_unmount;
696 pops->puffs_fs_statvfs = pops51->puffs_fs_statvfs;
697 pops->puffs_fs_sync = pops51->puffs_fs_sync;
698 pops->puffs_fs_fhtonode = pops51->puffs_fs_fhtonode;
699 pops->puffs_fs_nodetofh = pops51->puffs_fs_nodetofh;
700 pops->puffs_node_lookup = pops51->puffs_node_lookup;
701 pops->puffs_node_create = pops51->puffs_node_create;
702 pops->puffs_node_mknod = pops51->puffs_node_mknod;
703 pops->puffs_node_open = pops51->puffs_node_open;
704 pops->puffs_node_close = pops51->puffs_node_close;
705 pops->puffs_node_access = pops51->puffs_node_access;
706 pops->puffs_node_getattr = pops51->puffs_node_getattr;
707 pops->puffs_node_setattr = pops51->puffs_node_setattr;
708 pops->puffs_node_poll = pops51->puffs_node_poll;
709 pops->puffs_node_mmap = pops51->puffs_node_mmap;
710 pops->puffs_node_fsync = pops51->puffs_node_fsync;
711 pops->puffs_node_seek = pops51->puffs_node_seek;
712 pops->puffs_node_remove = pops51->puffs_node_remove;
713 pops->puffs_node_link = pops51->puffs_node_link;
714 pops->puffs_node_rename = pops51->puffs_node_rename;
715 pops->puffs_node_mkdir = pops51->puffs_node_mkdir;
716 pops->puffs_node_rmdir = pops51->puffs_node_rmdir;
717 pops->puffs_node_symlink = pops51->puffs_node_symlink;
718 pops->puffs_node_readdir = pops51->puffs_node_readdir;
719 pops->puffs_node_readlink = pops51->puffs_node_readlink;
720 pops->puffs_node_reclaim = pops51->puffs_node_reclaim;
721 pops->puffs_node_inactive = pops51->puffs_node_inactive;
722 pops->puffs_node_print = pops51->puffs_node_print;
723 pops->puffs_node_pathconf = pops51->puffs_node_pathconf;
724 pops->puffs_node_advlock = pops51->puffs_node_advlock;
725 pops->puffs_node_read = pops51->puffs_node_read;
726 pops->puffs_node_write = pops51->puffs_node_write;
727 pops->puffs_node_abortop = pops51->puffs_node_abortop;
728
729 free(pops51);
730
731 return _puffs_init52(dummy, pops, mntfromname,
732 puffsname, priv, pflags);
733 }
734
735
736 void
737 puffs_cancel(struct puffs_usermount *pu, int error)
738 {
739
740 assert(puffs_getstate(pu) < PUFFS_STATE_RUNNING);
741 shutdaemon(pu, error);
742 free(pu);
743 }
744
745 /*
746 * XXX: there's currently no clean way to request unmount from
747 * within the user server, so be very brutal about it.
748 */
749 /*ARGSUSED1*/
750 int
751 puffs_exit(struct puffs_usermount *pu, int force)
752 {
753 struct puffs_node *pn;
754
755 force = 1; /* currently */
756 assert((pu->pu_state & PU_PUFFSDAEMON) == 0);
757
758 if (pu->pu_fd)
759 close(pu->pu_fd);
760
761 while ((pn = LIST_FIRST(&pu->pu_pnodelst)) != NULL)
762 puffs_pn_put(pn);
763
764 finalpush(pu);
765 puffs__framev_exit(pu);
766 puffs__cc_exit(pu);
767 if (pu->pu_state & PU_HASKQ)
768 close(pu->pu_kq);
769 free(pu);
770
771 return 0; /* always succesful for now, WILL CHANGE */
772 }
773
774 /*
775 * Actual mainloop. This is called from a context which can block.
776 * It is called either from puffs_mainloop (indirectly, via
777 * puffs_cc_continue() or from puffs_cc_yield()).
778 */
779 void
780 puffs__theloop(struct puffs_cc *pcc)
781 {
782 struct puffs_usermount *pu = pcc->pcc_pu;
783 struct puffs_framectrl *pfctrl;
784 struct puffs_fctrl_io *fio;
785 struct kevent *curev;
786 size_t nchanges;
787 int ndone;
788
789 while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) {
790 /*
791 * Schedule existing requests.
792 */
793 while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) {
794 TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent);
795 puffs__goto(pcc);
796 }
797
798 if (pu->pu_ml_lfn)
799 pu->pu_ml_lfn(pu);
800
801 /* XXX: can we still do these optimizations? */
802 #if 0
803 /*
804 * Do this here, because:
805 * a) loopfunc might generate some results
806 * b) it's still "after" event handling (except for round 1)
807 */
808 if (puffs_req_putput(ppr) == -1)
809 goto out;
810 puffs_req_resetput(ppr);
811
812 /* micro optimization: skip kevent syscall if possible */
813 if (pu->pu_nfds == 1 && pu->pu_ml_timep == NULL
814 && (pu->pu_state & PU_ASYNCFD) == 0) {
815 pfctrl = XXX->fctrl;
816 puffs_framev_input(pu, pfctrl, XXX);
817 continue;
818 }
819 #endif
820
821 /* else: do full processing */
822 /* Don't bother worrying about O(n) for now */
823 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
824 if (fio->stat & FIO_WRGONE)
825 continue;
826
827 pfctrl = fio->fctrl;
828
829 /*
830 * Try to write out everything to avoid the
831 * need for enabling EVFILT_WRITE. The likely
832 * case is that we can fit everything into the
833 * socket buffer.
834 */
835 puffs__framev_output(pu, pfctrl, fio);
836 }
837
838 /*
839 * Build list of which to enable/disable in writecheck.
840 */
841 nchanges = 0;
842 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
843 if (fio->stat & FIO_WRGONE)
844 continue;
845
846 /* en/disable write checks for kqueue as needed */
847 assert((FIO_EN_WRITE(fio) && FIO_RM_WRITE(fio)) == 0);
848 if (FIO_EN_WRITE(fio)) {
849 EV_SET(&pu->pu_evs[nchanges], fio->io_fd,
850 EVFILT_WRITE, EV_ENABLE, 0, 0,
851 (uintptr_t)fio);
852 fio->stat |= FIO_WR;
853 nchanges++;
854 }
855 if (FIO_RM_WRITE(fio)) {
856 EV_SET(&pu->pu_evs[nchanges], fio->io_fd,
857 EVFILT_WRITE, EV_DISABLE, 0, 0,
858 (uintptr_t)fio);
859 fio->stat &= ~FIO_WR;
860 nchanges++;
861 }
862 assert(nchanges <= pu->pu_nfds);
863 }
864
865 ndone = kevent(pu->pu_kq, pu->pu_evs, nchanges,
866 pu->pu_evs, 2*pu->pu_nfds, pu->pu_ml_timep);
867
868 if (ndone == -1) {
869 if (errno != EINTR)
870 break;
871 else
872 continue;
873 }
874
875 /* uoptimize */
876 if (ndone == 0)
877 continue;
878
879 /* iterate over the results */
880 for (curev = pu->pu_evs; ndone--; curev++) {
881 int what;
882
883 #if 0
884 /* get & possibly dispatch events from kernel */
885 if (curev->ident == puffsfd) {
886 if (puffs_req_handle(pgr, ppr, 0) == -1)
887 goto out;
888 continue;
889 }
890 #endif
891
892 fio = (void *)curev->udata;
893 pfctrl = fio->fctrl;
894 if (curev->flags & EV_ERROR) {
895 assert(curev->filter == EVFILT_WRITE);
896 fio->stat &= ~FIO_WR;
897
898 /* XXX: how to know if it's a transient error */
899 puffs__framev_writeclose(pu, fio,
900 (int)curev->data);
901 puffs__framev_notify(fio, PUFFS_FBIO_ERROR);
902 continue;
903 }
904
905 what = 0;
906 if (curev->filter == EVFILT_READ) {
907 puffs__framev_input(pu, pfctrl, fio);
908 what |= PUFFS_FBIO_READ;
909 }
910
911 else if (curev->filter == EVFILT_WRITE) {
912 puffs__framev_output(pu, pfctrl, fio);
913 what |= PUFFS_FBIO_WRITE;
914 }
915 if (what)
916 puffs__framev_notify(fio, what);
917 }
918
919 /*
920 * Really free fd's now that we don't have references
921 * to them.
922 */
923 while ((fio = LIST_FIRST(&pu->pu_ios_rmlist)) != NULL) {
924 LIST_REMOVE(fio, fio_entries);
925 free(fio);
926 }
927 }
928
929 if (puffs__cc_restoremain(pu) == -1)
930 warn("cannot restore main context. impending doom");
931 }
932
933 int
934 puffs_mainloop(struct puffs_usermount *pu)
935 {
936 struct puffs_fctrl_io *fio;
937 struct puffs_cc *pcc;
938 struct kevent *curev;
939 int sverrno;
940
941 assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
942
943 pu->pu_kq = kqueue();
944 if (pu->pu_kq == -1)
945 goto out;
946 pu->pu_state |= PU_HASKQ;
947
948 puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK);
949 if (puffs__framev_addfd_ctrl(pu, puffs_getselectable(pu),
950 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE,
951 &pu->pu_framectrl[PU_FRAMECTRL_FS]) == -1)
952 goto out;
953
954 curev = realloc(pu->pu_evs, (2*pu->pu_nfds)*sizeof(struct kevent));
955 if (curev == NULL)
956 goto out;
957 pu->pu_evs = curev;
958
959 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
960 EV_SET(curev, fio->io_fd, EVFILT_READ, EV_ADD,
961 0, 0, (uintptr_t)fio);
962 curev++;
963 EV_SET(curev, fio->io_fd, EVFILT_WRITE, EV_ADD | EV_DISABLE,
964 0, 0, (uintptr_t)fio);
965 curev++;
966 }
967 if (kevent(pu->pu_kq, pu->pu_evs, 2*pu->pu_nfds, NULL, 0, NULL) == -1)
968 goto out;
969
970 pu->pu_state |= PU_INLOOP;
971
972 /*
973 * Create alternate execution context and jump to it. Note
974 * that we come "out" of savemain twice. Where we come out
975 * of it depends on the architecture. If the return address is
976 * stored on the stack, we jump out from puffs_cc_continue(),
977 * for a register return address from puffs__cc_savemain().
978 * PU_MAINRESTORE makes sure we DTRT in both cases.
979 */
980 if (puffs__cc_create(pu, puffs__theloop, &pcc) == -1) {
981 goto out;
982 }
983 if (puffs__cc_savemain(pu) == -1) {
984 goto out;
985 }
986 if ((pu->pu_state & PU_MAINRESTORE) == 0)
987 puffs_cc_continue(pcc);
988
989 finalpush(pu);
990 errno = 0;
991
992 out:
993 /* store the real error for a while */
994 sverrno = errno;
995
996 errno = sverrno;
997 if (errno)
998 return -1;
999 else
1000 return 0;
1001 }
1002