xref: /minix3/lib/libpuffs/puffs.c (revision b1c4ba4ab66acbca4eb1bab1b49a15e96feef93e)
1 /*	$NetBSD: puffs.c,v 1.92.4.4 2009/10/27 20:37:38 bouyer 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 /* TODO: We don't support PUFFS_COMFD used in original puffs_mount,
33  * add it to the docs if any.
34  *
35  */
36 
37 #include "fs.h"
38 #include <sys/cdefs.h>
39 #if !defined(lint)
40 __RCSID("$NetBSD: puffs.c,v 1.92.4.4 2009/10/27 20:37:38 bouyer Exp $");
41 #endif /* !lint */
42 
43 #include <sys/param.h>
44 #include <sys/mount.h>
45 
46 #include <minix/endpoint.h>
47 #include <minix/vfsif.h>
48 
49 #include <assert.h>
50 #include <err.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <paths.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <syslog.h>
58 #include <unistd.h>
59 
60 #include "puffs.h"
61 #include "puffs_priv.h"
62 
63 #ifdef PUFFS_WITH_THREADS
64 #include <pthread.h>
65 pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER;
66 #endif
67 
68 
69 /* Declare some local functions. */
70 static void get_work(message *m_in);
71 static void reply(endpoint_t who, message *m_out);
72 
73 /* SEF functions and variables. */
74 static void sef_local_startup(void);
75 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
76 static void sef_cb_signal_handler(int signo);
77 
78 EXTERN int env_argc;
79 EXTERN char **env_argv;
80 
81 
82 #define PUFFS_MAX_ARGS 20
83 
84 int __real_main(int argc, char* argv[]);
85 int __wrap_main(int argc, char* argv[]);
86 
87 int __wrap_main(int argc, char *argv[])
88 {
89   int i;
90   int new_argc = 0;
91   static char* new_argv[PUFFS_MAX_ARGS];
92   char *name;
93 
94   /* SEF local startup. */
95   env_setargs(argc, argv);
96   sef_local_startup();
97 
98   global_kcred.pkcr_type = PUFFCRED_TYPE_INTERNAL;
99 
100   if (argc < 3) {
101 	panic("Unexpected arguments, use:\
102 		mount -t fs /dev/ /dir [-o option1,option2]\n");
103   }
104 
105   name = argv[0] + strlen(argv[0]);
106   while (*name != '/' && name != argv[0])
107 	  name--;
108   if (name != argv[0])
109 	  name++;
110   strcpy(fs_name, name);
111 
112   new_argv[new_argc] = argv[0];
113   new_argc++;
114 
115   for (i = 1; i < argc; i++) {
116 	if (new_argc >= PUFFS_MAX_ARGS) {
117 		panic("Too many arguments, change PUFFS_MAX_ARGS");
118 	}
119 	new_argv[new_argc] = argv[i];
120 	new_argc++;
121   }
122 
123   assert(new_argc > 0);
124 
125   get_work(&fs_m_in);
126 
127   return __real_main(new_argc, new_argv);
128 }
129 
130 
131 #define FILLOP(lower, upper)						\
132 do {									\
133 	if (pops->puffs_node_##lower)					\
134 		opmask[PUFFS_VN_##upper] = 1;				\
135 } while (/*CONSTCOND*/0)
136 static void
137 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
138 {
139 
140 	memset(opmask, 0, PUFFS_VN_MAX);
141 
142 	FILLOP(create,   CREATE);
143 	FILLOP(mknod,    MKNOD);
144 	FILLOP(open,     OPEN);
145 	FILLOP(close,    CLOSE);
146 	FILLOP(access,   ACCESS);
147 	FILLOP(getattr,  GETATTR);
148 	FILLOP(setattr,  SETATTR);
149 	FILLOP(poll,     POLL); /* XXX: not ready in kernel */
150 	FILLOP(mmap,     MMAP);
151 	FILLOP(fsync,    FSYNC);
152 	FILLOP(seek,     SEEK);
153 	FILLOP(remove,   REMOVE);
154 	FILLOP(link,     LINK);
155 	FILLOP(rename,   RENAME);
156 	FILLOP(mkdir,    MKDIR);
157 	FILLOP(rmdir,    RMDIR);
158 	FILLOP(symlink,  SYMLINK);
159 	FILLOP(readdir,  READDIR);
160 	FILLOP(readlink, READLINK);
161 	FILLOP(reclaim,  RECLAIM);
162 	FILLOP(inactive, INACTIVE);
163 	FILLOP(print,    PRINT);
164 	FILLOP(read,     READ);
165 	FILLOP(write,    WRITE);
166 	FILLOP(abortop,  ABORTOP);
167 }
168 #undef FILLOP
169 
170 
171 /*ARGSUSED*/
172 static void
173 puffs_defaulterror(struct puffs_usermount *pu, uint8_t type,
174 	int error, const char *str, puffs_cookie_t cookie)
175 {
176 
177 	lpuffs_debug("abort: type %d, error %d, cookie %p (%s)\n",
178 	    type, error, cookie, str);
179 	abort();
180 }
181 
182 
183 int
184 puffs_getstate(struct puffs_usermount *pu)
185 {
186 
187 	return pu->pu_state & PU_STATEMASK;
188 }
189 
190 void
191 puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
192 {
193 	long psize, minsize;
194 	int stackshift;
195 	int bonus;
196 
197 	assert(puffs_getstate(pu) == PUFFS_STATE_BEFOREMOUNT);
198 
199 	psize = sysconf(_SC_PAGESIZE);
200 	minsize = 4*psize;
201 	if (ss < minsize || ss == PUFFS_STACKSIZE_MIN) {
202 		if (ss != PUFFS_STACKSIZE_MIN)
203 			lpuffs_debug("puffs_setstacksize: adjusting "
204 			    "stacksize to minimum %ld\n", minsize);
205 		ss = 4*psize;
206 	}
207 
208 	stackshift = -1;
209 	bonus = 0;
210 	while (ss) {
211 		if (ss & 0x1)
212 			bonus++;
213 		ss >>= 1;
214 		stackshift++;
215 	}
216 	if (bonus > 1) {
217 		stackshift++;
218 		lpuffs_debug("puffs_setstacksize: using next power of two: "
219 		    "%d\n", 1<<stackshift);
220 	}
221 
222 	pu->pu_cc_stackshift = stackshift;
223 }
224 
225 struct puffs_pathobj *
226 puffs_getrootpathobj(struct puffs_usermount *pu)
227 {
228 	struct puffs_node *pnr;
229 
230 	pnr = pu->pu_pn_root;
231 	if (pnr == NULL) {
232 		errno = ENOENT;
233 		return NULL;
234 	}
235 
236 	return &pnr->pn_po;
237 }
238 
239 void
240 puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn)
241 {
242 
243 	pu->pu_pn_root = pn;
244 }
245 
246 struct puffs_node *
247 puffs_getroot(struct puffs_usermount *pu)
248 {
249 
250 	return pu->pu_pn_root;
251 }
252 
253 void
254 puffs_setrootinfo(struct puffs_usermount *pu, enum vtype vt,
255 	vsize_t vsize, dev_t rdev)
256 {
257 	struct puffs_kargs *pargs = pu->pu_kargp;
258 
259 	if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) {
260 		warnx("puffs_setrootinfo: call has effect only "
261 		    "before mount\n");
262 		return;
263 	}
264 
265 	pargs->pa_root_vtype = vt;
266 	pargs->pa_root_vsize = vsize;
267 	pargs->pa_root_rdev = rdev;
268 }
269 
270 void *
271 puffs_getspecific(struct puffs_usermount *pu)
272 {
273 
274 	return pu->pu_privdata;
275 }
276 
277 void
278 puffs_setspecific(struct puffs_usermount *pu, void *privdata)
279 {
280 
281 	pu->pu_privdata = privdata;
282 }
283 
284 void
285 puffs_setmntinfo(struct puffs_usermount *pu,
286 	const char *mntfromname, const char *puffsname)
287 {
288 	struct puffs_kargs *pargs = pu->pu_kargp;
289 
290 	(void)strlcpy(pargs->pa_mntfromname, mntfromname,
291 	    sizeof(pargs->pa_mntfromname));
292 	(void)strlcpy(pargs->pa_typename, puffsname,
293 	    sizeof(pargs->pa_typename));
294 }
295 
296 size_t
297 puffs_getmaxreqlen(struct puffs_usermount *pu)
298 {
299 
300 	return pu->pu_maxreqlen;
301 }
302 
303 void
304 puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen)
305 {
306 
307 	if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
308 		warnx("puffs_setmaxreqlen: call has effect only "
309 		    "before mount\n");
310 
311 	pu->pu_kargp->pa_maxmsglen = reqlen;
312 }
313 
314 void
315 puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags)
316 {
317 
318 	if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
319 		warnx("puffs_setfhsize: call has effect only before mount\n");
320 
321 	pu->pu_kargp->pa_fhsize = fhsize;
322 	pu->pu_kargp->pa_fhflags = flags;
323 }
324 
325 void
326 puffs_setncookiehash(struct puffs_usermount *pu, int nhash)
327 {
328 
329 	if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
330 		warnx("puffs_setfhsize: call has effect only before mount\n");
331 
332 	pu->pu_kargp->pa_nhashbuckets = nhash;
333 }
334 
335 void
336 puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
337 {
338 
339 	pu->pu_pathbuild = fn;
340 }
341 
342 void
343 puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
344 {
345 
346 	pu->pu_pathtransform = fn;
347 }
348 
349 void
350 puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
351 {
352 
353 	pu->pu_pathcmp = fn;
354 }
355 
356 void
357 puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
358 {
359 
360 	pu->pu_pathfree = fn;
361 }
362 
363 void
364 puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
365 {
366 
367 	pu->pu_namemod = fn;
368 }
369 
370 void
371 puffs_set_errnotify(struct puffs_usermount *pu, pu_errnotify_fn fn)
372 {
373 
374 	pu->pu_errnotify = fn;
375 }
376 
377 void
378 puffs_set_cmap(struct puffs_usermount *pu, pu_cmap_fn fn)
379 {
380 
381 	pu->pu_cmap = fn;
382 }
383 
384 void
385 puffs_ml_setloopfn(struct puffs_usermount *pu, puffs_ml_loop_fn lfn)
386 {
387 
388 	pu->pu_ml_lfn = lfn;
389 }
390 
391 void
392 puffs_ml_settimeout(struct puffs_usermount *pu, struct timespec *ts)
393 {
394 
395 	if (ts == NULL) {
396 		pu->pu_ml_timep = NULL;
397 	} else {
398 		pu->pu_ml_timeout = *ts;
399 		pu->pu_ml_timep = &pu->pu_ml_timeout;
400 	}
401 }
402 
403 void
404 puffs_set_prepost(struct puffs_usermount *pu,
405 	pu_prepost_fn pre, pu_prepost_fn pst)
406 {
407 
408 	pu->pu_oppre = pre;
409 	pu->pu_oppost = pst;
410 }
411 
412 int
413 puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags,
414 	puffs_cookie_t cookie)
415 {
416         endpoint_t src;
417         int error, ind;
418 
419         pu->pu_kargp->pa_root_cookie = cookie;
420 
421         src = fs_m_in.m_source;
422         error = OK;
423         caller_uid = INVAL_UID; /* To trap errors */
424         caller_gid = INVAL_GID;
425         req_nr = fs_m_in.m_type;
426 
427         if (req_nr < VFS_BASE) {
428                 fs_m_in.m_type += VFS_BASE;
429                 req_nr = fs_m_in.m_type;
430         }
431         ind = req_nr - VFS_BASE;
432 
433         assert(ind == REQ_READ_SUPER);
434 
435         if (ind < 0 || ind >= NREQS) {
436                 error = EINVAL;
437         } else {
438                 error = (*fs_call_vec[ind])();
439         }
440 
441         fs_m_out.m_type = error;
442 	if (IS_VFS_FS_TRANSID(last_request_transid)) {
443 		/* If a transaction ID was set, reset it */
444 		fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type,
445 					      last_request_transid);
446 	}
447         reply(src, &fs_m_out);
448 
449         if (error) {
450                 free(pu->pu_kargp);
451                 pu->pu_kargp = NULL;
452                 errno = error;
453                 return -1;
454         }
455 
456         PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
457         return 0;
458 }
459 
460 /*ARGSUSED*/
461 struct puffs_usermount *
462 _puffs_init(int dummy, struct puffs_ops *pops, const char *mntfromname,
463 	const char *puffsname, void *priv, uint32_t pflags)
464 {
465 	struct puffs_usermount *pu;
466 	struct puffs_kargs *pargs;
467 	int sverrno;
468 
469 	if (puffsname == PUFFS_DEFER)
470 		puffsname = "n/a";
471 	if (mntfromname == PUFFS_DEFER)
472 		mntfromname = "n/a";
473 	if (priv == PUFFS_DEFER)
474 		priv = NULL;
475 
476 	pu = malloc(sizeof(struct puffs_usermount));
477 	if (pu == NULL)
478 		goto failfree;
479 	memset(pu, 0, sizeof(struct puffs_usermount));
480 
481 	pargs = pu->pu_kargp = malloc(sizeof(struct puffs_kargs));
482 	if (pargs == NULL)
483 		goto failfree;
484 	memset(pargs, 0, sizeof(struct puffs_kargs));
485 
486 	pargs->pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
487 	pargs->pa_flags = PUFFS_FLAG_KERN(pflags);
488 	fillvnopmask(pops, pargs->pa_vnopmask);
489 	puffs_setmntinfo(pu, mntfromname, puffsname);
490 
491 	puffs_zerostatvfs(&pargs->pa_svfsb);
492 	pargs->pa_root_cookie = NULL;
493 	pargs->pa_root_vtype = VDIR;
494 	pargs->pa_root_vsize = 0;
495 	pargs->pa_root_rdev = 0;
496 	pargs->pa_maxmsglen = 0;
497 
498 	pu->pu_flags = pflags;
499 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH; /* XXX */
500 	pu->pu_ops = *pops;
501 	free(pops); /* XXX */
502 
503 	pu->pu_privdata = priv;
504 	pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT;
505 	LIST_INIT(&pu->pu_pnodelst);
506 	LIST_INIT(&pu->pu_pnode_removed_lst);
507 	LIST_INIT(&pu->pu_ios);
508 	LIST_INIT(&pu->pu_ios_rmlist);
509 	LIST_INIT(&pu->pu_ccmagazin);
510 	TAILQ_INIT(&pu->pu_sched);
511 
512 	/* defaults for some user-settable translation functions */
513 	pu->pu_cmap = NULL; /* identity translation */
514 
515         pu->pu_pathbuild = puffs_stdpath_buildpath;
516         pu->pu_pathfree = puffs_stdpath_freepath;
517         pu->pu_pathcmp = puffs_stdpath_cmppath;
518         pu->pu_pathtransform = NULL;
519         pu->pu_namemod = NULL;
520 
521         pu->pu_errnotify = puffs_defaulterror;
522 
523 	PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT);
524 
525 	global_pu = pu;
526 
527 	return pu;
528 
529  failfree:
530 	/* can't unmount() from here for obvious reasons */
531 	sverrno = errno;
532 	free(pu);
533 	errno = sverrno;
534 	return NULL;
535 }
536 
537 void
538 puffs_cancel(struct puffs_usermount *pu, int error)
539 {
540 	assert(puffs_getstate(pu) < PUFFS_STATE_RUNNING);
541 	free(pu);
542 }
543 
544 /*ARGSUSED1*/
545 int
546 puffs_exit(struct puffs_usermount *pu, int force)
547 {
548 	struct puffs_node *pn;
549 
550         lpuffs_debug("puffs_exit\n");
551 
552 	while ((pn = LIST_FIRST(&pu->pu_pnodelst)) != NULL)
553 		puffs_pn_put(pn);
554 
555 	while ((pn = LIST_FIRST(&pu->pu_pnode_removed_lst)) != NULL)
556 		puffs_pn_put(pn);
557 
558 	puffs__cc_exit(pu);
559 	if (pu->pu_state & PU_HASKQ)
560 		close(pu->pu_kq);
561 	free(pu);
562 
563 	return 0; /* always succesful for now, WILL CHANGE */
564 }
565 
566 /*
567  * Actual mainloop.  This is called from a context which can block.
568  * It is called either from puffs_mainloop (indirectly, via
569  * puffs_cc_continue() or from puffs_cc_yield()).
570  */
571 void
572 puffs__theloop(struct puffs_cc *pcc)
573 {
574 	struct puffs_usermount *pu = pcc->pcc_pu;
575 	int error, ind;
576 
577 	while (!unmountdone || !exitsignaled) {
578 		endpoint_t src;
579 
580 		/*
581 		 * Schedule existing requests.
582 		 */
583 		while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) {
584 			lpuffs_debug("scheduling existing tasks\n");
585 			TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent);
586 			puffs__goto(pcc);
587 		}
588 
589 		if (pu->pu_ml_lfn) {
590                         lpuffs_debug("Calling user mainloop handler\n");
591 			pu->pu_ml_lfn(pu);
592 		}
593 
594 		/* Wait for request message. */
595 		get_work(&fs_m_in);
596 
597 		src = fs_m_in.m_source;
598 		error = OK;
599 		caller_uid = INVAL_UID; /* To trap errors */
600 		caller_gid = INVAL_GID;
601 		req_nr = fs_m_in.m_type;
602 
603 		if (req_nr < VFS_BASE) {
604 			fs_m_in.m_type += VFS_BASE;
605 			req_nr = fs_m_in.m_type;
606 		}
607 		ind = req_nr - VFS_BASE;
608 
609 		if (ind < 0 || ind >= NREQS) {
610 			error = EINVAL;
611 		} else {
612 			error = (*fs_call_vec[ind])();
613 		}
614 
615 		fs_m_out.m_type = error;
616 		if (IS_VFS_FS_TRANSID(last_request_transid)) {
617 			/* If a transaction ID was set, reset it */
618 			fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type, last_request_transid);
619 		}
620 		reply(src, &fs_m_out);
621 	}
622 
623 	if (puffs__cc_restoremain(pu) == -1)
624 		warn("cannot restore main context.  impending doom");
625 
626 	/* May get here, if puffs_fakecc is set to 1. Currently librefuse sets it.
627 	 * Now we just return to the caller.
628 	 */
629 }
630 
631 int
632 puffs_mainloop(struct puffs_usermount *pu)
633 {
634 	struct puffs_cc *pcc;
635 	int sverrno;
636 
637 	assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
638 
639 	pu->pu_state |= PU_HASKQ | PU_INLOOP;
640 
641 	/*
642 	 * Create alternate execution context and jump to it.  Note
643 	 * that we come "out" of savemain twice.  Where we come out
644 	 * of it depends on the architecture.  If the return address is
645 	 * stored on the stack, we jump out from puffs_cc_continue(),
646 	 * for a register return address from puffs__cc_savemain().
647 	 * PU_MAINRESTORE makes sure we DTRT in both cases.
648 	 */
649 	if (puffs__cc_create(pu, puffs__theloop, &pcc) == -1) {
650 		goto out;
651 	}
652 	if (puffs__cc_savemain(pu) == -1) {
653 		goto out;
654 	}
655 	if ((pu->pu_state & PU_MAINRESTORE) == 0)
656 		puffs_cc_continue(pcc);
657 
658 	errno = 0;
659 
660  out:
661 	/* store the real error for a while */
662 	sverrno = errno;
663 
664 	errno = sverrno;
665 	if (errno)
666 		return -1;
667 	else
668 		return 0;
669 }
670 
671 
672 /*===========================================================================*
673  *			       sef_local_startup			     *
674  *===========================================================================*/
675 static void sef_local_startup()
676 {
677   /* Register init callbacks. */
678   sef_setcb_init_fresh(sef_cb_init_fresh);
679   sef_setcb_init_restart(sef_cb_init_fail);
680 
681   /* No live update support for now. */
682 
683   /* Register signal callbacks. */
684   sef_setcb_signal_handler(sef_cb_signal_handler);
685 
686   /* Let SEF perform startup. */
687   sef_startup();
688 }
689 
690 /*===========================================================================*
691  *		            sef_cb_init_fresh                                *
692  *===========================================================================*/
693 static int sef_cb_init_fresh(int type, sef_init_info_t *info)
694 {
695 /* Initialize the Minix file server. */
696   SELF_E = getprocnr();
697   return(OK);
698 }
699 
700 /*===========================================================================*
701  *		           sef_cb_signal_handler                             *
702  *===========================================================================*/
703 static void sef_cb_signal_handler(int signo)
704 {
705   /* Only check for termination signal, ignore anything else. */
706   if (signo != SIGTERM) return;
707 
708   exitsignaled = 1;
709   fs_sync();
710 
711   /* If unmounting has already been performed, exit immediately.
712    * We might not get another message.
713    */
714   if (unmountdone) {
715         if (puffs__cc_restoremain(global_pu) == -1)
716                 warn("cannot restore main context.  impending doom");
717 	/* May happen if puffs_fakecc is set to 1. Currently librefuse sets it.
718 	 * There is a chance, that main loop hangs in receive() and we will
719 	 * never get any new message, so we have to exit() here.
720 	 */
721 	exit(0);
722   }
723 }
724 
725 /*===========================================================================*
726  *				get_work				     *
727  *===========================================================================*/
728 static void get_work(m_in)
729 message *m_in;				/* pointer to message */
730 {
731   int r, srcok = 0;
732   endpoint_t src;
733 
734   do {
735 	if ((r = sef_receive(ANY, m_in)) != OK) 	/* wait for message */
736 		panic("sef_receive failed: %d", r);
737 	src = m_in->m_source;
738 
739 	if(src == VFS_PROC_NR) {
740 		if(unmountdone)
741 			lpuffs_debug("libpuffs: unmounted: unexpected message from FS\n");
742 		else
743 			srcok = 1;		/* Normal FS request. */
744 
745 	} else
746 		lpuffs_debug("libpuffs: unexpected source %d\n", src);
747   } while(!srcok);
748 
749   assert((src == VFS_PROC_NR && !unmountdone));
750 
751   last_request_transid = TRNS_GET_ID(fs_m_in.m_type);
752   fs_m_in.m_type = TRNS_DEL_ID(fs_m_in.m_type);
753   if (fs_m_in.m_type == 0) {
754 	  assert(!IS_VFS_FS_TRANSID(last_request_transid));
755 	  fs_m_in.m_type = last_request_transid;  /* Backwards compat. */
756 	  last_request_transid = 0;
757   } else
758 	  assert(IS_VFS_FS_TRANSID(last_request_transid));
759 }
760 
761 
762 /*===========================================================================*
763  *				reply					     *
764  *===========================================================================*/
765 static void reply(
766   endpoint_t who,
767   message *m_out                       	/* report result */
768 )
769 {
770   if (OK != send(who, m_out))    /* send the message */
771 	lpuffs_debug("libpuffs(%d) was unable to send reply\n", SELF_E);
772 
773   last_request_transid = 0;
774 }
775 
776