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