1 /* $NetBSD: perfuse.c,v 1.42 2019/04/17 12:30:51 maya Exp $ */ 2 3 /*- 4 * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <fcntl.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <puffs.h> 35 #include <inttypes.h> 36 #include <sys/types.h> 37 #include <sys/mman.h> 38 #include <sys/resource.h> 39 #include <sys/socket.h> 40 #include <sys/extattr.h> 41 #include <sys/hash.h> 42 #include <sys/un.h> 43 #include <machine/vmparam.h> 44 45 #define LIBPERFUSE 46 #include "perfuse.h" 47 #include "perfuse_if.h" 48 #include "perfuse_priv.h" 49 50 int perfuse_diagflags = 0; /* global used only in DPRINTF/DERR/DWARN */ 51 extern char **environ; 52 53 static struct perfuse_state *init_state(void); 54 static int get_fd(const char *); 55 56 static struct perfuse_state * 57 init_state(void) 58 { 59 struct perfuse_state *ps; 60 size_t len; 61 char opts[1024]; 62 int i; 63 64 if ((ps = malloc(sizeof(*ps))) == NULL) 65 DERR(EX_OSERR, "%s:%d malloc failed", __func__, __LINE__); 66 67 (void)memset(ps, 0, sizeof(*ps)); 68 ps->ps_max_write = UINT_MAX; 69 ps->ps_max_readahead = UINT_MAX; 70 TAILQ_INIT(&ps->ps_trace); 71 72 ps->ps_nnidhash = PUFFS_PNODEBUCKETS; 73 len = sizeof(*ps->ps_nidhash) * ps->ps_nnidhash; 74 if ((ps->ps_nidhash = malloc(len)) == NULL) 75 DERR(EX_OSERR, "%s:%d malloc failed", __func__, __LINE__); 76 for (i = 0; i < ps->ps_nnidhash; i++) 77 LIST_INIT(&ps->ps_nidhash[i]); 78 79 /* 80 * Most of the time, access() is broken because the filesystem 81 * performs the check with root privileges. glusterfs will do that 82 * if the Linux-specific setfsuid() is missing, for instance. 83 */ 84 ps->ps_flags |= PS_NO_ACCESS; 85 86 /* 87 * This is a temporary way to toggle access and creat usage. 88 * It would be nice if that could be provided as mount options, 89 * but that will not be obvious to do. 90 */ 91 if (getenv_r("PERFUSE_OPTIONS", opts, sizeof(opts)) != -1) { 92 char *optname; 93 char *last; 94 95 for ((optname = strtok_r(opts, ",", &last)); 96 optname != NULL; 97 (optname = strtok_r(NULL, ",", &last))) { 98 if (strcmp(optname, "enable_access") == 0) 99 ps->ps_flags &= ~PS_NO_ACCESS; 100 101 if (strcmp(optname, "disable_access") == 0) 102 ps->ps_flags |= PS_NO_ACCESS; 103 104 if (strcmp(optname, "enable_creat") == 0) 105 ps->ps_flags &= ~PS_NO_CREAT; 106 107 if (strcmp(optname, "disable_creat") == 0) 108 ps->ps_flags |= PS_NO_CREAT; 109 } 110 } 111 112 113 return ps; 114 } 115 116 117 static int 118 get_fd(const char *data) 119 { 120 char *string; 121 const char fdopt[] = "fd="; 122 char *lastp; 123 char *opt; 124 int fd = -1; 125 126 if ((string = strdup(data)) == NULL) 127 return -1; 128 129 for (opt = strtok_r(string, ",", &lastp); 130 opt != NULL; 131 opt = strtok_r(NULL, ",", &lastp)) { 132 if (strncmp(opt, fdopt, strlen(fdopt)) == 0) { 133 fd = atoi(opt + strlen(fdopt)); 134 break; 135 } 136 } 137 138 /* 139 * No file descriptor found 140 */ 141 if (fd == -1) 142 errno = EINVAL; 143 144 free(string); 145 return fd; 146 147 } 148 149 uint32_t 150 perfuse_bufvar_from_env(const char *name, uint32_t defval) 151 { 152 char valstr[1024]; 153 int e; 154 uint32_t retval; 155 156 if (getenv_r(name, valstr, sizeof(valstr)) == -1) 157 return defval; 158 159 retval = (uint32_t)strtoi(valstr, NULL, 0, 0, UINT32_MAX, &e); 160 if (!e) 161 return retval; 162 163 DWARNC(e, "conversion from `%s' to uint32_t failed, using %u", 164 valstr, defval); 165 return defval; 166 } 167 168 int 169 perfuse_open(const char *path, int flags, mode_t mode) 170 { 171 int sv[2]; 172 struct sockaddr_un sun; 173 struct sockaddr *sa; 174 char progname[] = _PATH_PERFUSED; 175 char minus_i[] = "-i"; 176 char fdstr[16]; 177 char *const argv[] = { progname, minus_i, fdstr, NULL}; 178 uint32_t opt; 179 uint32_t optlen; 180 int sock_type = SOCK_SEQPACKET; 181 182 if (strcmp(path, _PATH_FUSE) != 0) 183 return open(path, flags, mode); 184 185 /* 186 * Try SOCK_SEQPACKET then SOCK_DGRAM if unavailable 187 */ 188 if ((sv[0] = socket(PF_LOCAL, SOCK_SEQPACKET, 0)) == -1) { 189 sock_type = SOCK_DGRAM; 190 DWARNX("SEQPACKET local sockets unavailable, using less " 191 "reliable DGRAM sockets. Expect file operation hangs."); 192 193 if ((sv[0] = socket(PF_LOCAL, SOCK_DGRAM, 0)) == -1) { 194 #ifdef PERFUSE_DEBUG 195 DWARN("%s: %d socket failed", __func__, __LINE__); 196 #endif 197 return -1; 198 } 199 } 200 201 /* 202 * Set a buffer length large enough so that enough FUSE packets 203 * will fit. 204 */ 205 opt = perfuse_bufvar_from_env("PERFUSE_BUFSIZE", 206 (uint32_t)(16 * FUSE_BUFSIZE)); 207 optlen = sizeof(opt); 208 if (setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &opt, optlen) != 0) 209 DWARN("%s: setsockopt SO_SNDBUF to %d failed", __func__, opt); 210 211 if (setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &opt, optlen) != 0) 212 DWARN("%s: setsockopt SO_RCVBUF to %d failed", __func__, opt); 213 214 sa = (struct sockaddr *)(void *)&sun; 215 sun.sun_len = sizeof(sun); 216 sun.sun_family = AF_LOCAL; 217 (void)strcpy(sun.sun_path, path); 218 219 if (connect(sv[0], sa, (socklen_t)sun.sun_len) == 0) 220 return sv[0]; 221 222 /* 223 * Attempt to run perfused on our own 224 * if it does not run yet; In that case 225 * we will talk using a socketpair 226 * instead of /dev/fuse. 227 */ 228 if (socketpair(PF_LOCAL, sock_type, 0, sv) != 0) { 229 DWARN("%s:%d: socketpair failed", __func__, __LINE__); 230 return -1; 231 } 232 233 /* 234 * Set a buffer length large enough so that enough FUSE packets 235 * will fit. 236 */ 237 opt = perfuse_bufvar_from_env("PERFUSE_BUFSIZE", 238 (uint32_t)(16 * FUSE_BUFSIZE)); 239 optlen = sizeof(opt); 240 if (setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &opt, optlen) != 0) 241 DWARN("%s: setsockopt SO_SNDBUF to %d failed", __func__, opt); 242 243 if (setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &opt, optlen) != 0) 244 DWARN("%s: setsockopt SO_RCVBUF to %d failed", __func__, opt); 245 246 if (setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &opt, optlen) != 0) 247 DWARN("%s: setsockopt SO_SNDBUF to %d failed", __func__, opt); 248 249 if (setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &opt, optlen) != 0) 250 DWARN("%s: setsockopt SO_RCVBUF to %d failed", __func__, opt); 251 252 /* 253 * Request peer credentials. This musr be done before first 254 * frame is sent. 255 */ 256 opt = 1; 257 optlen = sizeof(opt); 258 if (setsockopt(sv[1], 0, LOCAL_CREDS, &opt, optlen) != 0) 259 DWARN("%s: setsockopt LOCAL_CREDS failed", __func__); 260 261 (void)sprintf(fdstr, "%d", sv[1]); 262 263 switch(fork()) { 264 case -1: 265 #ifdef PERFUSE_DEBUG 266 DWARN("%s:%d: fork failed", __func__, __LINE__); 267 #endif 268 return -1; 269 /* NOTREACHED */ 270 break; 271 case 0: 272 (void)close(sv[0]); 273 (void)execve(argv[0], argv, environ); 274 #ifdef PERFUSE_DEBUG 275 DWARN("%s:%d: execve failed", __func__, __LINE__); 276 #endif 277 return -1; 278 /* NOTREACHED */ 279 break; 280 default: 281 break; 282 } 283 284 (void)close(sv[1]); 285 return sv[0]; 286 } 287 288 int 289 perfuse_mount(const char *source, const char *target, 290 const char *filesystemtype, long mountflags, const void *data) 291 { 292 int s; 293 size_t len; 294 struct perfuse_mount_out *pmo; 295 struct sockaddr_storage ss; 296 struct sockaddr_un *sun; 297 struct sockaddr *sa; 298 socklen_t sa_len; 299 size_t sock_len; 300 char *frame; 301 char *cp; 302 303 #ifdef PERFUSE_DEBUG 304 if (perfuse_diagflags & PDF_MISC) 305 DPRINTF("%s(\"%s\", \"%s\", \"%s\", 0x%lx, \"%s\")\n", 306 __func__, source, target, filesystemtype, 307 mountflags, (const char *)data); 308 #endif 309 310 if ((s = get_fd(data)) == -1) 311 return -1; 312 313 /* 314 * If we are connected to /dev/fuse, we need a second 315 * socket to get replies from perfused. 316 * XXX This socket is not removed at exit time yet 317 */ 318 sock_len = 0; 319 sa = (struct sockaddr *)(void *)&ss; 320 sun = (struct sockaddr_un *)(void *)&ss; 321 sa_len = sizeof(ss); 322 if ((getpeername(s, sa, &sa_len) == 0) && 323 (sa->sa_family = AF_LOCAL) && 324 (strcmp(sun->sun_path, _PATH_FUSE) == 0)) { 325 326 sun->sun_len = sizeof(*sun); 327 sun->sun_family = AF_LOCAL; 328 (void)sprintf(sun->sun_path, "%s/%s-%d", 329 _PATH_TMP, getprogname(), getpid()); 330 331 if (bind(s, sa, (socklen_t)sa->sa_len) != 0) 332 DERR(EX_OSERR, "%s:%d bind to \"%s\" failed", 333 __func__, __LINE__, sun->sun_path); 334 335 sock_len = strlen(sun->sun_path) + 1; 336 } 337 338 len = sizeof(*pmo); 339 len += source ? (uint32_t)strlen(source) + 1 : 0; 340 len += target ? (uint32_t)strlen(target) + 1 : 0; 341 len += filesystemtype ? (uint32_t)strlen(filesystemtype) + 1 : 0; 342 len += data ? (uint32_t)strlen(data) + 1 : 0; 343 len += sock_len; 344 345 if ((frame = malloc(len)) == NULL) { 346 #ifdef PERFUSE_DEBUG 347 if (perfuse_diagflags & PDF_MISC) 348 DWARN("%s:%d malloc failed", __func__, __LINE__); 349 #endif 350 return -1; 351 } 352 353 pmo = (struct perfuse_mount_out *)(void *)frame; 354 pmo->pmo_len = (uint32_t)len; 355 pmo->pmo_error = 0; 356 pmo->pmo_unique = (uint64_t)-1; 357 (void)strcpy(pmo->pmo_magic, PERFUSE_MOUNT_MAGIC); 358 359 pmo->pmo_source_len = source ? (uint32_t)strlen(source) + 1 : 0; 360 pmo->pmo_target_len = target ? (uint32_t)strlen(target) + 1: 0; 361 pmo->pmo_filesystemtype_len = 362 filesystemtype ? (uint32_t)strlen(filesystemtype) + 1 : 0; 363 pmo->pmo_mountflags = (uint32_t)mountflags; 364 pmo->pmo_data_len = data ? (uint32_t)strlen(data) + 1 : 0; 365 pmo->pmo_sock_len = (uint32_t)sock_len; 366 367 cp = (char *)(void *)(pmo + 1); 368 369 if (source) { 370 (void)strcpy(cp, source); 371 cp += pmo->pmo_source_len; 372 } 373 374 if (target) { 375 (void)strcpy(cp, target); 376 cp += pmo->pmo_target_len; 377 } 378 379 if (filesystemtype) { 380 (void)strcpy(cp, filesystemtype); 381 cp += pmo->pmo_filesystemtype_len; 382 } 383 384 if (data) { 385 (void)strcpy(cp, data); 386 cp += pmo->pmo_data_len; 387 } 388 389 if (sock_len != 0) { 390 (void)strcpy(cp, sun->sun_path); 391 cp += pmo->pmo_sock_len; 392 } 393 394 if (send(s, frame, len, MSG_NOSIGNAL) != (ssize_t)len) { 395 #ifdef PERFUSE_DEBUG 396 DWARN("%s:%d sendto failed", __func__, __LINE__); 397 #endif 398 return -1; 399 } 400 401 return 0; 402 } 403 404 405 uint64_t 406 perfuse_next_unique(struct puffs_usermount *pu) 407 { 408 struct perfuse_state *ps; 409 410 ps = puffs_getspecific(pu); 411 412 return ps->ps_unique++; 413 } 414 415 static void 416 updatelimit(const char *func, int lim, const char *name) 417 { 418 struct rlimit rl; 419 420 /* Try infinity but that will fail unless we are root */ 421 rl.rlim_cur = RLIM_INFINITY; 422 rl.rlim_max = RLIM_INFINITY; 423 if (setrlimit(lim, &rl) != -1) 424 return; 425 426 /* Get and set to the maximum allowed */ 427 if (getrlimit(lim, &rl) == -1) 428 DERR(EX_OSERR, "%s: getrlimit %s failed", func, name); 429 430 rl.rlim_cur = rl.rlim_max; 431 if (setrlimit(lim, &rl) == -1) 432 DERR(EX_OSERR, "%s: setrlimit %s to %ju failed", func, 433 name, (uintmax_t)rl.rlim_cur); 434 } 435 436 struct puffs_usermount * 437 perfuse_init(struct perfuse_callbacks *pc, struct perfuse_mount_info *pmi) 438 { 439 struct perfuse_state *ps; 440 struct puffs_usermount *pu; 441 struct puffs_ops *pops; 442 const char *source = _PATH_PUFFS; 443 char *fstype; 444 unsigned int puffs_flags; 445 struct puffs_node *pn_root; 446 struct puffs_pathobj *po_root; 447 448 /* 449 * perfused can grow quite large, let assume there's enough ram ... 450 */ 451 updatelimit(__func__, RLIMIT_DATA, "RLIMIT_DATA"); 452 updatelimit(__func__, RLIMIT_AS, "RLIMIT_AS"); 453 454 ps = init_state(); 455 ps->ps_owner_uid = pmi->pmi_uid; 456 457 if (pmi->pmi_source) { 458 if ((ps->ps_source = strdup(pmi->pmi_source)) == NULL) 459 DERR(EX_OSERR, "%s: strdup failed", __func__); 460 461 source = ps->ps_source; 462 } 463 464 if (pmi->pmi_filesystemtype) { 465 size_t len; 466 467 ps->ps_filesystemtype = strdup(pmi->pmi_filesystemtype); 468 if (ps->ps_filesystemtype == NULL) 469 DERR(EX_OSERR, "%s: strdup failed", __func__); 470 471 len = sizeof("perfuse|") + strlen(ps->ps_filesystemtype) + 1; 472 if ((fstype = malloc(len)) == NULL) 473 DERR(EX_OSERR, "%s: malloc failed", __func__); 474 475 (void)sprintf(fstype, "perfuse|%s", ps->ps_filesystemtype); 476 } else { 477 if ((fstype = strdup("perfuse")) == NULL) 478 DERR(EX_OSERR, "%s: strdup failed", __func__); 479 } 480 481 if ((ps->ps_target = strdup(pmi->pmi_target)) == NULL) 482 DERR(EX_OSERR, "%s: strdup failed", __func__); 483 484 ps->ps_mountflags = pmi->pmi_mountflags; 485 486 /* 487 * Some options are forbidden for non root users 488 */ 489 if (ps->ps_owner_uid != 0) 490 ps->ps_mountflags |= MNT_NOSUID|MNT_NODEV; 491 492 PUFFSOP_INIT(pops); 493 PUFFSOP_SET(pops, perfuse, fs, unmount); 494 PUFFSOP_SET(pops, perfuse, fs, statvfs); 495 PUFFSOP_SET(pops, perfuse, fs, sync); 496 PUFFSOP_SET(pops, perfuse, node, lookup); 497 PUFFSOP_SET(pops, perfuse, node, create); 498 PUFFSOP_SET(pops, perfuse, node, mknod); 499 PUFFSOP_SET(pops, perfuse, node, open); 500 PUFFSOP_SET(pops, perfuse, node, close); 501 PUFFSOP_SET(pops, perfuse, node, access); 502 PUFFSOP_SET(pops, perfuse, node, getattr); 503 PUFFSOP_SET(pops, perfuse, node, setattr); 504 PUFFSOP_SET(pops, perfuse, node, poll); 505 PUFFSOP_SET(pops, perfuse, node, fsync); 506 PUFFSOP_SET(pops, perfuse, node, remove); 507 PUFFSOP_SET(pops, perfuse, node, link); 508 PUFFSOP_SET(pops, perfuse, node, rename); 509 PUFFSOP_SET(pops, perfuse, node, mkdir); 510 PUFFSOP_SET(pops, perfuse, node, rmdir); 511 PUFFSOP_SET(pops, perfuse, node, symlink); 512 PUFFSOP_SET(pops, perfuse, node, readdir); 513 PUFFSOP_SET(pops, perfuse, node, readlink); 514 PUFFSOP_SET(pops, perfuse, node, reclaim); 515 PUFFSOP_SET(pops, perfuse, node, reclaim2); 516 PUFFSOP_SET(pops, perfuse, node, inactive); 517 PUFFSOP_SET(pops, perfuse, node, print); 518 PUFFSOP_SET(pops, perfuse, node, pathconf); 519 PUFFSOP_SET(pops, perfuse, node, advlock); 520 PUFFSOP_SET(pops, perfuse, node, read); 521 PUFFSOP_SET(pops, perfuse, node, write); 522 #ifdef PUFFS_EXTNAMELEN 523 PUFFSOP_SET(pops, perfuse, node, getextattr); 524 PUFFSOP_SET(pops, perfuse, node, setextattr); 525 PUFFSOP_SET(pops, perfuse, node, listextattr); 526 PUFFSOP_SET(pops, perfuse, node, deleteextattr); 527 #endif /* PUFFS_EXTNAMELEN */ 528 #ifdef PUFFS_KFLAG_CACHE_FS_TTL 529 PUFFSOP_SET(pops, perfuse, node, getattr_ttl); 530 PUFFSOP_SET(pops, perfuse, node, setattr_ttl); 531 #endif /* PUFFS_KFLAG_CACHE_FS_TTL */ 532 #ifdef PUFFS_SETATTR_FAF 533 PUFFSOP_SET(pops, perfuse, node, write2); 534 #endif /* PUFFS_SETATTR_FAF */ 535 #ifdef PUFFS_OPEN_IO_DIRECT 536 PUFFSOP_SET(pops, perfuse, node, open2); 537 #endif /* PUFFS_OPEN_IO_DIRECT */ 538 #ifdef PUFFS_HAVE_FALLOCATE 539 PUFFSOP_SET(pops, perfuse, node, fallocate); 540 #endif /* PUFFS_HAVE_FALLOCATE */ 541 542 /* 543 * PUFFS_KFLAG_NOCACHE_NAME is required so that we can see changes 544 * done by other machines in networked filesystems. In later 545 * NetBSD releases we use the alternative PUFFS_KFLAG_CACHE_FS_TTL, 546 * which implement name cache with a filesystem-provided TTL. 547 */ 548 #ifdef PUFFS_KFLAG_CACHE_FS_TTL 549 puffs_flags = PUFFS_KFLAG_CACHE_FS_TTL; 550 #else 551 puffs_flags = PUFFS_KFLAG_NOCACHE_NAME; 552 #endif 553 554 /* 555 * Do not lookuo .. 556 * That means we keep all parent vnode active 557 */ 558 #ifdef PUFFS_KFLAG_CACHE_DOTDOT 559 puffs_flags |= PUFFS_KFLAG_CACHE_DOTDOT; 560 #endif 561 562 /* 563 * It would be nice to avoid useless inactive, and only 564 * get them on file open for writing (PUFFS does 565 * CLOSE/WRITE/INACTIVE, therefore actual close must be 566 * done at INACTIVE time). Unfortunatley, puffs_setback 567 * crashes when called on OPEN, therefore leave it for 568 * another day. 569 */ 570 #ifdef notyet 571 puffs_flags |= PUFFS_FLAG_IAONDEMAND; 572 #endif 573 574 /* 575 * FUSE filesystem do not expect [amc]time and size 576 * updates to be sent by the kernel, they do the 577 * updates on their own after other operations. 578 */ 579 #ifdef PUFFS_KFLAG_NOFLUSH_META 580 puffs_flags |= PUFFS_KFLAG_NOFLUSH_META; 581 #endif 582 583 if (perfuse_diagflags & PDF_PUFFS) 584 puffs_flags |= PUFFS_FLAG_OPDUMP; 585 586 if ((pu = puffs_init(pops, source, fstype, ps, puffs_flags)) == NULL) 587 DERR(EX_OSERR, "%s: puffs_init failed", __func__); 588 589 puffs_setncookiehash(pu, PUFFS_PNODEBUCKETS); 590 591 ps->ps_pu = pu; 592 593 /* 594 * Setup filesystem root 595 */ 596 pn_root = perfuse_new_pn(pu, "", NULL); 597 PERFUSE_NODE_DATA(pn_root)->pnd_nodeid = FUSE_ROOT_ID; 598 PERFUSE_NODE_DATA(pn_root)->pnd_parent_nodeid = FUSE_ROOT_ID; 599 perfuse_node_cache(ps, pn_root); 600 puffs_setroot(pu, pn_root); 601 ps->ps_fsid = pn_root->pn_va.va_fsid; 602 603 po_root = puffs_getrootpathobj(pu); 604 if ((po_root->po_path = strdup("/")) == NULL) 605 DERRX(EX_OSERR, "perfuse_mount_start() failed"); 606 607 po_root->po_len = 1; 608 puffs_path_buildhash(pu, po_root); 609 610 puffs_vattr_null(&pn_root->pn_va); 611 pn_root->pn_va.va_type = VDIR; 612 pn_root->pn_va.va_mode = 0755; 613 pn_root->pn_va.va_fileid = FUSE_ROOT_ID; 614 615 ps->ps_root = pn_root; 616 617 /* 618 * Callbacks 619 */ 620 ps->ps_new_msg = pc->pc_new_msg; 621 ps->ps_xchg_msg = pc->pc_xchg_msg; 622 ps->ps_destroy_msg = pc->pc_destroy_msg; 623 ps->ps_get_inhdr = pc->pc_get_inhdr; 624 ps->ps_get_inpayload = pc->pc_get_inpayload; 625 ps->ps_get_outhdr = pc->pc_get_outhdr; 626 ps->ps_get_outpayload = pc->pc_get_outpayload; 627 ps->ps_umount = pc->pc_umount; 628 629 pc->pc_fsreq = *perfuse_fsreq; 630 631 return pu; 632 } 633 634 void 635 perfuse_setspecific(struct puffs_usermount *pu, void *priv) 636 { 637 struct perfuse_state *ps; 638 639 ps = puffs_getspecific(pu); 640 ps->ps_private = priv; 641 642 return; 643 } 644 645 void * 646 perfuse_getspecific(struct puffs_usermount *pu) 647 { 648 struct perfuse_state *ps; 649 650 ps = puffs_getspecific(pu); 651 652 return ps->ps_private; 653 } 654 655 int 656 perfuse_inloop(struct puffs_usermount *pu) 657 { 658 struct perfuse_state *ps; 659 660 ps = puffs_getspecific(pu); 661 662 return ps->ps_flags & PS_INLOOP; 663 } 664 665 int 666 perfuse_mainloop(struct puffs_usermount *pu) 667 { 668 struct perfuse_state *ps; 669 670 ps = puffs_getspecific(pu); 671 672 ps->ps_flags |= PS_INLOOP; 673 if (puffs_mainloop(ps->ps_pu) != 0) { 674 DERR(EX_OSERR, "%s: failed", __func__); 675 return -1; 676 } 677 678 /* 679 * Normal exit after unmount 680 */ 681 return 0; 682 } 683 684 /* ARGSUSED0 */ 685 uint64_t 686 perfuse_get_nodeid(struct puffs_usermount *pu, puffs_cookie_t opc) 687 { 688 return PERFUSE_NODE_DATA(opc)->pnd_nodeid; 689 } 690 691 int 692 perfuse_unmount(struct puffs_usermount *pu) 693 { 694 struct perfuse_state *ps; 695 696 ps = puffs_getspecific(pu); 697 698 return unmount(ps->ps_target, MNT_FORCE); 699 } 700 701 void 702 perfuse_fsreq(struct puffs_usermount *pu, perfuse_msg_t *pm) 703 { 704 struct perfuse_state *ps; 705 struct fuse_out_header *foh; 706 707 ps = puffs_getspecific(pu); 708 foh = GET_OUTHDR(ps, pm); 709 710 /* 711 * There are some operations we may use in a Fire and Forget wey, 712 * because the kernel does not await a reply, but FUSE still 713 * sends a reply. This happens for fsyc, setattr (for metadata 714 * associated with a fsync) and write (for VOP_PUTPAGES). Ignore 715 * if it was fine, warn or abort otherwise. 716 */ 717 switch (foh->error) { 718 case 0: 719 break; 720 case -ENOENT: 721 /* File disapeared during a FAF operation */ 722 break; 723 case -ENOTCONN: /* FALLTHROUGH */ 724 case -EAGAIN: /* FALLTHROUGH */ 725 case -EMSGSIZE: 726 DWARN("operation unique = %"PRId64" failed", foh->unique); 727 break; 728 default: 729 DWARNX("Unexpected frame: unique = %"PRId64", error = %d", 730 foh->unique, foh->error); 731 /* NOTREACHED */ 732 break; 733 } 734 735 ps->ps_destroy_msg(pm); 736 737 return; 738 } 739