xref: /minix/lib/libpuffs/puffs.c (revision a06e2ab3)
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 __dead 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 	size_t minsize;
194 	int psize;
195 	int stackshift;
196 	int bonus;
197 
198 	assert(puffs_getstate(pu) == PUFFS_STATE_BEFOREMOUNT);
199 
200 	psize = sysconf(_SC_PAGESIZE);
201 	minsize = 4*psize;
202 	if (ss < minsize || ss == PUFFS_STACKSIZE_MIN) {
203 		if (ss != PUFFS_STACKSIZE_MIN)
204 			lpuffs_debug("puffs_setstacksize: adjusting "
205 			    "stacksize to minimum %ld\n", minsize);
206 		ss = 4*psize;
207 	}
208 
209 	stackshift = -1;
210 	bonus = 0;
211 	while (ss) {
212 		if (ss & 0x1)
213 			bonus++;
214 		ss >>= 1;
215 		stackshift++;
216 	}
217 	if (bonus > 1) {
218 		stackshift++;
219 		lpuffs_debug("puffs_setstacksize: using next power of two: "
220 		    "%d\n", 1<<stackshift);
221 	}
222 
223 	pu->pu_cc_stackshift = stackshift;
224 }
225 
226 struct puffs_pathobj *
227 puffs_getrootpathobj(struct puffs_usermount *pu)
228 {
229 	struct puffs_node *pnr;
230 
231 	pnr = pu->pu_pn_root;
232 	if (pnr == NULL) {
233 		errno = ENOENT;
234 		return NULL;
235 	}
236 
237 	return &pnr->pn_po;
238 }
239 
240 void
241 puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn)
242 {
243 
244 	pu->pu_pn_root = pn;
245 }
246 
247 struct puffs_node *
248 puffs_getroot(struct puffs_usermount *pu)
249 {
250 
251 	return pu->pu_pn_root;
252 }
253 
254 void
255 puffs_setrootinfo(struct puffs_usermount *pu, enum vtype vt,
256 	vsize_t vsize, dev_t rdev)
257 {
258 	struct puffs_kargs *pargs = pu->pu_kargp;
259 
260 	if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) {
261 		warnx("puffs_setrootinfo: call has effect only "
262 		    "before mount\n");
263 		return;
264 	}
265 
266 	pargs->pa_root_vtype = vt;
267 	pargs->pa_root_vsize = vsize;
268 	pargs->pa_root_rdev = rdev;
269 }
270 
271 void *
272 puffs_getspecific(struct puffs_usermount *pu)
273 {
274 
275 	return pu->pu_privdata;
276 }
277 
278 void
279 puffs_setspecific(struct puffs_usermount *pu, void *privdata)
280 {
281 
282 	pu->pu_privdata = privdata;
283 }
284 
285 void
286 puffs_setmntinfo(struct puffs_usermount *pu,
287 	const char *mntfromname, const char *puffsname)
288 {
289 	struct puffs_kargs *pargs = pu->pu_kargp;
290 
291 	(void)strlcpy(pargs->pa_mntfromname, mntfromname,
292 	    sizeof(pargs->pa_mntfromname));
293 	(void)strlcpy(pargs->pa_typename, puffsname,
294 	    sizeof(pargs->pa_typename));
295 }
296 
297 size_t
298 puffs_getmaxreqlen(struct puffs_usermount *pu)
299 {
300 
301 	return pu->pu_maxreqlen;
302 }
303 
304 void
305 puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen)
306 {
307 
308 	if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
309 		warnx("puffs_setmaxreqlen: call has effect only "
310 		    "before mount\n");
311 
312 	pu->pu_kargp->pa_maxmsglen = reqlen;
313 }
314 
315 void
316 puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags)
317 {
318 
319 	if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
320 		warnx("puffs_setfhsize: call has effect only before mount\n");
321 
322 	pu->pu_kargp->pa_fhsize = fhsize;
323 	pu->pu_kargp->pa_fhflags = flags;
324 }
325 
326 void
327 puffs_setncookiehash(struct puffs_usermount *pu, int nhash)
328 {
329 
330 	if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
331 		warnx("puffs_setfhsize: call has effect only before mount\n");
332 
333 	pu->pu_kargp->pa_nhashbuckets = nhash;
334 }
335 
336 void
337 puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
338 {
339 
340 	pu->pu_pathbuild = fn;
341 }
342 
343 void
344 puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
345 {
346 
347 	pu->pu_pathtransform = fn;
348 }
349 
350 void
351 puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
352 {
353 
354 	pu->pu_pathcmp = fn;
355 }
356 
357 void
358 puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
359 {
360 
361 	pu->pu_pathfree = fn;
362 }
363 
364 void
365 puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
366 {
367 
368 	pu->pu_namemod = fn;
369 }
370 
371 void
372 puffs_set_errnotify(struct puffs_usermount *pu, pu_errnotify_fn fn)
373 {
374 
375 	pu->pu_errnotify = fn;
376 }
377 
378 void
379 puffs_set_cmap(struct puffs_usermount *pu, pu_cmap_fn fn)
380 {
381 
382 	pu->pu_cmap = fn;
383 }
384 
385 void
386 puffs_ml_setloopfn(struct puffs_usermount *pu, puffs_ml_loop_fn lfn)
387 {
388 
389 	pu->pu_ml_lfn = lfn;
390 }
391 
392 void
393 puffs_ml_settimeout(struct puffs_usermount *pu, struct timespec *ts)
394 {
395 
396 	if (ts == NULL) {
397 		pu->pu_ml_timep = NULL;
398 	} else {
399 		pu->pu_ml_timeout = *ts;
400 		pu->pu_ml_timep = &pu->pu_ml_timeout;
401 	}
402 }
403 
404 void
405 puffs_set_prepost(struct puffs_usermount *pu,
406 	pu_prepost_fn pre, pu_prepost_fn pst)
407 {
408 
409 	pu->pu_oppre = pre;
410 	pu->pu_oppost = pst;
411 }
412 
413 int
414 puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags,
415 	puffs_cookie_t cookie)
416 {
417         endpoint_t src;
418         int error, ind;
419 
420         pu->pu_kargp->pa_root_cookie = cookie;
421 
422         src = fs_m_in.m_source;
423         error = OK;
424         caller_uid = INVAL_UID; /* To trap errors */
425         caller_gid = INVAL_GID;
426         req_nr = fs_m_in.m_type;
427 
428         if (req_nr < FS_BASE) {
429                 fs_m_in.m_type += FS_BASE;
430                 req_nr = fs_m_in.m_type;
431         }
432         ind = req_nr - FS_BASE;
433 
434         assert(ind == REQ_READ_SUPER);
435 
436         if (ind < 0 || ind >= NREQS) {
437                 error = EINVAL;
438         } else {
439                 error = (*fs_call_vec[ind])();
440         }
441 
442         fs_m_out.m_type = error;
443 	if (IS_VFS_FS_TRANSID(last_request_transid)) {
444 		/* If a transaction ID was set, reset it */
445 		fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type,
446 					      last_request_transid);
447 	}
448         reply(src, &fs_m_out);
449 
450         if (error) {
451                 free(pu->pu_kargp);
452                 pu->pu_kargp = NULL;
453                 errno = error;
454                 return -1;
455         }
456 
457         PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
458         return 0;
459 }
460 
461 /*ARGSUSED*/
462 struct puffs_usermount *
463 _puffs_init(int dummy, struct puffs_ops *pops, const char *mntfromname,
464 	const char *puffsname, void *priv, uint32_t pflags)
465 {
466 	struct puffs_usermount *pu;
467 	struct puffs_kargs *pargs;
468 	int sverrno;
469 
470 	if (puffsname == PUFFS_DEFER)
471 		puffsname = "n/a";
472 	if (mntfromname == PUFFS_DEFER)
473 		mntfromname = "n/a";
474 	if (priv == PUFFS_DEFER)
475 		priv = NULL;
476 
477 	pu = malloc(sizeof(struct puffs_usermount));
478 	if (pu == NULL)
479 		goto failfree;
480 	memset(pu, 0, sizeof(struct puffs_usermount));
481 
482 	pargs = pu->pu_kargp = malloc(sizeof(struct puffs_kargs));
483 	if (pargs == NULL)
484 		goto failfree;
485 	memset(pargs, 0, sizeof(struct puffs_kargs));
486 
487 	pargs->pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
488 	pargs->pa_flags = PUFFS_FLAG_KERN(pflags);
489 	fillvnopmask(pops, pargs->pa_vnopmask);
490 	puffs_setmntinfo(pu, mntfromname, puffsname);
491 
492 	puffs_zerostatvfs(&pargs->pa_svfsb);
493 	pargs->pa_root_cookie = NULL;
494 	pargs->pa_root_vtype = VDIR;
495 	pargs->pa_root_vsize = 0;
496 	pargs->pa_root_rdev = 0;
497 	pargs->pa_maxmsglen = 0;
498 
499 	pu->pu_flags = pflags;
500 	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH; /* XXX */
501 	pu->pu_ops = *pops;
502 	free(pops); /* XXX */
503 
504 	pu->pu_privdata = priv;
505 	pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT;
506 	LIST_INIT(&pu->pu_pnodelst);
507 	LIST_INIT(&pu->pu_pnode_removed_lst);
508 	LIST_INIT(&pu->pu_ios);
509 	LIST_INIT(&pu->pu_ios_rmlist);
510 	LIST_INIT(&pu->pu_ccmagazin);
511 	TAILQ_INIT(&pu->pu_sched);
512 
513 	/* defaults for some user-settable translation functions */
514 	pu->pu_cmap = NULL; /* identity translation */
515 
516         pu->pu_pathbuild = puffs_stdpath_buildpath;
517         pu->pu_pathfree = puffs_stdpath_freepath;
518         pu->pu_pathcmp = puffs_stdpath_cmppath;
519         pu->pu_pathtransform = NULL;
520         pu->pu_namemod = NULL;
521 
522         pu->pu_errnotify = puffs_defaulterror;
523 
524 	PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT);
525 
526 	global_pu = pu;
527 
528 	return pu;
529 
530  failfree:
531 	/* can't unmount() from here for obvious reasons */
532 	sverrno = errno;
533 	free(pu);
534 	errno = sverrno;
535 	return NULL;
536 }
537 
538 void
539 puffs_cancel(struct puffs_usermount *pu, int error)
540 {
541 	assert(puffs_getstate(pu) < PUFFS_STATE_RUNNING);
542 	free(pu);
543 }
544 
545 /*ARGSUSED1*/
546 int
547 puffs_exit(struct puffs_usermount *pu, int force)
548 {
549 	struct puffs_node *pn;
550 
551         lpuffs_debug("puffs_exit\n");
552 
553 	while ((pn = LIST_FIRST(&pu->pu_pnodelst)) != NULL)
554 		puffs_pn_put(pn);
555 
556 	while ((pn = LIST_FIRST(&pu->pu_pnode_removed_lst)) != NULL)
557 		puffs_pn_put(pn);
558 
559 	puffs__cc_exit(pu);
560 	if (pu->pu_state & PU_HASKQ)
561 		close(pu->pu_kq);
562 	free(pu);
563 
564 	return 0; /* always succesful for now, WILL CHANGE */
565 }
566 
567 /*
568  * Actual mainloop.  This is called from a context which can block.
569  * It is called either from puffs_mainloop (indirectly, via
570  * puffs_cc_continue() or from puffs_cc_yield()).
571  */
572 void
573 puffs__theloop(struct puffs_cc *pcc)
574 {
575 	struct puffs_usermount *pu = pcc->pcc_pu;
576 	int error, ind;
577 
578 	while (!unmountdone || !exitsignaled) {
579 		endpoint_t src;
580 
581 		/*
582 		 * Schedule existing requests.
583 		 */
584 		while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) {
585 			lpuffs_debug("scheduling existing tasks\n");
586 			TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent);
587 			puffs__goto(pcc);
588 		}
589 
590 		if (pu->pu_ml_lfn) {
591                         lpuffs_debug("Calling user mainloop handler\n");
592 			pu->pu_ml_lfn(pu);
593 		}
594 
595 		/* Wait for request message. */
596 		get_work(&fs_m_in);
597 
598 		src = fs_m_in.m_source;
599 		error = OK;
600 		caller_uid = INVAL_UID; /* To trap errors */
601 		caller_gid = INVAL_GID;
602 		req_nr = fs_m_in.m_type;
603 
604 		if (req_nr < FS_BASE) {
605 			fs_m_in.m_type += FS_BASE;
606 			req_nr = fs_m_in.m_type;
607 		}
608 		ind = req_nr - FS_BASE;
609 
610 		if (ind < 0 || ind >= NREQS) {
611 			error = EINVAL;
612 		} else {
613 			error = (*fs_call_vec[ind])();
614 		}
615 
616 		fs_m_out.m_type = error;
617 		if (IS_VFS_FS_TRANSID(last_request_transid)) {
618 			/* If a transaction ID was set, reset it */
619 			fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type, last_request_transid);
620 		}
621 		reply(src, &fs_m_out);
622 	}
623 
624 	if (puffs__cc_restoremain(pu) == -1)
625 		warn("cannot restore main context.  impending doom");
626 
627 	/* May get here, if puffs_fakecc is set to 1. Currently librefuse sets it.
628 	 * Now we just return to the caller.
629 	 */
630 }
631 
632 int
633 puffs_mainloop(struct puffs_usermount *pu)
634 {
635 	struct puffs_cc *pcc;
636 	int sverrno;
637 
638 	assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
639 
640 	pu->pu_state |= PU_HASKQ | PU_INLOOP;
641 
642 	/*
643 	 * Create alternate execution context and jump to it.  Note
644 	 * that we come "out" of savemain twice.  Where we come out
645 	 * of it depends on the architecture.  If the return address is
646 	 * stored on the stack, we jump out from puffs_cc_continue(),
647 	 * for a register return address from puffs__cc_savemain().
648 	 * PU_MAINRESTORE makes sure we DTRT in both cases.
649 	 */
650 	if (puffs__cc_create(pu, puffs__theloop, &pcc) == -1) {
651 		goto out;
652 	}
653 	if (puffs__cc_savemain(pu) == -1) {
654 		goto out;
655 	}
656 	if ((pu->pu_state & PU_MAINRESTORE) == 0)
657 		puffs_cc_continue(pcc);
658 
659 	errno = 0;
660 
661  out:
662 	/* store the real error for a while */
663 	sverrno = errno;
664 
665 	errno = sverrno;
666 	if (errno)
667 		return -1;
668 	else
669 		return 0;
670 }
671 
672 
673 /*===========================================================================*
674  *			       sef_local_startup			     *
675  *===========================================================================*/
676 static void sef_local_startup()
677 {
678   /* Register init callbacks. */
679   sef_setcb_init_fresh(sef_cb_init_fresh);
680   sef_setcb_init_restart(sef_cb_init_fail);
681 
682   /* No live update support for now. */
683 
684   /* Register signal callbacks. */
685   sef_setcb_signal_handler(sef_cb_signal_handler);
686 
687   /* Let SEF perform startup. */
688   sef_startup();
689 }
690 
691 /*===========================================================================*
692  *		            sef_cb_init_fresh                                *
693  *===========================================================================*/
694 static int sef_cb_init_fresh(int type, sef_init_info_t *info)
695 {
696 /* Initialize the Minix file server. */
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 != ipc_send(who, m_out))    /* send the message */
771 	lpuffs_debug("libpuffs(%d) was unable to send reply\n", sef_self());
772 
773   last_request_transid = 0;
774 }
775 
776