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