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