1 /* $NetBSD: puffs.c,v 1.116 2011/05/03 13:16:47 manu Exp $ */
4 * Copyright (c) 2005, 2006, 2007 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
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
32 #include <sys/param.h>
33 #include <sys/event.h>
34 #include <sys/filio.h>
35 #include <sys/mount.h>
49 #include <vfs/puffs/puffs_msgif.h>
52 #include "puffs_priv.h"
54 /* Most file systems want this for opts, so just give it to them */
55 const struct mntopt puffsmopts
[] = {
61 pthread_mutex_t pu_lock
= PTHREAD_MUTEX_INITIALIZER
;
63 #define FILLOP(lower, upper) \
65 if (pops->puffs_node_##lower) \
66 opmask[PUFFS_VN_##upper] = 1; \
67 } while (/*CONSTCOND*/0)
69 fillvnopmask(struct puffs_ops
*pops
, struct puffs_kargs
*pa
)
71 uint8_t *opmask
= pa
->pa_vnopmask
;
73 memset(opmask
, 0, sizeof(pa
->pa_vnopmask
));
75 FILLOP(create
, CREATE
);
79 FILLOP(access
, ACCESS
);
80 FILLOP(getattr
, GETATTR
);
81 FILLOP(setattr
, SETATTR
);
86 FILLOP(remove
, REMOVE
);
88 FILLOP(rename
, RENAME
);
91 FILLOP(symlink
, SYMLINK
);
92 FILLOP(readdir
, READDIR
);
93 FILLOP(readlink
, READLINK
);
94 FILLOP(reclaim
, RECLAIM
);
95 FILLOP(inactive
, INACTIVE
);
99 FILLOP(advlock
, ADVLOCK
);
100 FILLOP(abortop
, ABORTOP
);
101 FILLOP(pathconf
, PATHCONF
);
103 FILLOP(getextattr
, GETEXTATTR
);
104 FILLOP(setextattr
, SETEXTATTR
);
105 FILLOP(listextattr
, LISTEXTATTR
);
106 FILLOP(deleteextattr
, DELETEEXTATTR
);
111 * Go over all framev entries and write everything we can. This is
112 * mostly for the benefit of delivering "unmount" to the kernel.
115 finalpush(struct puffs_usermount
*pu
)
117 struct puffs_fctrl_io
*fio
;
119 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
120 if (fio
->stat
& FIO_WRGONE
)
123 puffs__framev_output(pu
, fio
->fctrl
, fio
);
129 puffs_kernerr_abort(struct puffs_usermount
*pu
, uint8_t type
,
130 int error
, const char *str
, puffs_cookie_t cookie
)
133 fprintf(stderr
, "abort: type %d, error %d, cookie %p (%s)\n",
134 type
, error
, cookie
, str
);
140 puffs_kernerr_log(struct puffs_usermount
*pu
, uint8_t type
,
141 int error
, const char *str
, puffs_cookie_t cookie
)
144 syslog(LOG_WARNING
, "kernel: type %d, error %d, cookie %p (%s)\n",
145 type
, error
, cookie
, str
);
149 puffs_getselectable(struct puffs_usermount
*pu
)
156 puffs__nextreq(struct puffs_usermount
*pu
)
161 rv
= pu
->pu_nextreq
++ | (uint64_t)1<<63;
168 puffs_setblockingmode(struct puffs_usermount
*pu
, int mode
)
172 assert(puffs_getstate(pu
) == PUFFS_STATE_RUNNING
);
174 if (mode
!= PUFFSDEV_BLOCK
&& mode
!= PUFFSDEV_NONBLOCK
) {
180 rv
= ioctl(pu
->pu_fd
, FIONBIO
, &x
);
183 if (mode
== PUFFSDEV_BLOCK
)
184 pu
->pu_state
&= ~PU_ASYNCFD
;
186 pu
->pu_state
|= PU_ASYNCFD
;
193 puffs_getstate(struct puffs_usermount
*pu
)
196 return pu
->pu_state
& PU_STATEMASK
;
200 puffs_setstacksize(struct puffs_usermount
*pu
, size_t ss
)
206 assert(puffs_getstate(pu
) == PUFFS_STATE_BEFOREMOUNT
);
208 psize
= sysconf(_SC_PAGESIZE
);
210 if (ss
< (size_t)minsize
|| ss
== PUFFS_STACKSIZE_MIN
) {
211 if (ss
!= PUFFS_STACKSIZE_MIN
)
212 fprintf(stderr
, "puffs_setstacksize: adjusting "
213 "stacksize to minimum %ld\n", minsize
);
227 fprintf(stderr
, "puffs_setstacksize: using next power of two: "
228 "%d\n", 1<<stackshift
);
231 pu
->pu_cc_stackshift
= stackshift
;
234 struct puffs_pathobj
*
235 puffs_getrootpathobj(struct puffs_usermount
*pu
)
237 struct puffs_node
*pnr
;
239 pnr
= pu
->pu_pn_root
;
249 puffs_setroot(struct puffs_usermount
*pu
, struct puffs_node
*pn
)
256 puffs_getroot(struct puffs_usermount
*pu
)
259 return pu
->pu_pn_root
;
263 puffs_setrootinfo(struct puffs_usermount
*pu
, enum vtype vt
,
264 vsize_t vsize
, dev_t rdev
)
266 struct puffs_kargs
*pargs
= pu
->pu_kargp
;
268 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
) {
269 warnx("puffs_setrootinfo: call has effect only "
274 pargs
->pa_root_vtype
= vt
;
275 pargs
->pa_root_vsize
= vsize
;
276 pargs
->pa_root_rdev
= rdev
;
280 puffs_getspecific(struct puffs_usermount
*pu
)
283 return pu
->pu_privdata
;
287 puffs_setspecific(struct puffs_usermount
*pu
, void *privdata
)
290 pu
->pu_privdata
= privdata
;
294 puffs_setmntinfo(struct puffs_usermount
*pu
,
295 const char *mntfromname
, const char *puffsname
)
297 struct puffs_kargs
*pargs
= pu
->pu_kargp
;
299 (void)strlcpy(pargs
->pa_mntfromname
, mntfromname
,
300 sizeof(pargs
->pa_mntfromname
));
301 (void)strlcpy(pargs
->pa_typename
, puffsname
,
302 sizeof(pargs
->pa_typename
));
306 puffs_getmaxreqlen(struct puffs_usermount
*pu
)
309 return pu
->pu_maxreqlen
;
313 puffs_setmaxreqlen(struct puffs_usermount
*pu
, size_t reqlen
)
316 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
317 warnx("puffs_setmaxreqlen: call has effect only "
320 pu
->pu_kargp
->pa_maxmsglen
= reqlen
;
324 puffs_setfhsize(struct puffs_usermount
*pu
, size_t fhsize
, int flags
)
327 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
328 warnx("puffs_setfhsize: call has effect only before mount\n");
330 pu
->pu_kargp
->pa_fhsize
= fhsize
;
331 pu
->pu_kargp
->pa_fhflags
= flags
;
335 puffs_setncookiehash(struct puffs_usermount
*pu
, int nhash
)
338 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
339 warnx("puffs_setfhsize: call has effect only before mount\n");
341 pu
->pu_kargp
->pa_nhashbuckets
= nhash
;
345 puffs_set_pathbuild(struct puffs_usermount
*pu
, pu_pathbuild_fn fn
)
348 pu
->pu_pathbuild
= fn
;
352 puffs_set_pathtransform(struct puffs_usermount
*pu
, pu_pathtransform_fn fn
)
355 pu
->pu_pathtransform
= fn
;
359 puffs_set_pathcmp(struct puffs_usermount
*pu
, pu_pathcmp_fn fn
)
366 puffs_set_pathfree(struct puffs_usermount
*pu
, pu_pathfree_fn fn
)
369 pu
->pu_pathfree
= fn
;
373 puffs_set_namemod(struct puffs_usermount
*pu
, pu_namemod_fn fn
)
380 puffs_set_errnotify(struct puffs_usermount
*pu
, pu_errnotify_fn fn
)
383 pu
->pu_errnotify
= fn
;
387 puffs_set_cmap(struct puffs_usermount
*pu
, pu_cmap_fn fn
)
394 puffs_ml_setloopfn(struct puffs_usermount
*pu
, puffs_ml_loop_fn lfn
)
401 puffs_ml_settimeout(struct puffs_usermount
*pu
, struct timespec
*ts
)
405 pu
->pu_ml_timep
= NULL
;
407 pu
->pu_ml_timeout
= *ts
;
408 pu
->pu_ml_timep
= &pu
->pu_ml_timeout
;
413 puffs_set_prepost(struct puffs_usermount
*pu
,
414 pu_prepost_fn pre
, pu_prepost_fn pst
)
422 puffs_setback(struct puffs_cc
*pcc
, int whatback
)
424 struct puffs_req
*preq
= puffs__framebuf_getdataptr(pcc
->pcc_pb
);
426 assert(PUFFSOP_OPCLASS(preq
->preq_opclass
) == PUFFSOP_VN
&& (
427 preq
->preq_optype
== PUFFS_VN_OPEN
||
428 preq
->preq_optype
== PUFFS_VN_MMAP
||
429 preq
->preq_optype
== PUFFS_VN_REMOVE
||
430 preq
->preq_optype
== PUFFS_VN_RMDIR
||
431 preq
->preq_optype
== PUFFS_VN_INACTIVE
));
433 preq
->preq_setbacks
|= whatback
& PUFFS_SETBACK_MASK
;
437 puffs_daemon(struct puffs_usermount
*pu
, int nochdir
, int noclose
)
440 int parent
, value
, fd
;
442 if (pipe(pu
->pu_dpipe
) == -1)
455 pu
->pu_state
|= PU_PUFFSDAEMON
;
458 close(pu
->pu_dpipe
[1]);
459 n
= read(pu
->pu_dpipe
[0], &value
, sizeof(int));
461 err(1, "puffs_daemon");
462 if (n
!= sizeof(value
))
463 errx(1, "puffs_daemon got %ld bytes", n
);
466 err(1, "puffs_daemon");
477 fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
480 dup2(fd
, STDIN_FILENO
);
481 dup2(fd
, STDOUT_FILENO
);
482 dup2(fd
, STDERR_FILENO
);
483 if (fd
> STDERR_FILENO
)
490 n
= write(pu
->pu_dpipe
[1], &errno
, sizeof(int));
496 shutdaemon(struct puffs_usermount
*pu
, int error
)
500 n
= write(pu
->pu_dpipe
[1], &error
, sizeof(int));
502 close(pu
->pu_dpipe
[0]);
503 close(pu
->pu_dpipe
[1]);
504 pu
->pu_state
&= ~PU_PUFFSDAEMON
;
508 puffs_mount(struct puffs_usermount
*pu
, const char *dir
, int mntflags
,
509 puffs_cookie_t cookie
)
515 pu
->pu_kargp
->pa_root_cookie
= cookie
;
518 /* kauth doesn't provide this service any longer */
520 mntflags
|= MNT_NOSUID
| MNT_NODEV
;
523 * Undocumented... Well, documented only here.
525 * This is used for imaginative purposes. If the env variable is
526 * set, puffs_mount() doesn't do the regular mount procedure.
527 * Rather, it crams the mount data down the comfd and sets comfd as
528 * the puffs descriptor.
530 * This shouldn't be used unless you can read my mind ( ... or write
531 * it, not to mention execute it, but that's starting to get silly).
533 if ((comfd
= getenv("PUFFS_COMFD")) != NULL
) {
536 if (sscanf(comfd
, "%d", &pu
->pu_fd
) != 1) {
541 /* check that what we got at least resembles an fd */
542 if (fcntl(pu
->pu_fd
, F_GETFL
) == -1) {
547 #define allwrite(buf, len) \
550 al_rv = write(pu->pu_fd, buf, len); \
551 if ((size_t)al_rv != len) { \
557 } while (/*CONSTCOND*/0)
559 allwrite(&len
, sizeof(len
));
561 len
= strlen(pu
->pu_kargp
->pa_mntfromname
)+1;
562 allwrite(&len
, sizeof(len
));
563 allwrite(pu
->pu_kargp
->pa_mntfromname
, len
);
564 allwrite(&mntflags
, sizeof(mntflags
));
565 len
= sizeof(*pu
->pu_kargp
);
566 allwrite(&len
, sizeof(len
));
567 allwrite(pu
->pu_kargp
, sizeof(*pu
->pu_kargp
));
568 allwrite(&pu
->pu_flags
, sizeof(pu
->pu_flags
));
575 if (realpath(dir
, rp
) == NULL
) {
580 if (strcmp(dir
, rp
) != 0) {
581 warnx("puffs_mount: \"%s\" is a relative path.", dir
);
582 warnx("puffs_mount: using \"%s\" instead.", rp
);
585 fd
= open(_PATH_PUFFS
, O_RDWR
);
587 warnx("puffs_mount: cannot open %s", _PATH_PUFFS
);
592 warnx("puffs_mount: device fd %d (<= 2), sure this is "
593 "what you want?", fd
);
598 warnx("puffs_mount: putter device stat failed");
601 pu
->pu_kargp
->pa_minor
= minor(sb
.st_rdev
);
603 if ((rv
= mount(MOUNT_PUFFS
, rp
, mntflags
,
604 pu
->pu_kargp
)) == -1)
608 PU_SETSTATE(pu
, PUFFS_STATE_RUNNING
);
618 if (pu
->pu_state
& PU_PUFFSDAEMON
)
619 shutdaemon(pu
, sverrno
);
625 struct puffs_usermount
*
626 puffs_init(struct puffs_ops
*pops
, const char *mntfromname
,
627 const char *puffsname
, void *priv
, uint32_t pflags
)
629 struct puffs_usermount
*pu
;
630 struct puffs_kargs
*pargs
;
633 if (puffsname
== PUFFS_DEFER
)
635 if (mntfromname
== PUFFS_DEFER
)
637 if (priv
== PUFFS_DEFER
)
640 pu
= malloc(sizeof(struct puffs_usermount
));
643 memset(pu
, 0, sizeof(struct puffs_usermount
));
645 pargs
= pu
->pu_kargp
= malloc(sizeof(struct puffs_kargs
));
648 memset(pargs
, 0, sizeof(struct puffs_kargs
));
650 pargs
->pa_vers
= PUFFSVERSION
;
651 pargs
->pa_flags
= PUFFS_FLAG_KERN(pflags
);
652 fillvnopmask(pops
, pargs
);
653 puffs_setmntinfo(pu
, mntfromname
, puffsname
);
655 puffs_zerostatvfs(&pargs
->pa_svfsb
);
656 pargs
->pa_root_cookie
= NULL
;
657 pargs
->pa_root_vtype
= VDIR
;
658 pargs
->pa_root_vsize
= 0;
659 pargs
->pa_root_rdev
= 0;
660 pargs
->pa_maxmsglen
= 0;
661 if (/*CONSTCOND*/ sizeof(time_t) == 4)
662 pargs
->pa_time32
= 1;
664 pargs
->pa_time32
= 0;
666 pu
->pu_flags
= pflags
;
668 free(pops
); /* XXX */
670 pu
->pu_privdata
= priv
;
671 pu
->pu_cc_stackshift
= PUFFS_CC_STACKSHIFT_DEFAULT
;
672 LIST_INIT(&pu
->pu_pnodelst
);
673 LIST_INIT(&pu
->pu_ios
);
674 LIST_INIT(&pu
->pu_ios_rmlist
);
675 LIST_INIT(&pu
->pu_ccmagazin
);
676 TAILQ_INIT(&pu
->pu_sched
);
678 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].rfb
= puffs__fsframe_read
;
679 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].wfb
= puffs__fsframe_write
;
680 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].cmpfb
= puffs__fsframe_cmp
;
681 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].gotfb
= puffs__fsframe_gotframe
;
682 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].fdnotfn
= puffs_framev_unmountonclose
;
684 /* defaults for some user-settable translation functions */
685 pu
->pu_cmap
= NULL
; /* identity translation */
687 pu
->pu_pathbuild
= puffs_stdpath_buildpath
;
688 pu
->pu_pathfree
= puffs_stdpath_freepath
;
689 pu
->pu_pathcmp
= puffs_stdpath_cmppath
;
690 pu
->pu_pathtransform
= NULL
;
691 pu
->pu_namemod
= NULL
;
693 pu
->pu_errnotify
= puffs_kernerr_log
;
695 PU_SETSTATE(pu
, PUFFS_STATE_BEFOREMOUNT
);
700 /* can't unmount() from here for obvious reasons */
708 puffs_cancel(struct puffs_usermount
*pu
, int error
)
711 assert(puffs_getstate(pu
) < PUFFS_STATE_RUNNING
);
712 shutdaemon(pu
, error
);
718 puffs_exit(struct puffs_usermount
*pu
, int unused
/* strict compat */)
720 struct puffs_framebuf
*pb
;
721 struct puffs_req
*preq
;
726 pb
= puffs_framebuf_make();
732 winlen
= sizeof(struct puffs_req
);
733 if (puffs_framebuf_getwindow(pb
, 0, &winp
, &winlen
) == -1) {
735 puffs_framebuf_destroy(pb
);
741 preq
->preq_buflen
= sizeof(struct puffs_req
);
742 preq
->preq_opclass
= PUFFSOP_UNMOUNT
;
743 preq
->preq_id
= puffs__nextreq(pu
);
745 puffs_framev_enqueue_justsend(pu
, puffs_getselectable(pu
), pb
, 1, 0);
750 /* no sigset_t static intializer */
751 static int sigs
[NSIG
] = { 0, };
752 static int sigcatch
= 0;
755 puffs_unmountonsignal(int sig
, bool sigignore
)
758 if (sig
< 0 || sig
>= (int)NSIG
) {
763 if (signal(sig
, SIG_IGN
) == SIG_ERR
)
774 * Actual mainloop. This is called from a context which can block.
775 * It is called either from puffs_mainloop (indirectly, via
776 * puffs_cc_continue() or from puffs_cc_yield()).
779 puffs__theloop(struct puffs_cc
*pcc
)
781 struct puffs_usermount
*pu
= pcc
->pcc_pu
;
782 struct puffs_framectrl
*pfctrl
;
783 struct puffs_fctrl_io
*fio
;
784 struct kevent
*curev
;
788 while (puffs_getstate(pu
) != PUFFS_STATE_UNMOUNTED
) {
791 * Schedule existing requests.
793 while ((pcc
= TAILQ_FIRST(&pu
->pu_sched
)) != NULL
) {
794 TAILQ_REMOVE(&pu
->pu_sched
, pcc
, pcc_schedent
);
801 /* XXX: can we still do these optimizations? */
804 * Do this here, because:
805 * a) loopfunc might generate some results
806 * b) it's still "after" event handling (except for round 1)
808 if (puffs_req_putput(ppr
) == -1)
810 puffs_req_resetput(ppr
);
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) {
816 puffs_framev_input(pu
, pfctrl
, XXX
);
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
)
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
835 puffs__framev_output(pu
, pfctrl
, fio
);
839 * Build list of which to enable/disable in writecheck.
842 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
843 if (fio
->stat
& FIO_WRGONE
)
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,
855 if (FIO_RM_WRITE(fio
)) {
856 EV_SET(&pu
->pu_evs
[nchanges
], fio
->io_fd
,
857 EVFILT_WRITE
, EV_DISABLE
, 0, 0,
859 fio
->stat
&= ~FIO_WR
;
864 ndone
= kevent(pu
->pu_kq
, pu
->pu_evs
, nchanges
,
865 pu
->pu_evs
, pu
->pu_nevs
, pu
->pu_ml_timep
);
878 /* iterate over the results */
879 for (curev
= pu
->pu_evs
; ndone
--; curev
++) {
883 /* get & possibly dispatch events from kernel */
884 if (curev
->ident
== puffsfd
) {
885 if (puffs_req_handle(pgr
, ppr
, 0) == -1)
891 fio
= (void *)curev
->udata
;
892 if (__predict_true(fio
!= NULL
))
896 if (curev
->flags
& EV_ERROR
) {
897 assert(curev
->filter
== EVFILT_WRITE
);
898 fio
->stat
&= ~FIO_WR
;
900 /* XXX: how to know if it's a transient error */
901 puffs__framev_writeclose(pu
, fio
,
903 puffs__framev_notify(fio
, PUFFS_FBIO_ERROR
);
908 if (curev
->filter
== EVFILT_READ
) {
909 puffs__framev_input(pu
, pfctrl
, fio
);
910 what
|= PUFFS_FBIO_READ
;
913 else if (curev
->filter
== EVFILT_WRITE
) {
914 puffs__framev_output(pu
, pfctrl
, fio
);
915 what
|= PUFFS_FBIO_WRITE
;
918 else if (__predict_false(curev
->filter
==EVFILT_SIGNAL
)){
919 if ((pu
->pu_state
& PU_DONEXIT
) == 0) {
920 PU_SETSFLAG(pu
, PU_DONEXIT
);
925 puffs__framev_notify(fio
, what
);
929 * Really free fd's now that we don't have references
932 while ((fio
= LIST_FIRST(&pu
->pu_ios_rmlist
)) != NULL
) {
933 LIST_REMOVE(fio
, fio_entries
);
938 if (puffs__cc_restoremain(pu
) == -1)
939 warn("cannot restore main context. impending doom");
942 puffs_mainloop(struct puffs_usermount
*pu
)
944 struct puffs_fctrl_io
*fio
;
945 struct puffs_cc
*pcc
;
946 struct kevent
*curev
;
950 assert(puffs_getstate(pu
) >= PUFFS_STATE_RUNNING
);
952 pu
->pu_kq
= kqueue();
955 pu
->pu_state
|= PU_HASKQ
;
957 puffs_setblockingmode(pu
, PUFFSDEV_NONBLOCK
);
958 if (puffs__framev_addfd_ctrl(pu
, puffs_getselectable(pu
),
959 PUFFS_FBIO_READ
| PUFFS_FBIO_WRITE
,
960 &pu
->pu_framectrl
[PU_FRAMECTRL_FS
]) == -1)
963 nevs
= pu
->pu_nevs
+ sigcatch
;
964 curev
= realloc(pu
->pu_evs
, nevs
* sizeof(struct kevent
));
970 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
971 EV_SET(curev
, fio
->io_fd
, EVFILT_READ
, EV_ADD
,
974 EV_SET(curev
, fio
->io_fd
, EVFILT_WRITE
, EV_ADD
| EV_DISABLE
,
978 for (i
= 0; i
< NSIG
; i
++) {
980 EV_SET(curev
, i
, EVFILT_SIGNAL
, EV_ADD
| EV_ENABLE
,
985 assert(curev
- pu
->pu_evs
== (ssize_t
)pu
->pu_nevs
);
986 if (kevent(pu
->pu_kq
, pu
->pu_evs
, pu
->pu_nevs
, NULL
, 0, NULL
) == -1)
989 pu
->pu_state
|= PU_INLOOP
;
992 * Create alternate execution context and jump to it. Note
993 * that we come "out" of savemain twice. Where we come out
994 * of it depends on the architecture. If the return address is
995 * stored on the stack, we jump out from puffs_cc_continue(),
996 * for a register return address from puffs__cc_savemain().
997 * PU_MAINRESTORE makes sure we DTRT in both cases.
999 if (puffs__cc_create(pu
, puffs__theloop
, &pcc
) == -1) {
1002 if (puffs__cc_savemain(pu
) == -1) {
1005 if ((pu
->pu_state
& PU_MAINRESTORE
) == 0)
1006 puffs_cc_continue(pcc
);
1012 /* store the real error for a while */