1 /* $NetBSD: puffs.c,v 1.120 2015/06/17 00:15:26 christos 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/cdefs.h>
34 __RCSID("$NetBSD: puffs.c,v 1.120 2015/06/17 00:15:26 christos Exp $");
37 #include <sys/param.h>
38 #include <sys/mount.h>
48 #endif /* !defined(__minix) */
56 #include "puffs_priv.h"
58 /* Most file systems want this for opts, so just give it to them */
59 const struct mntopt puffsmopts
[] = {
66 pthread_mutex_t pu_lock
= PTHREAD_MUTEX_INITIALIZER
;
67 #endif /* !defined(__minix) */
69 #define FILLOP(lower, upper) \
71 if (pops->puffs_node_##lower) \
72 opmask[PUFFS_VN_##upper] = 1; \
73 } while (/*CONSTCOND*/0)
75 fillvnopmask(struct puffs_ops
*pops
, struct puffs_kargs
*pa
)
77 uint8_t *opmask
= pa
->pa_vnopmask
;
79 memset(opmask
, 0, sizeof(pa
->pa_vnopmask
));
81 FILLOP(create
, CREATE
);
85 FILLOP(access
, ACCESS
);
86 FILLOP(getattr
, GETATTR
);
87 FILLOP(setattr
, SETATTR
);
92 FILLOP(remove
, REMOVE
);
94 FILLOP(rename
, RENAME
);
97 FILLOP(symlink
, SYMLINK
);
98 FILLOP(readdir
, READDIR
);
99 FILLOP(readlink
, READLINK
);
100 FILLOP(reclaim
, RECLAIM
);
101 FILLOP(inactive
, INACTIVE
);
102 FILLOP(print
, PRINT
);
104 FILLOP(write
, WRITE
);
105 FILLOP(advlock
, ADVLOCK
);
106 FILLOP(abortop
, ABORTOP
);
107 FILLOP(pathconf
, PATHCONF
);
109 FILLOP(getextattr
, GETEXTATTR
);
110 FILLOP(setextattr
, SETEXTATTR
);
111 FILLOP(listextattr
, LISTEXTATTR
);
112 FILLOP(deleteextattr
, DELETEEXTATTR
);
113 FILLOP(fallocate
, FALLOCATE
);
114 FILLOP(fdiscard
, FDISCARD
);
119 * Go over all framev entries and write everything we can. This is
120 * mostly for the benefit of delivering "unmount" to the kernel.
123 finalpush(struct puffs_usermount
*pu
)
125 #if !defined(__minix)
126 struct puffs_fctrl_io
*fio
;
128 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
129 if (fio
->stat
& FIO_WRGONE
)
132 puffs__framev_output(pu
, fio
->fctrl
, fio
);
134 #endif /* !defined(__minix) */
139 puffs_kernerr_abort(struct puffs_usermount
*pu
, uint8_t type
,
140 int error
, const char *str
, puffs_cookie_t cookie
)
143 #if !defined(__minix)
144 warnx("abort: type %d, error %d, cookie %p (%s)",
146 lpuffs_debug("abort: type %d, error %d, cookie %p (%s)\n",
147 #endif /* !defined(__minix) */
148 type
, error
, cookie
, str
);
154 puffs_kernerr_log(struct puffs_usermount
*pu
, uint8_t type
,
155 int error
, const char *str
, puffs_cookie_t cookie
)
158 syslog(LOG_WARNING
, "kernel: type %d, error %d, cookie %p (%s)",
159 type
, error
, cookie
, str
);
162 #if !defined(__minix)
164 puffs_getselectable(struct puffs_usermount
*pu
)
171 puffs__nextreq(struct puffs_usermount
*pu
)
176 rv
= pu
->pu_nextreq
++ | (uint64_t)1<<63;
183 puffs_setblockingmode(struct puffs_usermount
*pu
, int mode
)
187 assert(puffs_getstate(pu
) == PUFFS_STATE_RUNNING
);
189 if (mode
!= PUFFSDEV_BLOCK
&& mode
!= PUFFSDEV_NONBLOCK
) {
195 rv
= ioctl(pu
->pu_fd
, FIONBIO
, &x
);
198 if (mode
== PUFFSDEV_BLOCK
)
199 pu
->pu_state
&= ~PU_ASYNCFD
;
201 pu
->pu_state
|= PU_ASYNCFD
;
206 #endif /* !defined(__minix) */
209 puffs_getstate(struct puffs_usermount
*pu
)
212 return pu
->pu_state
& PU_STATEMASK
;
216 puffs_setstacksize(struct puffs_usermount
*pu
, size_t ss
)
222 assert(puffs_getstate(pu
) == PUFFS_STATE_BEFOREMOUNT
);
224 psize
= sysconf(_SC_PAGESIZE
);
226 if (ss
< (size_t)minsize
|| ss
== PUFFS_STACKSIZE_MIN
) {
227 if (ss
!= PUFFS_STACKSIZE_MIN
)
228 #if !defined(__minix)
229 warnx("%s: adjusting " "stacksize to minimum %ld",
231 #endif /* !defined(__minix) */
245 #if !defined(__minix)
246 warnx("%s: using next power of two: %d", __func__
,
248 #endif /* !defined(__minix) */
251 pu
->pu_cc_stackshift
= stackshift
;
254 struct puffs_pathobj
*
255 puffs_getrootpathobj(struct puffs_usermount
*pu
)
257 struct puffs_node
*pnr
;
259 pnr
= pu
->pu_pn_root
;
269 puffs_setroot(struct puffs_usermount
*pu
, struct puffs_node
*pn
)
276 puffs_getroot(struct puffs_usermount
*pu
)
279 return pu
->pu_pn_root
;
283 puffs_setrootinfo(struct puffs_usermount
*pu
, enum vtype vt
,
284 vsize_t vsize
, dev_t rdev
)
286 struct puffs_kargs
*pargs
= pu
->pu_kargp
;
288 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
) {
289 warnx("%s: call has effect only before mount", __func__
);
293 pargs
->pa_root_vtype
= vt
;
294 pargs
->pa_root_vsize
= vsize
;
295 pargs
->pa_root_rdev
= rdev
;
299 puffs_getspecific(struct puffs_usermount
*pu
)
302 return pu
->pu_privdata
;
306 puffs_setspecific(struct puffs_usermount
*pu
, void *privdata
)
309 pu
->pu_privdata
= privdata
;
313 puffs_setmntinfo(struct puffs_usermount
*pu
,
314 const char *mntfromname
, const char *puffsname
)
316 struct puffs_kargs
*pargs
= pu
->pu_kargp
;
318 (void)strlcpy(pargs
->pa_mntfromname
, mntfromname
,
319 sizeof(pargs
->pa_mntfromname
));
320 (void)strlcpy(pargs
->pa_typename
, puffsname
,
321 sizeof(pargs
->pa_typename
));
325 puffs_getmaxreqlen(struct puffs_usermount
*pu
)
328 return pu
->pu_maxreqlen
;
332 puffs_setmaxreqlen(struct puffs_usermount
*pu
, size_t reqlen
)
335 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
336 warnx("%s: call has effect only before mount", __func__
);
338 pu
->pu_kargp
->pa_maxmsglen
= reqlen
;
342 puffs_setfhsize(struct puffs_usermount
*pu
, size_t fhsize
, int flags
)
345 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
346 warnx("%s: call has effect only before mount", __func__
);
348 pu
->pu_kargp
->pa_fhsize
= fhsize
;
349 pu
->pu_kargp
->pa_fhflags
= flags
;
353 puffs_setncookiehash(struct puffs_usermount
*pu
, int nhash
)
356 if (puffs_getstate(pu
) != PUFFS_STATE_BEFOREMOUNT
)
357 warnx("%s: call has effect only before mount", __func__
);
359 pu
->pu_kargp
->pa_nhashbuckets
= nhash
;
363 puffs_set_pathbuild(struct puffs_usermount
*pu
, pu_pathbuild_fn fn
)
366 pu
->pu_pathbuild
= fn
;
370 puffs_set_pathtransform(struct puffs_usermount
*pu
, pu_pathtransform_fn fn
)
373 pu
->pu_pathtransform
= fn
;
377 puffs_set_pathcmp(struct puffs_usermount
*pu
, pu_pathcmp_fn fn
)
384 puffs_set_pathfree(struct puffs_usermount
*pu
, pu_pathfree_fn fn
)
387 pu
->pu_pathfree
= fn
;
391 puffs_set_namemod(struct puffs_usermount
*pu
, pu_namemod_fn fn
)
398 puffs_set_errnotify(struct puffs_usermount
*pu
, pu_errnotify_fn fn
)
401 pu
->pu_errnotify
= fn
;
405 puffs_set_cmap(struct puffs_usermount
*pu
, pu_cmap_fn fn
)
412 puffs_ml_setloopfn(struct puffs_usermount
*pu
, puffs_ml_loop_fn lfn
)
419 puffs_ml_settimeout(struct puffs_usermount
*pu
, struct timespec
*ts
)
423 pu
->pu_ml_timep
= NULL
;
425 pu
->pu_ml_timeout
= *ts
;
426 pu
->pu_ml_timep
= &pu
->pu_ml_timeout
;
431 puffs_set_prepost(struct puffs_usermount
*pu
,
432 pu_prepost_fn pre
, pu_prepost_fn pst
)
439 #if !defined(__minix)
441 puffs_setback(struct puffs_cc
*pcc
, int whatback
)
443 struct puffs_req
*preq
= puffs__framebuf_getdataptr(pcc
->pcc_pb
);
445 assert(PUFFSOP_OPCLASS(preq
->preq_opclass
) == PUFFSOP_VN
&& (
446 preq
->preq_optype
== PUFFS_VN_OPEN
||
447 preq
->preq_optype
== PUFFS_VN_MMAP
||
448 preq
->preq_optype
== PUFFS_VN_REMOVE
||
449 preq
->preq_optype
== PUFFS_VN_RMDIR
||
450 preq
->preq_optype
== PUFFS_VN_INACTIVE
));
452 preq
->preq_setbacks
|= whatback
& PUFFS_SETBACK_MASK
;
456 puffs_daemon(struct puffs_usermount
*pu
, int nochdir
, int noclose
)
459 int parent
, value
, fd
;
461 if (pipe(pu
->pu_dpipe
) == -1)
474 pu
->pu_state
|= PU_PUFFSDAEMON
;
477 close(pu
->pu_dpipe
[1]);
478 n
= read(pu
->pu_dpipe
[0], &value
, sizeof(int));
480 err(1, "puffs_daemon");
481 if (n
!= sizeof(value
))
482 errx(1, "puffs_daemon got %ld bytes", n
);
485 err(1, "puffs_daemon");
496 fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
499 dup2(fd
, STDIN_FILENO
);
500 dup2(fd
, STDOUT_FILENO
);
501 dup2(fd
, STDERR_FILENO
);
502 if (fd
> STDERR_FILENO
)
509 n
= write(pu
->pu_dpipe
[1], &errno
, sizeof(int));
513 #endif /* !defined(__minix) */
516 shutdaemon(struct puffs_usermount
*pu
, int error
)
518 #if !defined(__minix)
521 n
= write(pu
->pu_dpipe
[1], &error
, sizeof(int));
523 close(pu
->pu_dpipe
[0]);
524 close(pu
->pu_dpipe
[1]);
525 #endif /* !defined(__minix) */
526 pu
->pu_state
&= ~PU_PUFFSDAEMON
;
530 puffs_mount(struct puffs_usermount
*pu
, const char *dir
, int mntflags
,
531 puffs_cookie_t cookie
)
533 #if !defined(__minix)
536 #endif /* !defined(__minix) */
538 pu
->pu_kargp
->pa_root_cookie
= cookie
;
540 #if !defined(__minix)
542 /* kauth doesn't provide this service any longer */
544 mntflags
|= MNT_NOSUID
| MNT_NODEV
;
547 * Undocumented... Well, documented only here.
549 * This is used for imaginative purposes. If the env variable is
550 * set, puffs_mount() doesn't do the regular mount procedure.
551 * Rather, it crams the mount data down the comfd and sets comfd as
552 * the puffs descriptor.
554 * This shouldn't be used unless you can read my mind ( ... or write
555 * it, not to mention execute it, but that's starting to get silly).
557 if ((comfd
= getenv("PUFFS_COMFD")) != NULL
) {
560 if (sscanf(comfd
, "%d", &pu
->pu_fd
) != 1) {
565 /* check that what we got at least resembles an fd */
566 if (fcntl(pu
->pu_fd
, F_GETFL
) == -1) {
571 #define allwrite(buf, len) \
574 al_rv = write(pu->pu_fd, buf, len); \
575 if ((size_t)al_rv != len) { \
581 } while (/*CONSTCOND*/0)
583 allwrite(&len
, sizeof(len
));
585 len
= strlen(pu
->pu_kargp
->pa_mntfromname
)+1;
586 allwrite(&len
, sizeof(len
));
587 allwrite(pu
->pu_kargp
->pa_mntfromname
, len
);
588 allwrite(&mntflags
, sizeof(mntflags
));
589 len
= sizeof(*pu
->pu_kargp
);
590 allwrite(&len
, sizeof(len
));
591 allwrite(pu
->pu_kargp
, sizeof(*pu
->pu_kargp
));
592 allwrite(&pu
->pu_flags
, sizeof(pu
->pu_flags
));
600 if (realpath(dir
, rp
) == NULL
) {
606 dirlen
= strlen(dir
);
607 if (strncmp(dir
, rp
, rplen
) != 0 ||
608 strspn(dir
+ rplen
, "/") != dirlen
- rplen
) {
609 warnx("puffs_mount: \"%s\" is a relative path.", dir
);
610 warnx("puffs_mount: using \"%s\" instead.", rp
);
613 fd
= open(_PATH_PUFFS
, O_RDWR
);
615 warnx("puffs_mount: cannot open %s", _PATH_PUFFS
);
620 warnx("puffs_mount: device fd %d (<= 2), sure this is "
621 "what you want?", fd
);
623 pu
->pu_kargp
->pa_fd
= pu
->pu_fd
= fd
;
624 if ((rv
= mount(MOUNT_PUFFS
, rp
, mntflags
,
625 pu
->pu_kargp
, sizeof(struct puffs_kargs
))) == -1)
629 /* Process the already-received mount request. */
630 if (!lpuffs_pump()) {
631 /* Not mounted? This should never happen.. */
637 #endif /* !defined(__minix) */
639 PU_SETSTATE(pu
, PUFFS_STATE_RUNNING
);
641 #if !defined(__minix)
650 if (pu
->pu_state
& PU_PUFFSDAEMON
)
651 shutdaemon(pu
, sverrno
);
657 #endif /* !defined(__minix) */
660 struct puffs_usermount
*
661 puffs_init(struct puffs_ops
*pops
, const char *mntfromname
,
662 const char *puffsname
, void *priv
, uint32_t pflags
)
664 struct puffs_usermount
*pu
;
665 struct puffs_kargs
*pargs
;
668 if (puffsname
== PUFFS_DEFER
)
670 if (mntfromname
== PUFFS_DEFER
)
672 if (priv
== PUFFS_DEFER
)
675 pu
= malloc(sizeof(struct puffs_usermount
));
678 memset(pu
, 0, sizeof(struct puffs_usermount
));
680 pargs
= pu
->pu_kargp
= malloc(sizeof(struct puffs_kargs
));
683 memset(pargs
, 0, sizeof(struct puffs_kargs
));
685 pargs
->pa_vers
= PUFFSVERSION
;
686 pargs
->pa_flags
= PUFFS_FLAG_KERN(pflags
);
687 fillvnopmask(pops
, pargs
);
688 puffs_setmntinfo(pu
, mntfromname
, puffsname
);
690 puffs_zerostatvfs(&pargs
->pa_svfsb
);
691 pargs
->pa_root_cookie
= NULL
;
692 pargs
->pa_root_vtype
= VDIR
;
693 pargs
->pa_root_vsize
= 0;
694 pargs
->pa_root_rdev
= 0;
695 pargs
->pa_maxmsglen
= 0;
696 if (/*CONSTCOND*/ sizeof(time_t) == 4)
697 pargs
->pa_time32
= 1;
699 pargs
->pa_time32
= 0;
701 pu
->pu_flags
= pflags
;
703 free(pops
); /* XXX */
705 pu
->pu_privdata
= priv
;
706 pu
->pu_cc_stackshift
= PUFFS_CC_STACKSHIFT_DEFAULT
;
707 LIST_INIT(&pu
->pu_pnodelst
);
708 LIST_INIT(&pu
->pu_ios
);
709 LIST_INIT(&pu
->pu_ios_rmlist
);
710 LIST_INIT(&pu
->pu_ccmagazin
);
711 TAILQ_INIT(&pu
->pu_sched
);
713 #if !defined(__minix)
714 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].rfb
= puffs__fsframe_read
;
715 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].wfb
= puffs__fsframe_write
;
716 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].cmpfb
= puffs__fsframe_cmp
;
717 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].gotfb
= puffs__fsframe_gotframe
;
718 pu
->pu_framectrl
[PU_FRAMECTRL_FS
].fdnotfn
= puffs_framev_unmountonclose
;
719 #endif /* !defined(__minix) */
721 /* defaults for some user-settable translation functions */
722 pu
->pu_cmap
= NULL
; /* identity translation */
724 pu
->pu_pathbuild
= puffs_stdpath_buildpath
;
725 pu
->pu_pathfree
= puffs_stdpath_freepath
;
726 pu
->pu_pathcmp
= puffs_stdpath_cmppath
;
727 pu
->pu_pathtransform
= NULL
;
728 pu
->pu_namemod
= NULL
;
730 pu
->pu_errnotify
= puffs_kernerr_log
;
732 PU_SETSTATE(pu
, PUFFS_STATE_BEFOREMOUNT
);
735 /* Do the MINIX3-specific side of the initialization. */
737 #endif /* defined(__minix) */
742 /* can't unmount() from here for obvious reasons */
750 puffs_cancel(struct puffs_usermount
*pu
, int error
)
753 assert(puffs_getstate(pu
) < PUFFS_STATE_RUNNING
);
754 shutdaemon(pu
, error
);
760 puffs_exit(struct puffs_usermount
*pu
, int unused
/* strict compat */)
762 #if !defined(__minix)
763 struct puffs_framebuf
*pb
;
764 struct puffs_req
*preq
;
769 pb
= puffs_framebuf_make();
775 winlen
= sizeof(struct puffs_req
);
776 if (puffs_framebuf_getwindow(pb
, 0, &winp
, &winlen
) == -1) {
778 puffs_framebuf_destroy(pb
);
784 preq
->preq_buflen
= sizeof(struct puffs_req
);
785 preq
->preq_opclass
= PUFFSOP_UNMOUNT
;
786 preq
->preq_id
= puffs__nextreq(pu
);
788 puffs_framev_enqueue_justsend(pu
, puffs_getselectable(pu
), pb
, 1, 0);
790 struct puffs_node
*pn
;
792 lpuffs_debug("puffs_exit\n");
794 while ((pn
= LIST_FIRST(&pu
->pu_pnodelst
)) != NULL
)
797 while ((pn
= LIST_FIRST(&pu
->pu_pnode_removed_lst
)) != NULL
)
801 if (pu
->pu_state
& PU_HASKQ
)
804 #endif /* !defined(__minix) */
809 #if !defined(__minix)
810 /* no sigset_t static intializer */
811 static int sigs
[NSIG
] = { 0, };
812 static int sigcatch
= 0;
815 puffs_unmountonsignal(int sig
, bool sigignore
)
818 if (sig
< 0 || sig
>= (int)NSIG
) {
823 if (signal(sig
, SIG_IGN
) == SIG_ERR
)
832 #endif /* !defined(__minix) */
835 * Actual mainloop. This is called from a context which can block.
836 * It is called either from puffs_mainloop (indirectly, via
837 * puffs_cc_continue() or from puffs_cc_yield()).
840 puffs__theloop(struct puffs_cc
*pcc
)
842 struct puffs_usermount
*pu
= pcc
->pcc_pu
;
843 #if !defined(__minix)
844 struct puffs_framectrl
*pfctrl
;
845 struct puffs_fctrl_io
*fio
;
846 struct kevent
*curev
;
849 #endif /* !defined(__minix) */
851 #if !defined(__minix)
852 while (puffs_getstate(pu
) != PUFFS_STATE_UNMOUNTED
) {
855 #endif /* !defined(__minix) */
858 * Schedule existing requests.
860 while ((pcc
= TAILQ_FIRST(&pu
->pu_sched
)) != NULL
) {
861 TAILQ_REMOVE(&pu
->pu_sched
, pcc
, pcc_schedent
);
868 #if !defined(__minix)
869 /* XXX: can we still do these optimizations? */
872 * Do this here, because:
873 * a) loopfunc might generate some results
874 * b) it's still "after" event handling (except for round 1)
876 if (puffs_req_putput(ppr
) == -1)
878 puffs_req_resetput(ppr
);
880 /* micro optimization: skip kevent syscall if possible */
881 if (pu
->pu_nfds
== 1 && pu
->pu_ml_timep
== NULL
882 && (pu
->pu_state
& PU_ASYNCFD
) == 0) {
884 puffs_framev_input(pu
, pfctrl
, XXX
);
889 /* else: do full processing */
890 /* Don't bother worrying about O(n) for now */
891 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
892 if (fio
->stat
& FIO_WRGONE
)
898 * Try to write out everything to avoid the
899 * need for enabling EVFILT_WRITE. The likely
900 * case is that we can fit everything into the
903 puffs__framev_output(pu
, pfctrl
, fio
);
907 * Build list of which to enable/disable in writecheck.
910 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
911 if (fio
->stat
& FIO_WRGONE
)
914 /* en/disable write checks for kqueue as needed */
915 assert((FIO_EN_WRITE(fio
) && FIO_RM_WRITE(fio
)) == 0);
916 if (FIO_EN_WRITE(fio
)) {
917 EV_SET(&pu
->pu_evs
[nchanges
], fio
->io_fd
,
918 EVFILT_WRITE
, EV_ENABLE
, 0, 0,
923 if (FIO_RM_WRITE(fio
)) {
924 EV_SET(&pu
->pu_evs
[nchanges
], fio
->io_fd
,
925 EVFILT_WRITE
, EV_DISABLE
, 0, 0,
927 fio
->stat
&= ~FIO_WR
;
932 ndone
= kevent(pu
->pu_kq
, pu
->pu_evs
, nchanges
,
933 pu
->pu_evs
, pu
->pu_nevs
, pu
->pu_ml_timep
);
946 /* iterate over the results */
947 for (curev
= pu
->pu_evs
; ndone
--; curev
++) {
951 /* get & possibly dispatch events from kernel */
952 if (curev
->ident
== puffsfd
) {
953 if (puffs_req_handle(pgr
, ppr
, 0) == -1)
959 fio
= (void *)curev
->udata
;
960 if (__predict_true(fio
))
964 if (curev
->flags
& EV_ERROR
) {
965 assert(curev
->filter
== EVFILT_WRITE
);
966 fio
->stat
&= ~FIO_WR
;
968 /* XXX: how to know if it's a transient error */
969 puffs__framev_writeclose(pu
, fio
,
971 puffs__framev_notify(fio
, PUFFS_FBIO_ERROR
);
976 if (curev
->filter
== EVFILT_READ
) {
977 puffs__framev_input(pu
, pfctrl
, fio
);
978 what
|= PUFFS_FBIO_READ
;
981 else if (curev
->filter
== EVFILT_WRITE
) {
982 puffs__framev_output(pu
, pfctrl
, fio
);
983 what
|= PUFFS_FBIO_WRITE
;
986 else if (__predict_false(curev
->filter
==EVFILT_SIGNAL
)){
987 if ((pu
->pu_state
& PU_DONEXIT
) == 0) {
988 PU_SETSFLAG(pu
, PU_DONEXIT
);
993 puffs__framev_notify(fio
, what
);
997 * Really free fd's now that we don't have references
1000 while ((fio
= LIST_FIRST(&pu
->pu_ios_rmlist
)) != NULL
) {
1001 LIST_REMOVE(fio
, fio_entries
);
1004 #endif /* !defined(__minix) */
1006 #if defined(__minix)
1007 while (lpuffs_pump());
1008 #endif /* defined(__minix) */
1010 if (puffs__cc_restoremain(pu
) == -1)
1011 warn("cannot restore main context. impending doom");
1014 puffs_mainloop(struct puffs_usermount
*pu
)
1016 #if !defined(__minix)
1017 struct puffs_fctrl_io
*fio
;
1018 #endif /* !defined(__minix) */
1019 struct puffs_cc
*pcc
;
1020 #if !defined(__minix)
1021 struct kevent
*curev
;
1026 #endif /* !defined(__minix) */
1028 assert(puffs_getstate(pu
) >= PUFFS_STATE_RUNNING
);
1030 #if !defined(__minix)
1031 pu
->pu_kq
= kqueue();
1032 if (pu
->pu_kq
== -1)
1034 #endif /* !defined(__minix) */
1035 pu
->pu_state
|= PU_HASKQ
;
1037 #if !defined(__minix)
1038 puffs_setblockingmode(pu
, PUFFSDEV_NONBLOCK
);
1039 if (puffs__framev_addfd_ctrl(pu
, puffs_getselectable(pu
),
1040 PUFFS_FBIO_READ
| PUFFS_FBIO_WRITE
,
1041 &pu
->pu_framectrl
[PU_FRAMECTRL_FS
]) == -1)
1044 nevs
= pu
->pu_nevs
+ sigcatch
;
1045 curev
= realloc(pu
->pu_evs
, nevs
* sizeof(struct kevent
));
1051 LIST_FOREACH(fio
, &pu
->pu_ios
, fio_entries
) {
1052 EV_SET(curev
, fio
->io_fd
, EVFILT_READ
, EV_ADD
,
1053 0, 0, (uintptr_t)fio
);
1055 EV_SET(curev
, fio
->io_fd
, EVFILT_WRITE
, EV_ADD
| EV_DISABLE
,
1056 0, 0, (uintptr_t)fio
);
1059 for (i
= 0; i
< NSIG
; i
++) {
1061 EV_SET(curev
, i
, EVFILT_SIGNAL
, EV_ADD
| EV_ENABLE
,
1066 assert(curev
- pu
->pu_evs
== (ssize_t
)pu
->pu_nevs
);
1067 if (kevent(pu
->pu_kq
, pu
->pu_evs
, pu
->pu_nevs
, NULL
, 0, NULL
) == -1)
1069 #endif /* !defined(__minix) */
1071 pu
->pu_state
|= PU_INLOOP
;
1074 * Create alternate execution context and jump to it. Note
1075 * that we come "out" of savemain twice. Where we come out
1076 * of it depends on the architecture. If the return address is
1077 * stored on the stack, we jump out from puffs_cc_continue(),
1078 * for a register return address from puffs__cc_savemain().
1079 * PU_MAINRESTORE makes sure we DTRT in both cases.
1081 if (puffs__cc_create(pu
, puffs__theloop
, &pcc
) == -1) {
1086 if (puffs__cc_savemain(pu
) == -1) {
1092 * puffs__cc_savemain() uses getcontext() and then returns.
1093 * the caller (this function) may overwrite the stack frame
1094 * of puffs__cc_savemain(), so when we call setcontext() later and
1095 * return from puffs__cc_savemain() again, the return address or
1096 * saved stack pointer can be garbage.
1097 * avoid this by calling getcontext() directly here.
1099 extern int puffs_fakecc
;
1100 if (!puffs_fakecc
) {
1101 PU_CLRSFLAG(pu
, PU_MAINRESTORE
);
1102 if (getcontext(&pu
->pu_mainctx
) == -1) {
1108 if ((pu
->pu_state
& PU_MAINRESTORE
) == 0)
1109 puffs_cc_continue(pcc
);
1115 /* store the real error for a while */