1 /* $NetBSD: ops.c,v 1.46 2011/11/17 02:28:21 manu 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 <libgen.h> 32 #include <errno.h> 33 #include <err.h> 34 #include <sysexits.h> 35 #include <syslog.h> 36 #include <puffs.h> 37 #include <sys/socket.h> 38 #include <sys/socket.h> 39 #include <sys/extattr.h> 40 #include <machine/vmparam.h> 41 42 #include "perfuse_priv.h" 43 #include "fuse.h" 44 45 extern int perfuse_diagflags; 46 47 static void set_expire(puffs_cookie_t, struct fuse_entry_out *, 48 struct fuse_attr_out *); 49 static int attr_expired(puffs_cookie_t); 50 static int entry_expired(puffs_cookie_t); 51 static int xchg_msg(struct puffs_usermount *, puffs_cookie_t, 52 perfuse_msg_t *, size_t, enum perfuse_xchg_pb_reply); 53 static int mode_access(puffs_cookie_t, const struct puffs_cred *, mode_t); 54 static int sticky_access(struct puffs_node *, const struct puffs_cred *); 55 static void fuse_attr_to_vap(struct perfuse_state *, 56 struct vattr *, struct fuse_attr *); 57 static int node_lookup_dir_nodot(struct puffs_usermount *, 58 puffs_cookie_t, char *, size_t, struct puffs_node **); 59 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t, 60 const char *, const struct puffs_cred *, struct puffs_node **); 61 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t, 62 struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *); 63 static int node_mk_common_final(struct puffs_usermount *, puffs_cookie_t, 64 struct puffs_node *, const struct puffs_cn *pcn); 65 static uint64_t readdir_last_cookie(struct fuse_dirent *, size_t); 66 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t, 67 struct fuse_dirent *, size_t); 68 static int readdir_buffered(puffs_cookie_t, struct dirent *, off_t *, 69 size_t *); 70 static void requeue_request(struct puffs_usermount *, 71 puffs_cookie_t opc, enum perfuse_qtype); 72 static int dequeue_requests(struct perfuse_state *, 73 puffs_cookie_t opc, enum perfuse_qtype, int); 74 #define DEQUEUE_ALL 0 75 76 /* 77 * From <sys/vnode>, inside #ifdef _KERNEL section 78 */ 79 #define IO_SYNC (0x40|IO_DSYNC) 80 #define IO_DSYNC 0x00200 81 #define IO_DIRECT 0x02000 82 83 /* 84 * From <fcntl>, inside #ifdef _KERNEL section 85 */ 86 #define F_WAIT 0x010 87 #define F_FLOCK 0x020 88 #define OFLAGS(fflags) ((fflags) - 1) 89 90 /* 91 * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h 92 */ 93 const enum vtype iftovt_tab[16] = { 94 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 95 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 96 }; 97 const int vttoif_tab[9] = { 98 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 99 S_IFSOCK, S_IFIFO, S_IFMT, 100 }; 101 102 #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12]) 103 #define VTTOIF(indx) (vttoif_tab[(int)(indx)]) 104 105 int 106 perfuse_node_close_common(pu, opc, mode) 107 struct puffs_usermount *pu; 108 puffs_cookie_t opc; 109 int mode; 110 { 111 struct perfuse_state *ps; 112 perfuse_msg_t *pm; 113 int op; 114 uint64_t fh; 115 struct fuse_release_in *fri; 116 struct perfuse_node_data *pnd; 117 struct puffs_node *pn; 118 int error; 119 120 ps = puffs_getspecific(pu); 121 pn = (struct puffs_node *)opc; 122 pnd = PERFUSE_NODE_DATA(pn); 123 124 if (puffs_pn_getvap(pn)->va_type == VDIR) { 125 op = FUSE_RELEASEDIR; 126 mode = FREAD; 127 } else { 128 op = FUSE_RELEASE; 129 } 130 131 /* 132 * Destroy the filehandle before sending the 133 * request to the FUSE filesystem, otherwise 134 * we may get a second close() while we wait 135 * for the reply, and we would end up closing 136 * the same fh twice instead of closng both. 137 */ 138 fh = perfuse_get_fh(opc, mode); 139 perfuse_destroy_fh(pn, fh); 140 141 /* 142 * release_flags may be set to FUSE_RELEASE_FLUSH 143 * to flush locks. lock_owner must be set in that case 144 * 145 * ps_new_msg() is called with NULL creds, which will 146 * be interpreted as FUSE superuser. We come here from the 147 * inactive method, which provides no creds, but obviously 148 * runs with kernel privilege. 149 */ 150 pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL); 151 fri = GET_INPAYLOAD(ps, pm, fuse_release_in); 152 fri->fh = fh; 153 fri->flags = 0; 154 fri->release_flags = 0; 155 fri->lock_owner = pnd->pnd_lock_owner; 156 fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0; 157 158 #ifdef PERFUSE_DEBUG 159 if (perfuse_diagflags & PDF_FH) 160 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 161 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh); 162 #endif 163 164 if ((error = xchg_msg(pu, opc, pm, 165 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 166 goto out; 167 168 ps->ps_destroy_msg(pm); 169 170 error = 0; 171 172 out: 173 if (error != 0) 174 DERRX(EX_SOFTWARE, "%s: freed fh = 0x%"PRIx64" but filesystem " 175 "returned error = %d", __func__, fh, error); 176 177 return error; 178 } 179 180 /* ARGSUSED1 */ 181 static int 182 xchg_msg(pu, opc, pm, len, wait) 183 struct puffs_usermount *pu; 184 puffs_cookie_t opc; 185 perfuse_msg_t *pm; 186 size_t len; 187 enum perfuse_xchg_pb_reply wait; 188 { 189 struct perfuse_state *ps; 190 struct perfuse_node_data *pnd; 191 int error; 192 193 ps = puffs_getspecific(pu); 194 pnd = NULL; 195 if ((struct puffs_node *)opc != NULL) 196 pnd = PERFUSE_NODE_DATA(opc); 197 198 #ifdef PERFUSE_DEBUG 199 if ((perfuse_diagflags & PDF_FILENAME) && (opc != 0)) 200 DPRINTF("file = \"%s\", ino = %"PRIu64" flags = 0x%x\n", 201 perfuse_node_path(opc), 202 ((struct puffs_node *)opc)->pn_va.va_fileid, 203 PERFUSE_NODE_DATA(opc)->pnd_flags); 204 #endif 205 if (pnd) 206 pnd->pnd_flags |= PND_INXCHG; 207 208 error = ps->ps_xchg_msg(pu, pm, len, wait); 209 210 if (pnd) { 211 pnd->pnd_flags &= ~PND_INXCHG; 212 (void)dequeue_requests(ps, opc, PCQ_AFTERXCHG, DEQUEUE_ALL); 213 } 214 215 return error; 216 } 217 218 static int 219 mode_access(opc, pcr, mode) 220 puffs_cookie_t opc; 221 const struct puffs_cred *pcr; 222 mode_t mode; 223 { 224 struct puffs_node *pn; 225 struct vattr *va; 226 227 /* 228 * pcr is NULL for self open through fsync or readdir. 229 * In both case, access control is useless, as it was 230 * done before, at open time. 231 */ 232 if (pcr == NULL) 233 return 0; 234 235 pn = (struct puffs_node *)opc; 236 va = puffs_pn_getvap(pn); 237 return puffs_access(va->va_type, va->va_mode, 238 va->va_uid, va->va_gid, 239 mode, pcr); 240 } 241 242 static int 243 sticky_access(targ, pcr) 244 struct puffs_node *targ; 245 const struct puffs_cred *pcr; 246 { 247 uid_t uid; 248 struct puffs_node *tdir; 249 int sticky, owner; 250 251 tdir = PERFUSE_NODE_DATA(targ)->pnd_parent; 252 253 /* 254 * This covers the case where the kernel requests a DELETE 255 * or RENAME on its own, and where puffs_cred_getuid would 256 * return -1. While such a situation should not happen, 257 * we allow it here. 258 * 259 * This also allows root to tamper with other users' files 260 * that have the sticky bit. 261 */ 262 if (puffs_cred_isjuggernaut(pcr)) 263 return 0; 264 265 if (puffs_cred_getuid(pcr, &uid) != 0) 266 DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__); 267 268 sticky = puffs_pn_getvap(tdir)->va_mode & S_ISTXT; 269 owner = puffs_pn_getvap(targ)->va_uid == uid; 270 271 if (sticky && !owner) 272 return EACCES; 273 274 return 0; 275 } 276 277 278 static void 279 fuse_attr_to_vap(ps, vap, fa) 280 struct perfuse_state *ps; 281 struct vattr *vap; 282 struct fuse_attr *fa; 283 { 284 vap->va_type = IFTOVT(fa->mode); 285 vap->va_mode = fa->mode & ALLPERMS; 286 vap->va_nlink = fa->nlink; 287 vap->va_uid = fa->uid; 288 vap->va_gid = fa->gid; 289 vap->va_fsid = (long)ps->ps_fsid; 290 vap->va_fileid = fa->ino; 291 vap->va_size = fa->size; 292 vap->va_blocksize = fa->blksize; 293 vap->va_atime.tv_sec = (time_t)fa->atime; 294 vap->va_atime.tv_nsec = (long) fa->atimensec; 295 vap->va_mtime.tv_sec = (time_t)fa->mtime; 296 vap->va_mtime.tv_nsec = (long)fa->mtimensec; 297 vap->va_ctime.tv_sec = (time_t)fa->ctime; 298 vap->va_ctime.tv_nsec = (long)fa->ctimensec; 299 vap->va_birthtime.tv_sec = 0; 300 vap->va_birthtime.tv_nsec = 0; 301 vap->va_gen = 0; 302 vap->va_flags = 0; 303 vap->va_rdev = fa->rdev; 304 vap->va_bytes = fa->size; 305 vap->va_filerev = (u_quad_t)PUFFS_VNOVAL; 306 vap->va_vaflags = 0; 307 308 if (vap->va_blocksize == 0) 309 vap->va_blocksize = DEV_BSIZE; 310 311 if (vap->va_size == (size_t)PUFFS_VNOVAL) /* XXX */ 312 vap->va_size = 0; 313 314 return; 315 } 316 317 static void 318 set_expire(opc, feo, fao) 319 puffs_cookie_t opc; 320 struct fuse_entry_out *feo; 321 struct fuse_attr_out *fao; 322 { 323 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 324 struct timespec entry_ts; 325 struct timespec attr_ts; 326 struct timespec now; 327 328 if ((feo == NULL) && (fao == NULL)) 329 DERRX(EX_SOFTWARE, "%s: feo and fao NULL", __func__); 330 331 if ((feo != NULL) && (fao != NULL)) 332 DERRX(EX_SOFTWARE, "%s: feo and fao != NULL", __func__); 333 334 if (clock_gettime(CLOCK_REALTIME, &now) != 0) 335 DERR(EX_OSERR, "clock_gettime failed"); 336 337 if (feo != NULL) { 338 entry_ts.tv_sec = (time_t)feo->entry_valid; 339 entry_ts.tv_nsec = (long)feo->entry_valid_nsec; 340 341 timespecadd(&now, &entry_ts, &pnd->pnd_entry_expire); 342 343 attr_ts.tv_sec = (time_t)feo->attr_valid; 344 attr_ts.tv_nsec = (long)feo->attr_valid_nsec; 345 346 timespecadd(&now, &attr_ts, &pnd->pnd_attr_expire); 347 } 348 349 if (fao != NULL) { 350 attr_ts.tv_sec = (time_t)fao->attr_valid; 351 attr_ts.tv_nsec = (long)fao->attr_valid_nsec; 352 353 timespecadd(&now, &attr_ts, &pnd->pnd_attr_expire); 354 } 355 356 return; 357 } 358 359 static int 360 attr_expired(opc) 361 puffs_cookie_t opc; 362 { 363 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 364 struct timespec now; 365 366 if (clock_gettime(CLOCK_REALTIME, &now) != 0) 367 DERR(EX_OSERR, "clock_gettime failed"); 368 369 return timespeccmp(&pnd->pnd_attr_expire, &now, <); 370 } 371 372 static int 373 entry_expired(opc) 374 puffs_cookie_t opc; 375 { 376 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 377 struct timespec expire = pnd->pnd_entry_expire; 378 struct timespec now; 379 380 if (clock_gettime(CLOCK_REALTIME, &now) != 0) 381 DERR(EX_OSERR, "clock_gettime failed"); 382 383 return timespeccmp(&expire, &now, <); 384 } 385 386 387 /* 388 * Lookup name in directory opc 389 * We take special care of name being . or .. 390 * These are returned by readdir and deserve tweaks. 391 */ 392 static int 393 node_lookup_dir_nodot(pu, opc, name, namelen, pnp) 394 struct puffs_usermount *pu; 395 puffs_cookie_t opc; 396 char *name; 397 size_t namelen; 398 struct puffs_node **pnp; 399 { 400 /* 401 * "dot" is easy as we already know it 402 */ 403 if (strncmp(name, ".", namelen) == 0) { 404 *pnp = (struct puffs_node *)opc; 405 return 0; 406 } 407 408 /* 409 * "dotdot" is also known 410 */ 411 if (strncmp(name, "..", namelen) == 0) { 412 *pnp = PERFUSE_NODE_DATA(opc)->pnd_parent; 413 return 0; 414 } 415 416 return node_lookup_common(pu, opc, name, NULL, pnp); 417 } 418 419 static int 420 node_lookup_common(pu, opc, path, pcr, pnp) 421 struct puffs_usermount *pu; 422 puffs_cookie_t opc; 423 const char *path; 424 const struct puffs_cred *pcr; 425 struct puffs_node **pnp; 426 { 427 struct perfuse_state *ps; 428 struct perfuse_node_data *oldpnd; 429 perfuse_msg_t *pm; 430 struct fuse_entry_out *feo; 431 struct puffs_node *pn; 432 size_t len; 433 int error; 434 435 if (pnp == NULL) 436 DERRX(EX_SOFTWARE, "pnp must be != NULL"); 437 438 ps = puffs_getspecific(pu); 439 440 #ifdef PERFUSE_DEBUG 441 if (perfuse_diagflags & PDF_FILENAME) 442 DPRINTF("%s: opc = %p, file = \"%s\" looking up \"%s\"\n", 443 __func__, (void *)opc, perfuse_node_path(opc), path); 444 #endif 445 /* 446 * Is the node already known? 447 */ 448 TAILQ_FOREACH(oldpnd, &PERFUSE_NODE_DATA(opc)->pnd_children, pnd_next) { 449 if ((oldpnd->pnd_flags & PND_REMOVED) || 450 (strcmp(oldpnd->pnd_name, path) != 0)) 451 continue; 452 453 #ifdef PERFUSE_DEBUG 454 if (perfuse_diagflags & PDF_FILENAME) 455 DPRINTF("%s: opc = %p, file = \"%s\" found " 456 "cookie = %p, nodeid = 0x%"PRIx64" for \"%s\"\n", 457 __func__, (void *)opc, perfuse_node_path(opc), 458 (void *)oldpnd->pnd_pn, oldpnd->pnd_nodeid, 459 path); 460 #endif 461 break; 462 } 463 464 /* 465 * Check for cached name 466 */ 467 if ((oldpnd != NULL) && !entry_expired(oldpnd->pnd_pn)) { 468 *pnp = oldpnd->pnd_pn; 469 return 0; 470 } 471 472 len = strlen(path) + 1; 473 474 pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, pcr); 475 (void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len); 476 477 error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply); 478 479 switch (error) { 480 case 0: 481 break; 482 case ENOENT: 483 if (oldpnd != NULL) { 484 oldpnd->pnd_flags |= PND_REMOVED; 485 #ifdef PERFUSE_DEBUG 486 if (perfuse_diagflags & PDF_FILENAME) 487 DPRINTF("%s: opc = %p nodeid = 0x%"PRIx64" " 488 "file = \"%s\" removed\n", __func__, 489 oldpnd->pnd_pn, oldpnd->pnd_nodeid, 490 oldpnd->pnd_name); 491 #endif 492 } 493 /* FALLTHROUGH */ 494 default: 495 goto out; 496 /* NOTREACHED */ 497 break; 498 } 499 500 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 501 502 if (oldpnd != NULL) { 503 if (oldpnd->pnd_nodeid == feo->nodeid) { 504 oldpnd->pnd_nlookup++; 505 *pnp = oldpnd->pnd_pn; 506 goto out; 507 } else { 508 oldpnd->pnd_flags |= PND_REMOVED; 509 #ifdef PERFUSE_DEBUG 510 if (perfuse_diagflags & PDF_FILENAME) 511 DPRINTF("%s: opc = %p nodeid = 0x%"PRIx64" " 512 "file = \"%s\" replaced\n", __func__, 513 oldpnd->pnd_pn, oldpnd->pnd_nodeid, 514 oldpnd->pnd_name); 515 #endif 516 } 517 } 518 519 pn = perfuse_new_pn(pu, path, opc); 520 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 521 522 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 523 pn->pn_va.va_gen = (u_long)(feo->generation); 524 set_expire((puffs_cookie_t)pn, feo, NULL); 525 526 *pnp = pn; 527 528 #ifdef PERFUSE_DEBUG 529 if (perfuse_diagflags & PDF_FILENAME) 530 DPRINTF("%s: opc = %p, looked up opc = %p, " 531 "nodeid = 0x%"PRIx64" file = \"%s\"\n", __func__, 532 (void *)opc, pn, feo->nodeid, path); 533 #endif 534 535 out: 536 ps->ps_destroy_msg(pm); 537 538 return error; 539 } 540 541 542 /* 543 * Common code for methods that create objects: 544 * perfuse_node_mkdir 545 * perfuse_node_mknod 546 * perfuse_node_symlink 547 */ 548 static int 549 node_mk_common(pu, opc, pni, pcn, pm) 550 struct puffs_usermount *pu; 551 puffs_cookie_t opc; 552 struct puffs_newinfo *pni; 553 const struct puffs_cn *pcn; 554 perfuse_msg_t *pm; 555 { 556 struct perfuse_state *ps; 557 struct puffs_node *pn; 558 struct fuse_entry_out *feo; 559 int error; 560 561 ps = puffs_getspecific(pu); 562 563 if ((error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply)) != 0) 564 goto out; 565 566 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 567 if (feo->nodeid == PERFUSE_UNKNOWN_NODEID) 568 DERRX(EX_SOFTWARE, "%s: no nodeid", __func__); 569 570 pn = perfuse_new_pn(pu, pcn->pcn_name, opc); 571 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 572 573 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 574 pn->pn_va.va_gen = (u_long)(feo->generation); 575 set_expire((puffs_cookie_t)pn, feo, NULL); 576 577 puffs_newinfo_setcookie(pni, pn); 578 579 #ifdef PERFUSE_DEBUG 580 if (perfuse_diagflags & PDF_FILENAME) 581 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x " 582 "nodeid = 0x%"PRIx64"\n", 583 __func__, (void *)pn, pcn->pcn_name, 584 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid); 585 #endif 586 ps->ps_destroy_msg(pm); 587 588 return node_mk_common_final(pu, opc, pn, pcn); 589 590 out: 591 ps->ps_destroy_msg(pm); 592 593 return error; 594 } 595 596 /* 597 * Common final code for methods that create objects: 598 * perfuse_node_mkdir via node_mk_common 599 * perfuse_node_mknod via node_mk_common 600 * perfuse_node_symlink via node_mk_common 601 * perfuse_node_create 602 */ 603 static int 604 node_mk_common_final(pu, opc, pn, pcn) 605 struct puffs_usermount *pu; 606 puffs_cookie_t opc; 607 struct puffs_node *pn; 608 const struct puffs_cn *pcn; 609 { 610 struct perfuse_state *ps; 611 perfuse_msg_t *pm; 612 struct fuse_setattr_in *fsi; 613 struct fuse_attr_out *fao; 614 int error; 615 616 ps = puffs_getspecific(pu); 617 618 /* 619 * Set owner and group. The kernel cannot create a file 620 * on its own (puffs_cred_getuid would return -1), right? 621 */ 622 if (puffs_cred_getuid(pcn->pcn_cred, &pn->pn_va.va_uid) != 0) 623 DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__); 624 if (puffs_cred_getgid(pcn->pcn_cred, &pn->pn_va.va_gid) != 0) 625 DERRX(EX_SOFTWARE, "puffs_cred_getgid fails in %s", __func__); 626 627 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, 628 FUSE_SETATTR, sizeof(*fsi), pcn->pcn_cred); 629 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 630 fsi->uid = pn->pn_va.va_uid; 631 fsi->gid = pn->pn_va.va_gid; 632 fsi->valid = FUSE_FATTR_UID|FUSE_FATTR_GID; 633 634 if ((error = xchg_msg(pu, (puffs_cookie_t)pn, pm, 635 sizeof(*fao), wait_reply)) != 0) 636 goto out; 637 638 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 639 fuse_attr_to_vap(ps, &pn->pn_va, &fao->attr); 640 set_expire((puffs_cookie_t)pn, NULL, fao); 641 642 /* 643 * The parent directory needs a sync 644 */ 645 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 646 647 out: 648 if (pm != NULL) 649 ps->ps_destroy_msg(pm); 650 651 return error; 652 } 653 654 static uint64_t 655 readdir_last_cookie(fd, fd_len) 656 struct fuse_dirent *fd; 657 size_t fd_len; 658 { 659 size_t len; 660 size_t seen = 0; 661 char *ndp; 662 663 do { 664 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen); 665 seen += len; 666 667 if (seen >= fd_len) 668 break; 669 670 ndp = (char *)(void *)fd + (size_t)len; 671 fd = (struct fuse_dirent *)(void *)ndp; 672 } while (1 /* CONSTCOND */); 673 674 return fd->off; 675 } 676 677 static ssize_t 678 fuse_to_dirent(pu, opc, fd, fd_len) 679 struct puffs_usermount *pu; 680 puffs_cookie_t opc; 681 struct fuse_dirent *fd; 682 size_t fd_len; 683 { 684 struct dirent *dents; 685 size_t dents_len; 686 ssize_t written; 687 uint64_t fd_offset; 688 struct fuse_dirent *fd_base; 689 size_t len; 690 691 fd_base = fd; 692 fd_offset = 0; 693 written = 0; 694 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent; 695 dents_len = (size_t)PERFUSE_NODE_DATA(opc)->pnd_dirent_len; 696 697 do { 698 char *ndp; 699 size_t reclen; 700 701 reclen = _DIRENT_RECLEN(dents, fd->namelen); 702 703 /* 704 * Check we do not overflow the output buffer 705 * struct fuse_dirent is bigger than struct dirent, 706 * so we should always use fd_len and never reallocate 707 * later. 708 * If we have to reallocate,try to double the buffer 709 * each time so that we do not have to do it too often. 710 */ 711 if (written + reclen > dents_len) { 712 if (dents_len == 0) 713 dents_len = fd_len; 714 else 715 dents_len = 716 MAX(2 * dents_len, written + reclen); 717 718 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent; 719 if ((dents = realloc(dents, dents_len)) == NULL) 720 DERR(EX_OSERR, "%s: malloc failed", __func__); 721 722 PERFUSE_NODE_DATA(opc)->pnd_dirent = dents; 723 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len; 724 725 /* 726 * (void *) for delint 727 */ 728 ndp = (char *)(void *)dents + written; 729 dents = (struct dirent *)(void *)ndp; 730 } 731 732 /* 733 * Filesystem was mounted without -o use_ino 734 * Perform a lookup to find it. 735 */ 736 if (fd->ino == PERFUSE_UNKNOWN_INO) { 737 struct puffs_node *pn; 738 739 if (node_lookup_dir_nodot(pu, opc, fd->name, 740 fd->namelen, &pn) != 0) { 741 DWARNX("node_lookup_dir_nodot failed"); 742 } else { 743 fd->ino = pn->pn_va.va_fileid; 744 } 745 } 746 747 dents->d_fileno = fd->ino; 748 dents->d_reclen = (unsigned short)reclen; 749 dents->d_namlen = fd->namelen; 750 dents->d_type = fd->type; 751 strlcpy(dents->d_name, fd->name, fd->namelen + 1); 752 753 #ifdef PERFUSE_DEBUG 754 if (perfuse_diagflags & PDF_READDIR) 755 DPRINTF("%s: translated \"%s\" ino = %"PRIu64"\n", 756 __func__, dents->d_name, dents->d_fileno); 757 #endif 758 759 dents = _DIRENT_NEXT(dents); 760 written += reclen; 761 762 /* 763 * Move to the next record. 764 * fd->off is not the offset, it is an opaque cookie 765 * given by the filesystem to keep state across multiple 766 * readdir() operation. 767 * Use record alignement instead. 768 */ 769 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen); 770 #ifdef PERFUSE_DEBUG 771 if (perfuse_diagflags & PDF_READDIR) 772 DPRINTF("%s: record at %"PRId64"/0x%"PRIx64" " 773 "length = %zd/0x%zx. " 774 "next record at %"PRId64"/0x%"PRIx64" " 775 "max %zd/0x%zx\n", 776 __func__, fd_offset, fd_offset, len, len, 777 fd_offset + len, fd_offset + len, 778 fd_len, fd_len); 779 #endif 780 fd_offset += len; 781 782 /* 783 * Check if next record is still within the packet 784 * If it is not, we reached the end of the buffer. 785 */ 786 if (fd_offset >= fd_len) 787 break; 788 789 /* 790 * (void *) for delint 791 */ 792 ndp = (char *)(void *)fd_base + (size_t)fd_offset; 793 fd = (struct fuse_dirent *)(void *)ndp; 794 795 } while (1 /* CONSTCOND */); 796 797 /* 798 * Adjust the dirent output length 799 */ 800 if (written != -1) 801 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written; 802 803 return written; 804 } 805 806 static int 807 readdir_buffered(opc, dent, readoff, reslen) 808 puffs_cookie_t opc; 809 struct dirent *dent; 810 off_t *readoff; 811 size_t *reslen; 812 { 813 struct dirent *fromdent; 814 struct perfuse_node_data *pnd; 815 char *ndp; 816 817 pnd = PERFUSE_NODE_DATA(opc); 818 819 while (*readoff < pnd->pnd_dirent_len) { 820 /* 821 * (void *) for delint 822 */ 823 ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff; 824 fromdent = (struct dirent *)(void *)ndp; 825 826 if (*reslen < _DIRENT_SIZE(fromdent)) 827 break; 828 829 memcpy(dent, fromdent, _DIRENT_SIZE(fromdent)); 830 *readoff += _DIRENT_SIZE(fromdent); 831 *reslen -= _DIRENT_SIZE(fromdent); 832 833 dent = _DIRENT_NEXT(dent); 834 } 835 836 #ifdef PERFUSE_DEBUG 837 if (perfuse_diagflags & PDF_READDIR) 838 DPRINTF("%s: readoff = %"PRId64", " 839 "pnd->pnd_dirent_len = %"PRId64"\n", 840 __func__, *readoff, pnd->pnd_dirent_len); 841 #endif 842 if (*readoff >= pnd->pnd_dirent_len) { 843 free(pnd->pnd_dirent); 844 pnd->pnd_dirent = NULL; 845 pnd->pnd_dirent_len = 0; 846 } 847 848 return 0; 849 } 850 851 static void 852 requeue_request(pu, opc, type) 853 struct puffs_usermount *pu; 854 puffs_cookie_t opc; 855 enum perfuse_qtype type; 856 { 857 struct perfuse_cc_queue pcq; 858 struct perfuse_node_data *pnd; 859 #ifdef PERFUSE_DEBUG 860 struct perfuse_state *ps; 861 862 ps = perfuse_getspecific(pu); 863 #endif 864 865 pnd = PERFUSE_NODE_DATA(opc); 866 pcq.pcq_type = type; 867 pcq.pcq_cc = puffs_cc_getcc(pu); 868 TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next); 869 870 #ifdef PERFUSE_DEBUG 871 if (perfuse_diagflags & PDF_REQUEUE) 872 DPRINTF("%s: REQUEUE opc = %p, pcc = %p (%s)\n", 873 __func__, (void *)opc, pcq.pcq_cc, 874 perfuse_qtypestr[type]); 875 #endif 876 877 puffs_cc_yield(pcq.pcq_cc); 878 TAILQ_REMOVE(&pnd->pnd_pcq, &pcq, pcq_next); 879 880 #ifdef PERFUSE_DEBUG 881 if (perfuse_diagflags & PDF_REQUEUE) 882 DPRINTF("%s: RESUME opc = %p, pcc = %p (%s)\n", 883 __func__, (void *)opc, pcq.pcq_cc, 884 perfuse_qtypestr[type]); 885 #endif 886 887 return; 888 } 889 890 /* ARGSUSED0 */ 891 static int 892 dequeue_requests(ps, opc, type, max) 893 struct perfuse_state *ps; 894 puffs_cookie_t opc; 895 enum perfuse_qtype type; 896 int max; 897 { 898 struct perfuse_cc_queue *pcq; 899 struct perfuse_node_data *pnd; 900 int dequeued; 901 902 pnd = PERFUSE_NODE_DATA(opc); 903 dequeued = 0; 904 TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) { 905 if (pcq->pcq_type != type) 906 continue; 907 908 #ifdef PERFUSE_DEBUG 909 if (perfuse_diagflags & PDF_REQUEUE) 910 DPRINTF("%s: SCHEDULE opc = %p, pcc = %p (%s)\n", 911 __func__, (void *)opc, pcq->pcq_cc, 912 perfuse_qtypestr[type]); 913 #endif 914 puffs_cc_schedule(pcq->pcq_cc); 915 916 if (++dequeued == max) 917 break; 918 } 919 920 #ifdef PERFUSE_DEBUG 921 if (perfuse_diagflags & PDF_REQUEUE) 922 DPRINTF("%s: DONE opc = %p\n", __func__, (void *)opc); 923 #endif 924 925 return dequeued; 926 } 927 928 void 929 perfuse_fs_init(pu) 930 struct puffs_usermount *pu; 931 { 932 struct perfuse_state *ps; 933 perfuse_msg_t *pm; 934 struct fuse_init_in *fii; 935 struct fuse_init_out *fio; 936 int error; 937 938 ps = puffs_getspecific(pu); 939 940 if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0) 941 DERR(EX_OSERR, "%s: puffs_mount failed", __func__); 942 943 /* 944 * Linux 2.6.34.1 sends theses flags: 945 * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC 946 * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK 947 * 948 * Linux also sets max_readahead at 32 pages (128 kB) 949 * 950 * ps_new_msg() is called with NULL creds, which will 951 * be interpreted as FUSE superuser. 952 */ 953 pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL); 954 fii = GET_INPAYLOAD(ps, pm, fuse_init_in); 955 fii->major = FUSE_KERNEL_VERSION; 956 fii->minor = FUSE_KERNEL_MINOR_VERSION; 957 fii->max_readahead = (unsigned int)(32 * sysconf(_SC_PAGESIZE)); 958 fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC); 959 960 if ((error = xchg_msg(pu, 0, pm, sizeof(*fio), wait_reply)) != 0) 961 DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error); 962 963 fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out); 964 ps->ps_max_readahead = fio->max_readahead; 965 ps->ps_max_write = fio->max_write; 966 967 ps->ps_destroy_msg(pm); 968 969 return; 970 } 971 972 int 973 perfuse_fs_unmount(pu, flags) 974 struct puffs_usermount *pu; 975 int flags; 976 { 977 perfuse_msg_t *pm; 978 struct perfuse_state *ps; 979 puffs_cookie_t opc; 980 int error; 981 982 ps = puffs_getspecific(pu); 983 opc = (puffs_cookie_t)puffs_getroot(pu); 984 985 /* 986 * ps_new_msg() is called with NULL creds, which will 987 * be interpreted as FUSE superuser. 988 */ 989 pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL); 990 991 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0){ 992 DWARN("unmount %s", ps->ps_target); 993 if (!(flags & MNT_FORCE)) 994 goto out; 995 } 996 997 ps->ps_umount(pu); 998 999 if (perfuse_diagflags & PDF_MISC) 1000 DPRINTF("%s unmounted, exit\n", ps->ps_target); 1001 1002 return 0; 1003 out: 1004 ps->ps_destroy_msg(pm); 1005 1006 return error; 1007 } 1008 1009 int 1010 perfuse_fs_statvfs(pu, svfsb) 1011 struct puffs_usermount *pu; 1012 struct statvfs *svfsb; 1013 { 1014 struct perfuse_state *ps; 1015 perfuse_msg_t *pm; 1016 puffs_cookie_t opc; 1017 struct fuse_statfs_out *fso; 1018 int error; 1019 1020 ps = puffs_getspecific(pu); 1021 opc = (puffs_cookie_t)puffs_getroot(pu); 1022 1023 /* 1024 * ps_new_msg() is called with NULL creds, which will 1025 * be interpreted as FUSE superuser. 1026 */ 1027 pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL); 1028 1029 if ((error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply)) != 0) 1030 goto out; 1031 1032 fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out); 1033 svfsb->f_flag = ps->ps_mountflags; 1034 svfsb->f_bsize = fso->st.bsize; 1035 svfsb->f_frsize = fso->st.frsize; 1036 svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize; 1037 svfsb->f_blocks = fso->st.blocks; 1038 svfsb->f_bfree = fso->st.bfree; 1039 svfsb->f_bavail = fso->st.bavail; 1040 svfsb->f_bresvd = fso->st.bfree - fso->st.bavail; 1041 svfsb->f_files = fso->st.files; 1042 svfsb->f_ffree = fso->st.ffree; 1043 svfsb->f_favail = fso->st.ffree;/* files not reserved for root */ 1044 svfsb->f_fresvd = 0; /* files reserved for root */ 1045 1046 svfsb->f_syncreads = ps->ps_syncreads; 1047 svfsb->f_syncwrites = ps->ps_syncwrites; 1048 1049 svfsb->f_asyncreads = ps->ps_asyncreads; 1050 svfsb->f_asyncwrites = ps->ps_asyncwrites; 1051 1052 (void)memcpy(&svfsb->f_fsidx, &ps->ps_fsid, sizeof(ps->ps_fsid)); 1053 svfsb->f_fsid = (unsigned long)ps->ps_fsid; 1054 svfsb->f_namemax = MAXPATHLEN; /* XXX */ 1055 svfsb->f_owner = ps->ps_owner_uid; 1056 1057 (void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN); 1058 1059 if (ps->ps_filesystemtype != NULL) 1060 (void)strlcpy(svfsb->f_fstypename, 1061 ps->ps_filesystemtype, _VFS_NAMELEN); 1062 else 1063 (void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN); 1064 1065 if (ps->ps_source != NULL) 1066 strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN); 1067 else 1068 strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN); 1069 out: 1070 ps->ps_destroy_msg(pm); 1071 1072 return error; 1073 } 1074 1075 int 1076 perfuse_fs_sync(pu, waitfor, pcr) 1077 struct puffs_usermount *pu; 1078 int waitfor; 1079 const struct puffs_cred *pcr; 1080 { 1081 /* 1082 * FUSE does not seem to have a FS sync callback. 1083 * Maybe do not even register this callback 1084 */ 1085 return puffs_fsnop_sync(pu, waitfor, pcr); 1086 } 1087 1088 /* ARGSUSED0 */ 1089 int 1090 perfuse_fs_fhtonode(pu, fid, fidsize, pni) 1091 struct puffs_usermount *pu; 1092 void *fid; 1093 size_t fidsize; 1094 struct puffs_newinfo *pni; 1095 { 1096 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1097 return 0; 1098 } 1099 1100 /* ARGSUSED0 */ 1101 int 1102 perfuse_fs_nodetofh(pu, cookie, fid, fidsize) 1103 struct puffs_usermount *pu; 1104 puffs_cookie_t cookie; 1105 void *fid; 1106 size_t *fidsize; 1107 { 1108 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1109 return 0; 1110 } 1111 1112 #if 0 1113 /* ARGSUSED0 */ 1114 void 1115 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname) 1116 struct puffs_usermount *pu; 1117 int cmd, 1118 puffs_cookie_t *cookie; 1119 int flags; 1120 int namespace; 1121 const char *attrname; 1122 { 1123 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1124 return 0; 1125 } 1126 #endif /* 0 */ 1127 1128 /* ARGSUSED0 */ 1129 void 1130 perfuse_fs_suspend(pu, status) 1131 struct puffs_usermount *pu; 1132 int status; 1133 { 1134 return; 1135 } 1136 1137 1138 1139 int 1140 perfuse_node_lookup(pu, opc, pni, pcn) 1141 struct puffs_usermount *pu; 1142 puffs_cookie_t opc; 1143 struct puffs_newinfo *pni; 1144 const struct puffs_cn *pcn; 1145 { 1146 struct puffs_node *pn; 1147 mode_t mode; 1148 int error; 1149 1150 /* 1151 * Check permissions 1152 */ 1153 switch(pcn->pcn_nameiop) { 1154 case NAMEI_DELETE: /* FALLTHROUGH */ 1155 case NAMEI_RENAME: /* FALLTHROUGH */ 1156 case NAMEI_CREATE: 1157 if (pcn->pcn_flags & NAMEI_ISLASTCN) 1158 mode = PUFFS_VEXEC|PUFFS_VWRITE; 1159 else 1160 mode = PUFFS_VEXEC; 1161 break; 1162 case NAMEI_LOOKUP: /* FALLTHROUGH */ 1163 default: 1164 mode = PUFFS_VEXEC; 1165 break; 1166 } 1167 1168 if ((error = mode_access(opc, pcn->pcn_cred, mode)) != 0) 1169 return error; 1170 1171 /* 1172 * Special case for .. 1173 */ 1174 if (strcmp(pcn->pcn_name, "..") == 0) 1175 pn = PERFUSE_NODE_DATA(opc)->pnd_parent; 1176 else 1177 error = node_lookup_common(pu, (puffs_cookie_t)opc, 1178 pcn->pcn_name, pcn->pcn_cred, &pn); 1179 if (error != 0) 1180 return error; 1181 1182 /* 1183 * Removed node 1184 */ 1185 if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_REMOVED) 1186 return ENOENT; 1187 1188 /* 1189 * Check for sticky bit. Unfortunately there is no way to 1190 * do this before creating the puffs_node, since we require 1191 * this operation to get the node owner. 1192 */ 1193 switch (pcn->pcn_nameiop) { 1194 case NAMEI_DELETE: /* FALLTHROUGH */ 1195 case NAMEI_RENAME: 1196 error = sticky_access(pn, pcn->pcn_cred); 1197 if (error != 0) { 1198 /* 1199 * kernel will never know about it and will 1200 * not reclaim it. The filesystem needs to 1201 * clean it up anyway, therefore mimick a forget. 1202 */ 1203 PERFUSE_NODE_DATA(pn)->pnd_flags |= PND_RECLAIMED; 1204 (void)perfuse_node_reclaim(pu, (puffs_cookie_t)pn); 1205 return error; 1206 } 1207 break; 1208 default: 1209 break; 1210 } 1211 1212 /* 1213 * If that node had a pending reclaim, wipe it out. 1214 */ 1215 PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED; 1216 1217 puffs_newinfo_setcookie(pni, pn); 1218 puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 1219 puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size); 1220 puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); 1221 1222 return error; 1223 } 1224 1225 int 1226 perfuse_node_create(pu, opc, pni, pcn, vap) 1227 struct puffs_usermount *pu; 1228 puffs_cookie_t opc; 1229 struct puffs_newinfo *pni; 1230 const struct puffs_cn *pcn; 1231 const struct vattr *vap; 1232 { 1233 perfuse_msg_t *pm; 1234 struct perfuse_state *ps; 1235 struct fuse_create_in *fci; 1236 struct fuse_entry_out *feo; 1237 struct fuse_open_out *foo; 1238 struct puffs_node *pn; 1239 const char *name; 1240 size_t namelen; 1241 size_t len; 1242 int error; 1243 1244 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1245 return ENOENT; 1246 1247 /* 1248 * If create is unimplemented: Check that it does not 1249 * already exists, and if not, do mknod and open 1250 */ 1251 ps = puffs_getspecific(pu); 1252 if (ps->ps_flags & PS_NO_CREAT) { 1253 error = node_lookup_common(pu, opc, pcn->pcn_name, 1254 pcn->pcn_cred, &pn); 1255 if (error == 0) 1256 return EEXIST; 1257 1258 error = perfuse_node_mknod(pu, opc, pni, pcn, vap); 1259 if (error != 0) 1260 return error; 1261 1262 error = node_lookup_common(pu, opc, pcn->pcn_name, 1263 pcn->pcn_cred, &pn); 1264 if (error != 0) 1265 return error; 1266 1267 /* 1268 * FUSE does the open at create time, while 1269 * NetBSD will open in a subsequent operation. 1270 * We need to open now, in order to retain FUSE 1271 * semantics. The calling process will not get 1272 * a file descriptor before the kernel sends 1273 * the open operation. 1274 */ 1275 opc = (puffs_cookie_t)pn; 1276 error = perfuse_node_open(pu, opc, FWRITE, pcn->pcn_cred); 1277 if (error != 0) 1278 return error; 1279 1280 return 0; 1281 } 1282 1283 name = pcn->pcn_name; 1284 namelen = pcn->pcn_namelen + 1; 1285 len = sizeof(*fci) + namelen; 1286 1287 /* 1288 * flags should use O_WRONLY instead of O_RDWR, but it 1289 * breaks when the caller tries to read from file. 1290 * 1291 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type) 1292 */ 1293 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred); 1294 fci = GET_INPAYLOAD(ps, pm, fuse_create_in); 1295 fci->flags = O_CREAT | O_TRUNC | O_RDWR; 1296 fci->mode = vap->va_mode | VTTOIF(vap->va_type); 1297 fci->umask = 0; /* Seems unused by libfuse */ 1298 (void)strlcpy((char*)(void *)(fci + 1), name, namelen); 1299 1300 len = sizeof(*feo) + sizeof(*foo); 1301 if ((error = xchg_msg(pu, opc, pm, len, wait_reply)) != 0) 1302 goto out; 1303 1304 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 1305 foo = (struct fuse_open_out *)(void *)(feo + 1); 1306 if (feo->nodeid == PERFUSE_UNKNOWN_NODEID) 1307 DERRX(EX_SOFTWARE, "%s: no nodeid", __func__); 1308 1309 /* 1310 * Save the file handle and inode in node private data 1311 * so that we can reuse it later 1312 */ 1313 pn = perfuse_new_pn(pu, name, opc); 1314 perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE); 1315 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 1316 1317 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 1318 pn->pn_va.va_gen = (u_long)(feo->generation); 1319 set_expire((puffs_cookie_t)pn, feo, NULL); 1320 1321 puffs_newinfo_setcookie(pni, pn); 1322 1323 #ifdef PERFUSE_DEBUG 1324 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1325 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x " 1326 "nodeid = 0x%"PRIx64", wfh = 0x%"PRIx64"\n", 1327 __func__, (void *)pn, pcn->pcn_name, 1328 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid, 1329 foo->fh); 1330 #endif 1331 1332 ps->ps_destroy_msg(pm); 1333 1334 return node_mk_common_final(pu, opc, pn, pcn); 1335 1336 out: 1337 ps->ps_destroy_msg(pm); 1338 1339 /* 1340 * create is unimplmented, remember it for later, 1341 * and start over using mknod and open instead. 1342 */ 1343 if (error == ENOSYS) { 1344 ps->ps_flags |= PS_NO_CREAT; 1345 return perfuse_node_create(pu, opc, pni, pcn, vap); 1346 } 1347 1348 return error; 1349 } 1350 1351 1352 int 1353 perfuse_node_mknod(pu, opc, pni, pcn, vap) 1354 struct puffs_usermount *pu; 1355 puffs_cookie_t opc; 1356 struct puffs_newinfo *pni; 1357 const struct puffs_cn *pcn; 1358 const struct vattr *vap; 1359 { 1360 struct perfuse_state *ps; 1361 perfuse_msg_t *pm; 1362 struct fuse_mknod_in *fmi; 1363 const char* path; 1364 size_t len; 1365 1366 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1367 return ENOENT; 1368 1369 /* 1370 * Only superuser can mknod objects other than 1371 * directories, files, socks, fifo and links. 1372 * 1373 * Create an object require -WX permission in the parent directory 1374 */ 1375 switch (vap->va_type) { 1376 case VDIR: /* FALLTHROUGH */ 1377 case VREG: /* FALLTHROUGH */ 1378 case VFIFO: /* FALLTHROUGH */ 1379 case VSOCK: 1380 break; 1381 default: /* VNON, VBLK, VCHR, VBAD */ 1382 if (!puffs_cred_isjuggernaut(pcn->pcn_cred)) 1383 return EACCES; 1384 break; 1385 } 1386 1387 1388 ps = puffs_getspecific(pu); 1389 path = pcn->pcn_name; 1390 len = sizeof(*fmi) + pcn->pcn_namelen + 1; 1391 1392 /* 1393 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type) 1394 */ 1395 pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, pcn->pcn_cred); 1396 fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in); 1397 fmi->mode = vap->va_mode | VTTOIF(vap->va_type); 1398 fmi->rdev = (uint32_t)vap->va_rdev; 1399 fmi->umask = 0; /* Seems unused bu libfuse */ 1400 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 1401 1402 return node_mk_common(pu, opc, pni, pcn, pm); 1403 } 1404 1405 1406 int 1407 perfuse_node_open(pu, opc, mode, pcr) 1408 struct puffs_usermount *pu; 1409 puffs_cookie_t opc; 1410 int mode; 1411 const struct puffs_cred *pcr; 1412 { 1413 struct perfuse_state *ps; 1414 struct perfuse_node_data *pnd; 1415 perfuse_msg_t *pm; 1416 mode_t fmode; 1417 int op; 1418 struct fuse_open_in *foi; 1419 struct fuse_open_out *foo; 1420 struct puffs_node *pn; 1421 int error; 1422 1423 ps = puffs_getspecific(pu); 1424 pn = (struct puffs_node *)opc; 1425 pnd = PERFUSE_NODE_DATA(opc); 1426 pm = NULL; 1427 error = 0; 1428 1429 if (pnd->pnd_flags & PND_REMOVED) 1430 return ENOENT; 1431 1432 if (puffs_pn_getvap(pn)->va_type == VDIR) 1433 op = FUSE_OPENDIR; 1434 else 1435 op = FUSE_OPEN; 1436 1437 /* 1438 * libfuse docs says 1439 * - O_CREAT and O_EXCL should never be set. 1440 * - O_TRUNC may be used if mount option atomic_o_trunc is used XXX 1441 * 1442 * O_APPEND makes no sense since FUSE always sends 1443 * the file offset for write operations. If the 1444 * filesystem uses pwrite(), O_APPEND would cause 1445 * the offset to be ignored and cause file corruption. 1446 */ 1447 mode &= ~(O_CREAT|O_EXCL|O_APPEND); 1448 1449 /* 1450 * Do not open twice, and do not reopen for reading 1451 * if we already have write handle. 1452 */ 1453 if (((mode & FREAD) && (pnd->pnd_flags & PND_RFH)) || 1454 ((mode & FREAD) && (pnd->pnd_flags & PND_WFH)) || 1455 ((mode & FWRITE) && (pnd->pnd_flags & PND_WFH))) { 1456 error = 0; 1457 goto out; 1458 } 1459 1460 /* 1461 * Queue open on a node so that we do not open 1462 * twice. This would be better with read and 1463 * write distinguished. 1464 */ 1465 while (pnd->pnd_flags & PND_INOPEN) 1466 requeue_request(pu, opc, PCQ_OPEN); 1467 pnd->pnd_flags |= PND_INOPEN; 1468 1469 /* 1470 * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE 1471 * to O_RDONLY/O_WRONLY while perserving the other options. 1472 */ 1473 fmode = mode & ~(FREAD|FWRITE); 1474 fmode |= (mode & FWRITE) ? O_RDWR : O_RDONLY; 1475 1476 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr); 1477 foi = GET_INPAYLOAD(ps, pm, fuse_open_in); 1478 foi->flags = fmode; 1479 foi->unused = 0; 1480 1481 if ((error = xchg_msg(pu, opc, pm, sizeof(*foo), wait_reply)) != 0) 1482 goto out; 1483 1484 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out); 1485 1486 /* 1487 * Save the file handle in node private data 1488 * so that we can reuse it later 1489 */ 1490 perfuse_new_fh(opc, foo->fh, mode); 1491 1492 #ifdef PERFUSE_DEBUG 1493 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1494 DPRINTF("%s: opc = %p, file = \"%s\", " 1495 "nodeid = 0x%"PRIx64", %s%sfh = 0x%"PRIx64"\n", 1496 __func__, (void *)opc, perfuse_node_path(opc), 1497 pnd->pnd_nodeid, mode & FREAD ? "r" : "", 1498 mode & FWRITE ? "w" : "", foo->fh); 1499 #endif 1500 1501 out: 1502 if (pm != NULL) 1503 ps->ps_destroy_msg(pm); 1504 1505 pnd->pnd_flags &= ~PND_INOPEN; 1506 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL); 1507 1508 return error; 1509 } 1510 1511 /* ARGSUSED0 */ 1512 int 1513 perfuse_node_close(pu, opc, flags, pcr) 1514 struct puffs_usermount *pu; 1515 puffs_cookie_t opc; 1516 int flags; 1517 const struct puffs_cred *pcr; 1518 { 1519 struct perfuse_node_data *pnd; 1520 1521 pnd = PERFUSE_NODE_DATA(opc); 1522 1523 if (!(pnd->pnd_flags & PND_OPEN)) 1524 return EBADF; 1525 1526 /* 1527 * Actual close is postponed at inactive time. 1528 */ 1529 return 0; 1530 } 1531 1532 int 1533 perfuse_node_access(pu, opc, mode, pcr) 1534 struct puffs_usermount *pu; 1535 puffs_cookie_t opc; 1536 int mode; 1537 const struct puffs_cred *pcr; 1538 { 1539 perfuse_msg_t *pm; 1540 struct perfuse_state *ps; 1541 struct fuse_access_in *fai; 1542 int error; 1543 1544 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1545 return ENOENT; 1546 1547 /* 1548 * If we previously detected the filesystem does not 1549 * implement access(), short-circuit the call and skip 1550 * to libpuffs access() emulation. 1551 */ 1552 ps = puffs_getspecific(pu); 1553 if (ps->ps_flags & PS_NO_ACCESS) { 1554 const struct vattr *vap; 1555 1556 vap = puffs_pn_getvap((struct puffs_node *)opc); 1557 1558 error = puffs_access(IFTOVT(vap->va_mode), 1559 vap->va_mode & ACCESSPERMS, 1560 vap->va_uid, vap->va_gid, 1561 (mode_t)mode, pcr); 1562 return error; 1563 } 1564 1565 /* 1566 * Plain access call 1567 */ 1568 pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr); 1569 fai = GET_INPAYLOAD(ps, pm, fuse_access_in); 1570 fai->mask = 0; 1571 fai->mask |= (mode & PUFFS_VREAD) ? R_OK : 0; 1572 fai->mask |= (mode & PUFFS_VWRITE) ? W_OK : 0; 1573 fai->mask |= (mode & PUFFS_VEXEC) ? X_OK : 0; 1574 1575 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply); 1576 1577 ps->ps_destroy_msg(pm); 1578 1579 /* 1580 * If unimplemented, start over with emulation 1581 */ 1582 if (error == ENOSYS) { 1583 ps->ps_flags |= PS_NO_ACCESS; 1584 return perfuse_node_access(pu, opc, mode, pcr); 1585 } 1586 1587 return error; 1588 } 1589 1590 int 1591 perfuse_node_getattr(pu, opc, vap, pcr) 1592 struct puffs_usermount *pu; 1593 puffs_cookie_t opc; 1594 struct vattr *vap; 1595 const struct puffs_cred *pcr; 1596 { 1597 perfuse_msg_t *pm = NULL; 1598 struct perfuse_state *ps; 1599 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 1600 struct fuse_getattr_in *fgi; 1601 struct fuse_attr_out *fao; 1602 int error = 0; 1603 1604 if (pnd->pnd_flags & PND_REMOVED) 1605 return ENOENT; 1606 1607 /* 1608 * Serialize size access, see comment in perfuse_node_setattr(). 1609 */ 1610 while (pnd->pnd_flags & PND_INRESIZE) 1611 requeue_request(pu, opc, PCQ_RESIZE); 1612 pnd->pnd_flags |= PND_INRESIZE; 1613 1614 ps = puffs_getspecific(pu); 1615 1616 /* 1617 * Check for cached attributes 1618 * This still require serialized access to size. 1619 */ 1620 if (!attr_expired(opc)) { 1621 (void)memcpy(vap, puffs_pn_getvap((struct puffs_node *)opc), 1622 sizeof(*vap)); 1623 goto out; 1624 } 1625 1626 /* 1627 * FUSE_GETATTR_FH must be set in fgi->flags 1628 * if we use for fgi->fh 1629 */ 1630 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr); 1631 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in); 1632 fgi->getattr_flags = 0; 1633 fgi->dummy = 0; 1634 fgi->fh = 0; 1635 1636 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) { 1637 fgi->fh = perfuse_get_fh(opc, FREAD); 1638 fgi->getattr_flags |= FUSE_GETATTR_FH; 1639 } 1640 1641 #ifdef PERFUSE_DEBUG 1642 if (perfuse_diagflags & PDF_RESIZE) 1643 DPRINTF(">> %s %p %" PRIu64 "\n", __func__, (void *)opc, 1644 vap->va_size); 1645 #endif 1646 1647 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0) 1648 goto out; 1649 1650 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1651 1652 #ifdef PERFUSE_DEBUG 1653 if (perfuse_diagflags & PDF_RESIZE) 1654 DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1655 (void *)opc, vap->va_size, fao->attr.size); 1656 #endif 1657 1658 /* 1659 * We set birthtime, flags, filerev,vaflags to 0. 1660 * This seems the best bet, since the information is 1661 * not available from filesystem. 1662 */ 1663 fuse_attr_to_vap(ps, vap, &fao->attr); 1664 set_expire(opc, NULL, fao); 1665 1666 out: 1667 if (pm != NULL) 1668 ps->ps_destroy_msg(pm); 1669 1670 pnd->pnd_flags &= ~PND_INRESIZE; 1671 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL); 1672 1673 return error; 1674 } 1675 1676 int 1677 perfuse_node_setattr(pu, opc, vap, pcr) 1678 struct puffs_usermount *pu; 1679 puffs_cookie_t opc; 1680 const struct vattr *vap; 1681 const struct puffs_cred *pcr; 1682 { 1683 perfuse_msg_t *pm; 1684 uint64_t fh; 1685 struct perfuse_state *ps; 1686 struct perfuse_node_data *pnd; 1687 struct fuse_setattr_in *fsi; 1688 struct fuse_attr_out *fao; 1689 struct vattr *old_va; 1690 int error; 1691 #ifdef PERFUSE_DEBUG 1692 struct vattr *old_vap; 1693 int resize_debug = 0; 1694 #endif 1695 1696 ps = puffs_getspecific(pu); 1697 pnd = PERFUSE_NODE_DATA(opc); 1698 pm = NULL; 1699 1700 /* 1701 * The only operation we can do once the file is removed 1702 * is to resize it, and we can do it only if it is open. 1703 * Do not even send the operation to the filesystem: the 1704 * file is not there anymore. 1705 */ 1706 if (pnd->pnd_flags & PND_REMOVED) { 1707 if (!(pnd->pnd_flags & PND_OPEN)) 1708 return ENOENT; 1709 1710 error = 0; 1711 goto out; 1712 } 1713 1714 old_va = puffs_pn_getvap((struct puffs_node *)opc); 1715 1716 /* 1717 * Check for permission to change size 1718 */ 1719 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1720 (error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0) 1721 return error; 1722 1723 /* 1724 * Check for permission to change dates 1725 */ 1726 if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) || 1727 (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) && 1728 (puffs_access_times(old_va->va_uid, old_va->va_gid, 1729 old_va->va_mode, 0, pcr) != 0)) 1730 return EACCES; 1731 1732 /* 1733 * Check for permission to change owner and group 1734 */ 1735 if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) || 1736 (vap->va_gid != (gid_t)PUFFS_VNOVAL)) && 1737 (puffs_access_chown(old_va->va_uid, old_va->va_gid, 1738 vap->va_uid, vap->va_gid, pcr)) != 0) 1739 return EACCES; 1740 1741 /* 1742 * Check for permission to change permissions 1743 */ 1744 if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && 1745 (puffs_access_chmod(old_va->va_uid, old_va->va_gid, 1746 old_va->va_type, vap->va_mode, pcr)) != 0) 1747 return EACCES; 1748 1749 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr); 1750 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 1751 fsi->valid = 0; 1752 1753 /* 1754 * Get a fh if the node is open for writing 1755 */ 1756 if (pnd->pnd_flags & PND_WFH) { 1757 fh = perfuse_get_fh(opc, FWRITE); 1758 fsi->fh = fh; 1759 fsi->valid |= FUSE_FATTR_FH; 1760 } 1761 1762 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) { 1763 fsi->size = vap->va_size; 1764 fsi->valid |= FUSE_FATTR_SIZE; 1765 1766 /* 1767 * Serialize anything that can touch file size 1768 * to avoid reordered GETATTR and SETATTR. 1769 * Out of order SETATTR can report stale size, 1770 * which will cause the kernel to truncate the file. 1771 */ 1772 while (pnd->pnd_flags & PND_INRESIZE) 1773 requeue_request(pu, opc, PCQ_RESIZE); 1774 pnd->pnd_flags |= PND_INRESIZE; 1775 } 1776 1777 /* 1778 * Setting mtime without atime or vice versa leads to 1779 * dates being reset to Epoch on glusterfs. If one 1780 * is missing, use the old value. 1781 */ 1782 if ((vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) || 1783 (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)) { 1784 1785 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) { 1786 fsi->atime = vap->va_atime.tv_sec; 1787 fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec; 1788 } else { 1789 fsi->atime = old_va->va_atime.tv_sec; 1790 fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec; 1791 } 1792 1793 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { 1794 fsi->mtime = vap->va_mtime.tv_sec; 1795 fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec; 1796 } else { 1797 fsi->mtime = old_va->va_mtime.tv_sec; 1798 fsi->mtimensec = (uint32_t)old_va->va_mtime.tv_nsec; 1799 } 1800 1801 fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_ATIME); 1802 } 1803 1804 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) { 1805 fsi->mode = vap->va_mode; 1806 fsi->valid |= FUSE_FATTR_MODE; 1807 } 1808 1809 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) { 1810 fsi->uid = vap->va_uid; 1811 fsi->valid |= FUSE_FATTR_UID; 1812 } 1813 1814 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) { 1815 fsi->gid = vap->va_gid; 1816 fsi->valid |= FUSE_FATTR_GID; 1817 } 1818 1819 if (pnd->pnd_lock_owner != 0) { 1820 fsi->lock_owner = pnd->pnd_lock_owner; 1821 fsi->valid |= FUSE_FATTR_LOCKOWNER; 1822 } 1823 1824 /* 1825 * ftruncate() sends only va_size, and metadata cache 1826 * flush adds va_atime and va_mtime. Some FUSE 1827 * filesystems will attempt to detect ftruncate by 1828 * checking for FATTR_SIZE being set without 1829 * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE 1830 * 1831 * Try to adapt and remove FATTR_ATIME|FATTR_MTIME 1832 * if we suspect a ftruncate(). 1833 */ 1834 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1835 ((vap->va_mode == (mode_t)PUFFS_VNOVAL) && 1836 (vap->va_uid == (uid_t)PUFFS_VNOVAL) && 1837 (vap->va_gid == (gid_t)PUFFS_VNOVAL))) { 1838 fsi->atime = 0; 1839 fsi->atimensec = 0; 1840 fsi->mtime = 0; 1841 fsi->mtimensec = 0; 1842 fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME); 1843 } 1844 1845 /* 1846 * If nothing remain, discard the operation. 1847 */ 1848 if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME| 1849 FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) { 1850 error = 0; 1851 goto out; 1852 } 1853 1854 #ifdef PERFUSE_DEBUG 1855 old_vap = puffs_pn_getvap((struct puffs_node *)opc); 1856 1857 if ((perfuse_diagflags & PDF_RESIZE) && 1858 (old_vap->va_size != (u_quad_t)PUFFS_VNOVAL)) { 1859 resize_debug = 1; 1860 1861 DPRINTF(">> %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1862 (void *)opc, 1863 puffs_pn_getvap((struct puffs_node *)opc)->va_size, 1864 fsi->size); 1865 } 1866 #endif 1867 1868 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0) 1869 goto out; 1870 1871 /* 1872 * Copy back the new values 1873 */ 1874 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1875 1876 #ifdef PERFUSE_DEBUG 1877 if (resize_debug) 1878 DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1879 (void *)opc, old_vap->va_size, fao->attr.size); 1880 #endif 1881 1882 fuse_attr_to_vap(ps, old_va, &fao->attr); 1883 set_expire(opc, NULL, fao); 1884 1885 out: 1886 if (pm != NULL) 1887 ps->ps_destroy_msg(pm); 1888 1889 if (pnd->pnd_flags & PND_INRESIZE) { 1890 pnd->pnd_flags &= ~PND_INRESIZE; 1891 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL); 1892 } 1893 1894 return error; 1895 } 1896 1897 int 1898 perfuse_node_poll(pu, opc, events) 1899 struct puffs_usermount *pu; 1900 puffs_cookie_t opc; 1901 int *events; 1902 { 1903 struct perfuse_state *ps; 1904 perfuse_msg_t *pm; 1905 struct fuse_poll_in *fpi; 1906 struct fuse_poll_out *fpo; 1907 int error; 1908 1909 ps = puffs_getspecific(pu); 1910 /* 1911 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set. 1912 * 1913 * XXX ps_new_msg() is called with NULL creds, which will 1914 * be interpreted as FUSE superuser. We have no way to 1915 * know the requesting process' credential, but since poll 1916 * is supposed to operate on a file that has been open, 1917 * permission should have already been checked at open time. 1918 * That still may breaks on filesystems that provides odd 1919 * semantics. 1920 */ 1921 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL); 1922 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in); 1923 fpi->fh = perfuse_get_fh(opc, FREAD); 1924 fpi->kh = 0; 1925 fpi->flags = 0; 1926 1927 #ifdef PERFUSE_DEBUG 1928 if (perfuse_diagflags & PDF_FH) 1929 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 1930 __func__, (void *)opc, 1931 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fpi->fh); 1932 #endif 1933 if ((error = xchg_msg(pu, opc, pm, sizeof(*fpo), wait_reply)) != 0) 1934 goto out; 1935 1936 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out); 1937 *events = fpo->revents; 1938 out: 1939 ps->ps_destroy_msg(pm); 1940 1941 return error; 1942 } 1943 1944 /* ARGSUSED0 */ 1945 int 1946 perfuse_node_mmap(pu, opc, flags, pcr) 1947 struct puffs_usermount *pu; 1948 puffs_cookie_t opc; 1949 int flags; 1950 const struct puffs_cred *pcr; 1951 { 1952 /* 1953 * Not implemented anymore in libfuse 1954 */ 1955 return ENOSYS; 1956 } 1957 1958 /* ARGSUSED2 */ 1959 int 1960 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi) 1961 struct puffs_usermount *pu; 1962 puffs_cookie_t opc; 1963 const struct puffs_cred *pcr; 1964 int flags; 1965 off_t offlo; 1966 off_t offhi; 1967 { 1968 int op; 1969 perfuse_msg_t *pm; 1970 struct perfuse_state *ps; 1971 struct perfuse_node_data *pnd; 1972 struct fuse_fsync_in *ffi; 1973 uint64_t fh; 1974 int error; 1975 1976 pm = NULL; 1977 ps = puffs_getspecific(pu); 1978 pnd = PERFUSE_NODE_DATA(opc); 1979 1980 /* 1981 * No need to sync a removed node 1982 */ 1983 if (pnd->pnd_flags & PND_REMOVED) 1984 return 0; 1985 1986 /* 1987 * We do not sync closed files. They have been 1988 * sync at inactive time already. 1989 */ 1990 if (!(pnd->pnd_flags & PND_OPEN)) 1991 return 0; 1992 1993 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR) 1994 op = FUSE_FSYNCDIR; 1995 else /* VREG but also other types such as VLNK */ 1996 op = FUSE_FSYNC; 1997 1998 /* 1999 * Do not sync if there are no change to sync 2000 * XXX remove that test on files if we implement mmap 2001 */ 2002 #ifdef PERFUSE_DEBUG 2003 if (perfuse_diagflags & PDF_SYNC) 2004 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n", 2005 __func__, (void*)opc, perfuse_node_path(opc), 2006 pnd->pnd_flags & PND_DIRTY ? "" : "not "); 2007 #endif 2008 if (!(pnd->pnd_flags & PND_DIRTY)) 2009 return 0; 2010 2011 /* 2012 * It seems NetBSD can call fsync without open first 2013 * glusterfs complain in such a situation: 2014 * "FSYNC() ERR => -1 (Invalid argument)" 2015 * The file will be closed at inactive time. 2016 * 2017 * We open the directory for reading in order to sync. 2018 * This sounds rather counterintuitive, but it works. 2019 */ 2020 if (!(pnd->pnd_flags & PND_WFH)) { 2021 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 2022 goto out; 2023 } 2024 2025 if (op == FUSE_FSYNCDIR) 2026 fh = perfuse_get_fh(opc, FREAD); 2027 else 2028 fh = perfuse_get_fh(opc, FWRITE); 2029 2030 /* 2031 * If fsync_flags is set, meta data should not be flushed. 2032 */ 2033 pm = ps->ps_new_msg(pu, opc, op, sizeof(*ffi), pcr); 2034 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in); 2035 ffi->fh = fh; 2036 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1; 2037 2038 #ifdef PERFUSE_DEBUG 2039 if (perfuse_diagflags & PDF_FH) 2040 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 2041 __func__, (void *)opc, 2042 PERFUSE_NODE_DATA(opc)->pnd_nodeid, ffi->fh); 2043 #endif 2044 2045 if ((error = xchg_msg(pu, opc, pm, 2046 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 2047 goto out; 2048 2049 /* 2050 * No reply beyond fuse_out_header: nothing to do on success 2051 * just clear the dirty flag 2052 */ 2053 pnd->pnd_flags &= ~PND_DIRTY; 2054 2055 #ifdef PERFUSE_DEBUG 2056 if (perfuse_diagflags & PDF_SYNC) 2057 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n", 2058 __func__, (void*)opc, perfuse_node_path(opc)); 2059 #endif 2060 2061 out: 2062 /* 2063 * ENOSYS is not returned to kernel, 2064 */ 2065 if (error == ENOSYS) 2066 error = 0; 2067 2068 if (pm != NULL) 2069 ps->ps_destroy_msg(pm); 2070 2071 return error; 2072 } 2073 2074 /* ARGSUSED0 */ 2075 int 2076 perfuse_node_seek(pu, opc, oldoff, newoff, pcr) 2077 struct puffs_usermount *pu; 2078 puffs_cookie_t opc; 2079 off_t oldoff; 2080 off_t newoff; 2081 const struct puffs_cred *pcr; 2082 { 2083 return 0; 2084 } 2085 2086 int 2087 perfuse_node_remove(pu, opc, targ, pcn) 2088 struct puffs_usermount *pu; 2089 puffs_cookie_t opc; 2090 puffs_cookie_t targ; 2091 const struct puffs_cn *pcn; 2092 { 2093 struct perfuse_state *ps; 2094 struct perfuse_node_data *pnd; 2095 perfuse_msg_t *pm; 2096 char *path; 2097 const char *name; 2098 size_t len; 2099 int error; 2100 2101 pnd = PERFUSE_NODE_DATA(opc); 2102 2103 if ((pnd->pnd_flags & PND_REMOVED) || 2104 (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED)) 2105 return ENOENT; 2106 2107 #ifdef PERFUSE_DEBUG 2108 if (targ == NULL) 2109 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__); 2110 2111 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 2112 DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n", 2113 __func__, (void *)opc, (void *)targ, pcn->pcn_name); 2114 #endif 2115 /* 2116 * Await for all operations on the deleted node to drain, 2117 * as the filesystem may be confused to have it deleted 2118 * during a getattr 2119 */ 2120 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 2121 requeue_request(pu, targ, PCQ_AFTERXCHG); 2122 2123 ps = puffs_getspecific(pu); 2124 pnd = PERFUSE_NODE_DATA(opc); 2125 name = pcn->pcn_name; 2126 len = pcn->pcn_namelen + 1; 2127 2128 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred); 2129 path = _GET_INPAYLOAD(ps, pm, char *); 2130 (void)strlcpy(path, name, len); 2131 2132 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2133 goto out; 2134 2135 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2136 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN)) 2137 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 2138 2139 /* 2140 * The parent directory needs a sync 2141 */ 2142 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2143 2144 #ifdef PERFUSE_DEBUG 2145 if (perfuse_diagflags & PDF_FILENAME) 2146 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n", 2147 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid, 2148 pcn->pcn_name); 2149 #endif 2150 out: 2151 ps->ps_destroy_msg(pm); 2152 2153 return error; 2154 } 2155 2156 int 2157 perfuse_node_link(pu, opc, targ, pcn) 2158 struct puffs_usermount *pu; 2159 puffs_cookie_t opc; 2160 puffs_cookie_t targ; 2161 const struct puffs_cn *pcn; 2162 { 2163 struct perfuse_state *ps; 2164 perfuse_msg_t *pm; 2165 const char *name; 2166 size_t len; 2167 struct puffs_node *pn; 2168 struct fuse_link_in *fli; 2169 int error; 2170 2171 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2172 return ENOENT; 2173 2174 ps = puffs_getspecific(pu); 2175 pn = (struct puffs_node *)targ; 2176 name = pcn->pcn_name; 2177 len = sizeof(*fli) + pcn->pcn_namelen + 1; 2178 2179 pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred); 2180 fli = GET_INPAYLOAD(ps, pm, fuse_link_in); 2181 fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_nodeid; 2182 (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli)); 2183 2184 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply); 2185 2186 ps->ps_destroy_msg(pm); 2187 2188 return error; 2189 } 2190 2191 int 2192 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ) 2193 struct puffs_usermount *pu; 2194 puffs_cookie_t opc; 2195 puffs_cookie_t src; 2196 const struct puffs_cn *pcn_src; 2197 puffs_cookie_t targ_dir; 2198 puffs_cookie_t targ; 2199 const struct puffs_cn *pcn_targ; 2200 { 2201 struct perfuse_state *ps; 2202 perfuse_msg_t *pm; 2203 struct fuse_rename_in *fri; 2204 const char *newname; 2205 const char *oldname; 2206 char *np; 2207 int error; 2208 size_t len; 2209 size_t newname_len; 2210 size_t oldname_len; 2211 2212 if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) || 2213 (PERFUSE_NODE_DATA(src)->pnd_flags & PND_REMOVED) || 2214 (PERFUSE_NODE_DATA(targ_dir)->pnd_flags & PND_REMOVED)) 2215 return ENOENT; 2216 2217 /* 2218 * Await for all operations on the deleted node to drain, 2219 * as the filesystem may be confused to have it deleted 2220 * during a getattr 2221 */ 2222 if ((struct puffs_node *)targ != NULL) { 2223 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 2224 requeue_request(pu, targ, PCQ_AFTERXCHG); 2225 } else { 2226 while (PERFUSE_NODE_DATA(src)->pnd_flags & PND_INXCHG) 2227 requeue_request(pu, src, PCQ_AFTERXCHG); 2228 } 2229 2230 ps = puffs_getspecific(pu); 2231 newname = pcn_targ->pcn_name; 2232 newname_len = pcn_targ->pcn_namelen + 1; 2233 oldname = pcn_src->pcn_name; 2234 oldname_len = pcn_src->pcn_namelen + 1; 2235 2236 len = sizeof(*fri) + oldname_len + newname_len; 2237 pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_targ->pcn_cred); 2238 fri = GET_INPAYLOAD(ps, pm, fuse_rename_in); 2239 fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid; 2240 np = (char *)(void *)(fri + 1); 2241 (void)strlcpy(np, oldname, oldname_len); 2242 np += oldname_len; 2243 (void)strlcpy(np, newname, newname_len); 2244 2245 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2246 goto out; 2247 2248 if (opc != targ_dir) { 2249 struct perfuse_node_data *srcdir_pnd; 2250 struct perfuse_node_data *dstdir_pnd; 2251 struct perfuse_node_data *src_pnd; 2252 2253 srcdir_pnd = PERFUSE_NODE_DATA(opc); 2254 dstdir_pnd = PERFUSE_NODE_DATA(targ_dir); 2255 src_pnd = PERFUSE_NODE_DATA(src); 2256 2257 TAILQ_REMOVE(&srcdir_pnd->pnd_children, src_pnd, pnd_next); 2258 TAILQ_INSERT_TAIL(&dstdir_pnd->pnd_children, src_pnd, pnd_next); 2259 2260 srcdir_pnd->pnd_childcount--; 2261 dstdir_pnd->pnd_childcount++; 2262 2263 src_pnd->pnd_parent = targ_dir; 2264 2265 PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY; 2266 } 2267 2268 (void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, newname, MAXPATHLEN); 2269 2270 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2271 2272 if ((struct puffs_node *)targ != NULL) 2273 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2274 2275 #ifdef PERFUSE_DEBUG 2276 if (perfuse_diagflags & PDF_FILENAME) 2277 DPRINTF("%s: nodeid = 0x%"PRIx64" file = \"%s\" renamed \"%s\" " 2278 "nodeid = 0x%"PRIx64" -> nodeid = 0x%"PRIx64" \"%s\"\n", 2279 __func__, PERFUSE_NODE_DATA(src)->pnd_nodeid, 2280 pcn_src->pcn_name, pcn_targ->pcn_name, 2281 PERFUSE_NODE_DATA(opc)->pnd_nodeid, 2282 PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid, 2283 perfuse_node_path(targ_dir)); 2284 #endif 2285 2286 out: 2287 if (pm != NULL) 2288 ps->ps_destroy_msg(pm); 2289 2290 return error; 2291 } 2292 2293 int 2294 perfuse_node_mkdir(pu, opc, pni, pcn, vap) 2295 struct puffs_usermount *pu; 2296 puffs_cookie_t opc; 2297 struct puffs_newinfo *pni; 2298 const struct puffs_cn *pcn; 2299 const struct vattr *vap; 2300 { 2301 struct perfuse_state *ps; 2302 perfuse_msg_t *pm; 2303 struct fuse_mkdir_in *fmi; 2304 const char *path; 2305 size_t len; 2306 2307 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2308 return ENOENT; 2309 2310 ps = puffs_getspecific(pu); 2311 path = pcn->pcn_name; 2312 len = sizeof(*fmi) + pcn->pcn_namelen + 1; 2313 2314 pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred); 2315 fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in); 2316 fmi->mode = vap->va_mode; 2317 fmi->umask = 0; /* Seems unused by libfuse? */ 2318 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 2319 2320 return node_mk_common(pu, opc, pni, pcn, pm); 2321 } 2322 2323 2324 int 2325 perfuse_node_rmdir(pu, opc, targ, pcn) 2326 struct puffs_usermount *pu; 2327 puffs_cookie_t opc; 2328 puffs_cookie_t targ; 2329 const struct puffs_cn *pcn; 2330 { 2331 struct perfuse_state *ps; 2332 struct perfuse_node_data *pnd; 2333 perfuse_msg_t *pm; 2334 char *path; 2335 const char *name; 2336 size_t len; 2337 int error; 2338 2339 pnd = PERFUSE_NODE_DATA(opc); 2340 if (pnd->pnd_flags & PND_REMOVED) 2341 return ENOENT; 2342 2343 /* 2344 * Await for all operations on the deleted node to drain, 2345 * as the filesystem may be confused to have it deleted 2346 * during a getattr 2347 */ 2348 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 2349 requeue_request(pu, targ, PCQ_AFTERXCHG); 2350 2351 ps = puffs_getspecific(pu); 2352 name = pcn->pcn_name; 2353 len = pcn->pcn_namelen + 1; 2354 2355 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred); 2356 path = _GET_INPAYLOAD(ps, pm, char *); 2357 (void)strlcpy(path, name, len); 2358 2359 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2360 goto out; 2361 2362 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2363 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN)) 2364 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 2365 2366 /* 2367 * The parent directory needs a sync 2368 */ 2369 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2370 2371 #ifdef PERFUSE_DEBUG 2372 if (perfuse_diagflags & PDF_FILENAME) 2373 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n", 2374 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid, 2375 perfuse_node_path(targ)); 2376 #endif 2377 out: 2378 ps->ps_destroy_msg(pm); 2379 2380 return error; 2381 } 2382 2383 /* vap is unused */ 2384 /* ARGSUSED4 */ 2385 int 2386 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target) 2387 struct puffs_usermount *pu; 2388 puffs_cookie_t opc; 2389 struct puffs_newinfo *pni; 2390 const struct puffs_cn *pcn_src; 2391 const struct vattr *vap; 2392 const char *link_target; 2393 { 2394 struct perfuse_state *ps; 2395 perfuse_msg_t *pm; 2396 char *np; 2397 const char *path; 2398 size_t path_len; 2399 size_t linkname_len; 2400 size_t len; 2401 2402 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2403 return ENOENT; 2404 2405 ps = puffs_getspecific(pu); 2406 path = pcn_src->pcn_name; 2407 path_len = pcn_src->pcn_namelen + 1; 2408 linkname_len = strlen(link_target) + 1; 2409 len = path_len + linkname_len; 2410 2411 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred); 2412 np = _GET_INPAYLOAD(ps, pm, char *); 2413 (void)strlcpy(np, path, path_len); 2414 np += path_len; 2415 (void)strlcpy(np, link_target, linkname_len); 2416 2417 return node_mk_common(pu, opc, pni, pcn_src, pm); 2418 } 2419 2420 /* ARGSUSED4 */ 2421 int 2422 perfuse_node_readdir(pu, opc, dent, readoff, 2423 reslen, pcr, eofflag, cookies, ncookies) 2424 struct puffs_usermount *pu; 2425 puffs_cookie_t opc; 2426 struct dirent *dent; 2427 off_t *readoff; 2428 size_t *reslen; 2429 const struct puffs_cred *pcr; 2430 int *eofflag; 2431 off_t *cookies; 2432 size_t *ncookies; 2433 { 2434 perfuse_msg_t *pm; 2435 uint64_t fh; 2436 struct perfuse_state *ps; 2437 struct perfuse_node_data *pnd; 2438 struct fuse_read_in *fri; 2439 struct fuse_out_header *foh; 2440 struct fuse_dirent *fd; 2441 size_t foh_len; 2442 int error; 2443 size_t fd_maxlen; 2444 2445 pm = NULL; 2446 error = 0; 2447 ps = puffs_getspecific(pu); 2448 2449 /* 2450 * readdir state is kept at node level, and several readdir 2451 * requests can be issued at the same time on the same node. 2452 * We need to queue requests so that only one is in readdir 2453 * code at the same time. 2454 */ 2455 pnd = PERFUSE_NODE_DATA(opc); 2456 while (pnd->pnd_flags & PND_INREADDIR) 2457 requeue_request(pu, opc, PCQ_READDIR); 2458 pnd->pnd_flags |= PND_INREADDIR; 2459 2460 #ifdef PERFUSE_DEBUG 2461 if (perfuse_diagflags & PDF_READDIR) 2462 DPRINTF("%s: READDIR opc = %p enter critical section\n", 2463 __func__, (void *)opc); 2464 #endif 2465 /* 2466 * Re-initialize pnd->pnd_fd_cookie on the first readdir for a node 2467 */ 2468 if (*readoff == 0) 2469 pnd->pnd_fd_cookie = 0; 2470 2471 /* 2472 * Do we already have the data bufered? 2473 */ 2474 if (pnd->pnd_dirent != NULL) 2475 goto out; 2476 pnd->pnd_dirent_len = 0; 2477 2478 /* 2479 * It seems NetBSD can call readdir without open first 2480 * libfuse will crash if it is done that way, hence open first. 2481 */ 2482 if (!(pnd->pnd_flags & PND_OPEN)) { 2483 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 2484 goto out; 2485 } 2486 2487 fh = perfuse_get_fh(opc, FREAD); 2488 2489 #ifdef PERFUSE_DEBUG 2490 if (perfuse_diagflags & PDF_FH) 2491 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", rfh = 0x%"PRIx64"\n", 2492 __func__, (void *)opc, 2493 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fh); 2494 #endif 2495 2496 pnd->pnd_all_fd = NULL; 2497 pnd->pnd_all_fd_len = 0; 2498 fd_maxlen = ps->ps_max_readahead - sizeof(*foh); 2499 2500 do { 2501 size_t fd_len; 2502 char *afdp; 2503 2504 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr); 2505 2506 /* 2507 * read_flags, lock_owner and flags are unused in libfuse 2508 */ 2509 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2510 fri->fh = fh; 2511 fri->offset = pnd->pnd_fd_cookie; 2512 fri->size = (uint32_t)fd_maxlen; 2513 fri->read_flags = 0; 2514 fri->lock_owner = 0; 2515 fri->flags = 0; 2516 2517 if ((error = xchg_msg(pu, opc, pm, 2518 UNSPEC_REPLY_LEN, wait_reply)) != 0) 2519 goto out; 2520 2521 /* 2522 * There are many puffs_framebufs calls later, 2523 * therefore foh will not be valid for a long time. 2524 * Just get the length and forget it. 2525 */ 2526 foh = GET_OUTHDR(ps, pm); 2527 foh_len = foh->len; 2528 2529 /* 2530 * Empty read: we reached the end of the buffer. 2531 */ 2532 if (foh_len == sizeof(*foh)) { 2533 *eofflag = 1; 2534 break; 2535 } 2536 2537 /* 2538 * Check for corrupted message. 2539 */ 2540 if (foh_len < sizeof(*foh) + sizeof(*fd)) { 2541 DWARNX("readdir reply too short"); 2542 error = EIO; 2543 goto out; 2544 } 2545 2546 2547 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent); 2548 fd_len = foh_len - sizeof(*foh); 2549 2550 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd, 2551 pnd->pnd_all_fd_len + fd_len); 2552 if (pnd->pnd_all_fd == NULL) 2553 DERR(EX_OSERR, "%s: malloc failed", __func__); 2554 2555 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len; 2556 (void)memcpy(afdp, fd, fd_len); 2557 2558 pnd->pnd_all_fd_len += fd_len; 2559 2560 /* 2561 * The fd->off field is used as a cookie for 2562 * resuming the next readdir() where this one was left. 2563 */ 2564 pnd->pnd_fd_cookie = readdir_last_cookie(fd, fd_len); 2565 2566 ps->ps_destroy_msg(pm); 2567 pm = NULL; 2568 } while (1 /* CONSTCOND */); 2569 2570 if (pnd->pnd_all_fd != NULL) { 2571 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd, 2572 pnd->pnd_all_fd_len) == -1) 2573 error = EIO; 2574 } 2575 2576 out: 2577 if (pnd->pnd_all_fd != NULL) { 2578 free(pnd->pnd_all_fd); 2579 pnd->pnd_all_fd = NULL; 2580 pnd->pnd_all_fd_len = 0; 2581 } 2582 2583 if (pm != NULL) 2584 ps->ps_destroy_msg(pm); 2585 2586 if (error == 0) 2587 error = readdir_buffered(opc, dent, readoff, reslen); 2588 2589 /* 2590 * Schedule queued readdir requests 2591 */ 2592 pnd->pnd_flags &= ~PND_INREADDIR; 2593 (void)dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL); 2594 2595 #ifdef PERFUSE_DEBUG 2596 if (perfuse_diagflags & PDF_READDIR) 2597 DPRINTF("%s: READDIR opc = %p exit critical section\n", 2598 __func__, (void *)opc); 2599 #endif 2600 2601 return error; 2602 } 2603 2604 int 2605 perfuse_node_readlink(pu, opc, pcr, linkname, linklen) 2606 struct puffs_usermount *pu; 2607 puffs_cookie_t opc; 2608 const struct puffs_cred *pcr; 2609 char *linkname; 2610 size_t *linklen; 2611 { 2612 struct perfuse_state *ps; 2613 perfuse_msg_t *pm; 2614 int error; 2615 size_t len; 2616 struct fuse_out_header *foh; 2617 2618 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2619 return ENOENT; 2620 2621 ps = puffs_getspecific(pu); 2622 2623 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr); 2624 2625 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2626 goto out; 2627 2628 foh = GET_OUTHDR(ps, pm); 2629 len = foh->len - sizeof(*foh); 2630 if (len > *linklen) 2631 DERRX(EX_PROTOCOL, "path len = %zd too long", len); 2632 if (len == 0) 2633 DERRX(EX_PROTOCOL, "path len = %zd too short", len); 2634 2635 /* 2636 * FUSE filesystems return a NUL terminated string, we 2637 * do not want to trailing \0 2638 */ 2639 *linklen = len - 1; 2640 (void)memcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len); 2641 out: 2642 ps->ps_destroy_msg(pm); 2643 2644 return error; 2645 } 2646 2647 int 2648 perfuse_node_reclaim(pu, opc) 2649 struct puffs_usermount *pu; 2650 puffs_cookie_t opc; 2651 { 2652 struct perfuse_state *ps; 2653 perfuse_msg_t *pm; 2654 struct perfuse_node_data *pnd; 2655 struct fuse_forget_in *ffi; 2656 struct puffs_node *pn; 2657 struct puffs_node *pn_root; 2658 2659 ps = puffs_getspecific(pu); 2660 pnd = PERFUSE_NODE_DATA(opc); 2661 2662 /* 2663 * Never forget the root. 2664 */ 2665 if (pnd->pnd_nodeid == FUSE_ROOT_ID) 2666 return 0; 2667 2668 pnd->pnd_flags |= PND_RECLAIMED; 2669 2670 #ifdef PERFUSE_DEBUG 2671 if (perfuse_diagflags & PDF_RECLAIM) 2672 DPRINTF("%s (nodeid %"PRId64") reclaimed\n", 2673 perfuse_node_path(opc), pnd->pnd_nodeid); 2674 #endif 2675 2676 pn_root = puffs_getroot(pu); 2677 pn = (struct puffs_node *)opc; 2678 while (pn != pn_root) { 2679 struct puffs_node *parent_pn; 2680 2681 pnd = PERFUSE_NODE_DATA(pn); 2682 2683 #ifdef PERFUSE_DEBUG 2684 if (perfuse_diagflags & PDF_RECLAIM) 2685 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, " 2686 "has childcount %d %s%s%s%s, pending ops:%s%s%s\n", 2687 perfuse_node_path((puffs_cookie_t)pn), pnd->pnd_nodeid, 2688 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ", 2689 pnd->pnd_childcount, 2690 pnd->pnd_flags & PND_OPEN ? "open " : "not open", 2691 pnd->pnd_flags & PND_RFH ? "r" : "", 2692 pnd->pnd_flags & PND_WFH ? "w" : "", 2693 pnd->pnd_flags & PND_BUSY ? "" : " none", 2694 pnd->pnd_flags & PND_INREADDIR ? " readdir" : "", 2695 pnd->pnd_flags & PND_INWRITE ? " write" : "", 2696 pnd->pnd_flags & PND_INOPEN ? " open" : ""); 2697 #endif 2698 2699 if (!(pnd->pnd_flags & PND_RECLAIMED) || 2700 (pnd->pnd_childcount != 0)) 2701 return 0; 2702 2703 #ifdef PERFUSE_DEBUG 2704 if ((pnd->pnd_flags & PND_OPEN) || 2705 !TAILQ_EMPTY(&pnd->pnd_pcq)) 2706 DERRX(EX_SOFTWARE, "%s: opc = %p: still open", 2707 __func__, (void *)opc); 2708 2709 if ((pnd->pnd_flags & PND_BUSY) || 2710 !TAILQ_EMPTY(&pnd->pnd_pcq)) 2711 DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations", 2712 __func__, (void *)opc); 2713 #endif 2714 2715 /* 2716 * Send the FORGET message 2717 * 2718 * ps_new_msg() is called with NULL creds, which will 2719 * be interpreted as FUSE superuser. This is obviously 2720 * fine since we operate with kernel creds here. 2721 */ 2722 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET, 2723 sizeof(*ffi), NULL); 2724 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in); 2725 ffi->nlookup = pnd->pnd_nlookup; 2726 2727 /* 2728 * No reply is expected, pm is freed in xchg_msg 2729 */ 2730 (void)xchg_msg(pu, (puffs_cookie_t)pn, 2731 pm, UNSPEC_REPLY_LEN, no_reply); 2732 2733 parent_pn = pnd->pnd_parent; 2734 2735 perfuse_destroy_pn(pn); 2736 2737 pn = parent_pn; 2738 } 2739 2740 return 0; 2741 } 2742 2743 int 2744 perfuse_node_inactive(pu, opc) 2745 struct puffs_usermount *pu; 2746 puffs_cookie_t opc; 2747 { 2748 struct perfuse_state *ps; 2749 struct perfuse_node_data *pnd; 2750 2751 ps = puffs_getspecific(pu); 2752 pnd = PERFUSE_NODE_DATA(opc); 2753 2754 if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED))) 2755 return 0; 2756 2757 /* 2758 * Make sure all operation are finished 2759 * There can be an ongoing write. Other 2760 * operation wait for all data before 2761 * the close/inactive. 2762 */ 2763 while (pnd->pnd_flags & PND_INWRITE) 2764 requeue_request(pu, opc, PCQ_AFTERWRITE); 2765 2766 /* 2767 * The inactive operation may be cancelled. 2768 * If no open is in progress, set PND_INOPEN 2769 * so that a new open will be queued. 2770 */ 2771 if (pnd->pnd_flags & PND_INOPEN) 2772 return 0; 2773 2774 pnd->pnd_flags |= PND_INOPEN; 2775 2776 /* 2777 * Sync data 2778 */ 2779 if (pnd->pnd_flags & PND_DIRTY) 2780 (void)perfuse_node_fsync(pu, opc, NULL, 0, 0, 0); 2781 2782 /* 2783 * Close handles 2784 */ 2785 if (pnd->pnd_flags & PND_WFH) 2786 (void)perfuse_node_close_common(pu, opc, FWRITE); 2787 2788 if (pnd->pnd_flags & PND_RFH) 2789 (void)perfuse_node_close_common(pu, opc, FREAD); 2790 2791 /* 2792 * This will cause a reclaim to be sent 2793 */ 2794 if (pnd->pnd_flags & PND_REMOVED) 2795 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 2796 2797 /* 2798 * Schedule awaiting operations 2799 */ 2800 pnd->pnd_flags &= ~PND_INOPEN; 2801 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL); 2802 2803 return 0; 2804 } 2805 2806 2807 /* ARGSUSED0 */ 2808 int 2809 perfuse_node_print(pu, opc) 2810 struct puffs_usermount *pu; 2811 puffs_cookie_t opc; 2812 { 2813 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2814 return 0; 2815 } 2816 2817 /* ARGSUSED0 */ 2818 int 2819 perfuse_node_pathconf(pu, opc, name, retval) 2820 struct puffs_usermount *pu; 2821 puffs_cookie_t opc; 2822 int name; 2823 int *retval; 2824 { 2825 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2826 return 0; 2827 } 2828 2829 int 2830 perfuse_node_advlock(pu, opc, id, op, fl, flags) 2831 struct puffs_usermount *pu; 2832 puffs_cookie_t opc; 2833 void *id; 2834 int op; 2835 struct flock *fl; 2836 int flags; 2837 { 2838 struct perfuse_state *ps; 2839 int fop; 2840 perfuse_msg_t *pm; 2841 uint64_t fh; 2842 struct fuse_lk_in *fli; 2843 struct fuse_out_header *foh; 2844 struct fuse_lk_out *flo; 2845 uint32_t owner; 2846 size_t len; 2847 int error; 2848 2849 /* 2850 * Make sure we do have a filehandle, as the FUSE filesystem 2851 * expect one. E.g.: if we provide none, GlusterFS logs an error 2852 * "0-glusterfs-fuse: xl is NULL" 2853 * 2854 * We need the read file handle if the file is open read only, 2855 * in order to support shared locks on read-only files. 2856 * NB: The kernel always sends advlock for read-only 2857 * files at exit time when the process used lock, see 2858 * sys_exit -> exit1 -> fd_free -> fd_close -> VOP_ADVLOCK 2859 */ 2860 if ((fh = perfuse_get_fh(opc, FREAD)) == FUSE_UNKNOWN_FH) 2861 return EBADF; 2862 2863 ps = puffs_getspecific(pu); 2864 2865 if (op == F_GETLK) 2866 fop = FUSE_GETLK; 2867 else 2868 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK; 2869 2870 /* 2871 * XXX ps_new_msg() is called with NULL creds, which will 2872 * be interpreted as FUSE superuser. We have no way to 2873 * know the requesting process' credential, but since advlock() 2874 * is supposed to operate on a file that has been open(), 2875 * permission should have already been checked at open() time. 2876 */ 2877 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL); 2878 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in); 2879 fli->fh = fh; 2880 fli->owner = (uint64_t)(vaddr_t)id; 2881 fli->lk.start = fl->l_start; 2882 fli->lk.end = fl->l_start + fl->l_len; 2883 fli->lk.type = fl->l_type; 2884 fli->lk.pid = fl->l_pid; 2885 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0; 2886 2887 owner = (uint64_t)(vaddr_t)id; 2888 2889 #ifdef PERFUSE_DEBUG 2890 if (perfuse_diagflags & PDF_FH) 2891 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 2892 __func__, (void *)opc, 2893 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fli->fh); 2894 #endif 2895 2896 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2897 goto out; 2898 2899 foh = GET_OUTHDR(ps, pm); 2900 len = foh->len - sizeof(*foh); 2901 2902 /* 2903 * Save or clear the lock 2904 */ 2905 switch (op) { 2906 case F_GETLK: 2907 if (len != sizeof(*flo)) 2908 DERRX(EX_SOFTWARE, 2909 "%s: Unexpected lock reply len %zd", 2910 __func__, len); 2911 2912 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out); 2913 fl->l_start = flo->lk.start; 2914 fl->l_len = flo->lk.end - flo->lk.start; 2915 fl->l_pid = flo->lk.pid; 2916 fl->l_type = flo->lk.type; 2917 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */ 2918 2919 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid; 2920 break; 2921 case F_UNLCK: 2922 owner = 0; 2923 /* FALLTHROUGH */ 2924 case F_SETLK: 2925 /* FALLTHROUGH */ 2926 case F_SETLKW: 2927 if (error != 0) 2928 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = owner; 2929 2930 if (len != 0) 2931 DERRX(EX_SOFTWARE, 2932 "%s: Unexpected unlock reply len %zd", 2933 __func__, len); 2934 2935 break; 2936 default: 2937 DERRX(EX_SOFTWARE, "%s: Unexpected op %d", __func__, op); 2938 break; 2939 } 2940 2941 out: 2942 ps->ps_destroy_msg(pm); 2943 2944 return error; 2945 } 2946 2947 int 2948 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag) 2949 struct puffs_usermount *pu; 2950 puffs_cookie_t opc; 2951 uint8_t *buf; 2952 off_t offset; 2953 size_t *resid; 2954 const struct puffs_cred *pcr; 2955 int ioflag; 2956 { 2957 struct perfuse_state *ps; 2958 struct perfuse_node_data *pnd; 2959 const struct vattr *vap; 2960 perfuse_msg_t *pm; 2961 struct fuse_read_in *fri; 2962 struct fuse_out_header *foh; 2963 size_t readen; 2964 int error; 2965 2966 ps = puffs_getspecific(pu); 2967 pnd = PERFUSE_NODE_DATA(opc); 2968 vap = puffs_pn_getvap((struct puffs_node *)opc); 2969 pm = NULL; 2970 2971 /* 2972 * NetBSD turns that into a getdents(2) output 2973 * We just do a EISDIR as this feature is of little use. 2974 */ 2975 if (vap->va_type == VDIR) 2976 return EISDIR; 2977 2978 if ((u_quad_t)offset + *resid > vap->va_size) 2979 DWARNX("%s %p read %lld@%zu beyond EOF %" PRIu64 "\n", 2980 __func__, (void *)opc, (long long)offset, 2981 *resid, vap->va_size); 2982 2983 do { 2984 size_t max_read; 2985 2986 max_read = ps->ps_max_readahead - sizeof(*foh); 2987 /* 2988 * flags may be set to FUSE_READ_LOCKOWNER 2989 * if lock_owner is provided. 2990 */ 2991 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr); 2992 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2993 fri->fh = perfuse_get_fh(opc, FREAD); 2994 fri->offset = offset; 2995 fri->size = (uint32_t)MIN(*resid, max_read); 2996 fri->read_flags = 0; /* XXX Unused by libfuse? */ 2997 fri->lock_owner = pnd->pnd_lock_owner; 2998 fri->flags = 0; 2999 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0; 3000 3001 #ifdef PERFUSE_DEBUG 3002 if (perfuse_diagflags & PDF_FH) 3003 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 3004 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh); 3005 #endif 3006 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply); 3007 3008 if (error != 0) 3009 goto out; 3010 3011 foh = GET_OUTHDR(ps, pm); 3012 readen = foh->len - sizeof(*foh); 3013 3014 #ifdef PERFUSE_DEBUG 3015 if (readen > *resid) 3016 DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd", 3017 __func__, readen); 3018 #endif 3019 3020 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen); 3021 3022 buf += readen; 3023 offset += readen; 3024 *resid -= readen; 3025 3026 ps->ps_destroy_msg(pm); 3027 pm = NULL; 3028 } while ((*resid != 0) && (readen != 0)); 3029 3030 if (ioflag & (IO_SYNC|IO_DSYNC)) 3031 ps->ps_syncreads++; 3032 else 3033 ps->ps_asyncreads++; 3034 3035 out: 3036 if (pm != NULL) 3037 ps->ps_destroy_msg(pm); 3038 3039 return error; 3040 } 3041 3042 int 3043 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag) 3044 struct puffs_usermount *pu; 3045 puffs_cookie_t opc; 3046 uint8_t *buf; 3047 off_t offset; 3048 size_t *resid; 3049 const struct puffs_cred *pcr; 3050 int ioflag; 3051 { 3052 struct perfuse_state *ps; 3053 struct perfuse_node_data *pnd; 3054 struct vattr *vap; 3055 perfuse_msg_t *pm; 3056 struct fuse_write_in *fwi; 3057 struct fuse_write_out *fwo; 3058 size_t data_len; 3059 size_t payload_len; 3060 size_t written; 3061 int inresize; 3062 int error; 3063 3064 ps = puffs_getspecific(pu); 3065 pnd = PERFUSE_NODE_DATA(opc); 3066 vap = puffs_pn_getvap((struct puffs_node *)opc); 3067 written = 0; 3068 inresize = 0; 3069 pm = NULL; 3070 3071 if (vap->va_type == VDIR) 3072 return EISDIR; 3073 3074 /* 3075 * We need to queue write requests in order to avoid 3076 * dequeueing PCQ_AFTERWRITE when there are pending writes. 3077 */ 3078 while (pnd->pnd_flags & PND_INWRITE) 3079 requeue_request(pu, opc, PCQ_WRITE); 3080 pnd->pnd_flags |= PND_INWRITE; 3081 3082 /* 3083 * Serialize size access, see comment in perfuse_node_setattr(). 3084 */ 3085 if ((u_quad_t)offset + *resid > vap->va_size) { 3086 while (pnd->pnd_flags & PND_INRESIZE) 3087 requeue_request(pu, opc, PCQ_RESIZE); 3088 pnd->pnd_flags |= PND_INRESIZE; 3089 inresize = 1; 3090 } 3091 3092 /* 3093 * append flag: re-read the file size so that 3094 * we get the latest value. 3095 */ 3096 if (ioflag & PUFFS_IO_APPEND) { 3097 DWARNX("%s: PUFFS_IO_APPEND set, untested code", __func__); 3098 3099 if ((error = perfuse_node_getattr(pu, opc, vap, pcr)) != 0) 3100 goto out; 3101 3102 offset = vap->va_size; 3103 } 3104 3105 pm = NULL; 3106 3107 #ifdef PERFUSE_DEBUG 3108 if (perfuse_diagflags & PDF_RESIZE) 3109 DPRINTF(">> %s %p %" PRIu64 "\n", __func__, 3110 (void *)opc, vap->va_size); 3111 #endif 3112 3113 do { 3114 size_t max_write; 3115 /* 3116 * There is a writepage flag when data 3117 * is aligned to page size. Use it for 3118 * everything but the data after the last 3119 * page boundary. 3120 */ 3121 max_write = ps->ps_max_write - sizeof(*fwi); 3122 3123 data_len = MIN(*resid, max_write); 3124 if (data_len > (size_t)sysconf(_SC_PAGESIZE)) 3125 data_len = data_len & ~(sysconf(_SC_PAGESIZE) - 1); 3126 3127 payload_len = data_len + sizeof(*fwi); 3128 3129 /* 3130 * flags may be set to FUSE_WRITE_CACHE (XXX usage?) 3131 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided. 3132 * write_flags is set to 1 for writepage. 3133 */ 3134 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr); 3135 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in); 3136 fwi->fh = perfuse_get_fh(opc, FWRITE); 3137 fwi->offset = offset; 3138 fwi->size = (uint32_t)data_len; 3139 fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1; 3140 fwi->lock_owner = pnd->pnd_lock_owner; 3141 fwi->flags = 0; 3142 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0; 3143 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE; 3144 (void)memcpy((fwi + 1), buf, data_len); 3145 3146 3147 #ifdef PERFUSE_DEBUG 3148 if (perfuse_diagflags & PDF_FH) 3149 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", " 3150 "fh = 0x%"PRIx64"\n", __func__, 3151 (void *)opc, pnd->pnd_nodeid, fwi->fh); 3152 #endif 3153 if ((error = xchg_msg(pu, opc, pm, 3154 sizeof(*fwo), wait_reply)) != 0) 3155 goto out; 3156 3157 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out); 3158 written = fwo->size; 3159 #ifdef PERFUSE_DEBUG 3160 if (written > *resid) 3161 DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd", 3162 __func__, written); 3163 #endif 3164 *resid -= written; 3165 offset += written; 3166 buf += written; 3167 3168 ps->ps_destroy_msg(pm); 3169 pm = NULL; 3170 } while (*resid != 0); 3171 3172 /* 3173 * puffs_ops(3) says 3174 * "everything must be written or an error will be generated" 3175 */ 3176 if (*resid != 0) 3177 error = EFBIG; 3178 3179 #ifdef PERFUSE_DEBUG 3180 if (perfuse_diagflags & PDF_RESIZE) { 3181 if (offset > (off_t)vap->va_size) 3182 DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__, 3183 (void *)opc, vap->va_size, (long long)offset); 3184 else 3185 DPRINTF("<< %s %p \n", __func__, (void *)opc); 3186 } 3187 #endif 3188 3189 /* 3190 * Update file size if we wrote beyond the end 3191 */ 3192 if (offset > (off_t)vap->va_size) 3193 vap->va_size = offset; 3194 3195 if (inresize) { 3196 #ifdef PERFUSE_DEBUG 3197 if (!(pnd->pnd_flags & PND_INRESIZE)) 3198 DERRX(EX_SOFTWARE, "file write grow without resize"); 3199 #endif 3200 pnd->pnd_flags &= ~PND_INRESIZE; 3201 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL); 3202 } 3203 3204 3205 /* 3206 * Statistics 3207 */ 3208 if (ioflag & (IO_SYNC|IO_DSYNC)) 3209 ps->ps_syncwrites++; 3210 else 3211 ps->ps_asyncwrites++; 3212 3213 /* 3214 * Remember to sync the file 3215 */ 3216 pnd->pnd_flags |= PND_DIRTY; 3217 3218 #ifdef PERFUSE_DEBUG 3219 if (perfuse_diagflags & PDF_SYNC) 3220 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n", 3221 __func__, (void*)opc, perfuse_node_path(opc)); 3222 #endif 3223 out: 3224 if (pm != NULL) 3225 ps->ps_destroy_msg(pm); 3226 3227 /* 3228 * If there are no more queued write, we can resume 3229 * an operation awaiting write completion. 3230 */ 3231 pnd->pnd_flags &= ~PND_INWRITE; 3232 if (dequeue_requests(ps, opc, PCQ_WRITE, 1) == 0) 3233 (void)dequeue_requests(ps, opc, PCQ_AFTERWRITE, DEQUEUE_ALL); 3234 3235 return error; 3236 } 3237 3238 /* ARGSUSED0 */ 3239 void 3240 perfuse_cache_write(pu, opc, size, runs) 3241 struct puffs_usermount *pu; 3242 puffs_cookie_t opc; 3243 size_t size; 3244 struct puffs_cacherun *runs; 3245 { 3246 return; 3247 } 3248 3249 /* ARGSUSED4 */ 3250 int 3251 perfuse_node_getextattr(pu, opc, attrns, attrname, attrsize, attr, resid, pcr) 3252 struct puffs_usermount *pu; 3253 puffs_cookie_t opc; 3254 int attrns; 3255 const char *attrname; 3256 size_t *attrsize; 3257 uint8_t *attr; 3258 size_t *resid; 3259 const struct puffs_cred *pcr; 3260 { 3261 struct perfuse_state *ps; 3262 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3263 perfuse_msg_t *pm; 3264 struct fuse_getxattr_in *fgi; 3265 struct fuse_getxattr_out *fgo; 3266 struct fuse_out_header *foh; 3267 size_t attrnamelen; 3268 size_t len; 3269 char *np; 3270 int error; 3271 3272 ps = puffs_getspecific(pu); 3273 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3274 attrnamelen = strlen(attrname) + 1; 3275 len = sizeof(*fgi) + attrnamelen; 3276 3277 pm = ps->ps_new_msg(pu, opc, FUSE_GETXATTR, len, pcr); 3278 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in); 3279 fgi->size = (unsigned int)((resid != NULL) ? *resid : 0); 3280 np = (char *)(void *)(fgi + 1); 3281 (void)strlcpy(np, attrname, attrnamelen); 3282 3283 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 3284 goto out; 3285 3286 /* 3287 * We just get fuse_getattr_out with list size if we requested 3288 * a null size. 3289 */ 3290 if (resid == NULL) { 3291 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out); 3292 3293 if (attrsize != NULL) 3294 *attrsize = fgo->size; 3295 3296 goto out; 3297 } 3298 3299 /* 3300 * And with a non null requested size, we get the list just 3301 * after the header 3302 */ 3303 foh = GET_OUTHDR(ps, pm); 3304 np = (char *)(void *)(foh + 1); 3305 3306 if (resid != NULL) { 3307 len = MAX(foh->len - sizeof(*foh), *resid); 3308 (void)memcpy(attr, np, len); 3309 *resid -= len; 3310 } 3311 3312 out: 3313 ps->ps_destroy_msg(pm); 3314 3315 return error; 3316 } 3317 3318 int 3319 perfuse_node_setextattr(pu, opc, attrns, attrname, attr, resid, pcr) 3320 struct puffs_usermount *pu; 3321 puffs_cookie_t opc; 3322 int attrns; 3323 const char *attrname; 3324 uint8_t *attr; 3325 size_t *resid; 3326 const struct puffs_cred *pcr; 3327 { 3328 struct perfuse_state *ps; 3329 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3330 perfuse_msg_t *pm; 3331 struct fuse_setxattr_in *fsi; 3332 size_t attrnamelen; 3333 size_t len; 3334 char *np; 3335 int error; 3336 3337 ps = puffs_getspecific(pu); 3338 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3339 attrnamelen = strlen(attrname) + 1; 3340 len = sizeof(*fsi) + attrnamelen + *resid; 3341 3342 pm = ps->ps_new_msg(pu, opc, FUSE_SETXATTR, len, pcr); 3343 fsi = GET_INPAYLOAD(ps, pm, fuse_setxattr_in); 3344 fsi->size = (unsigned int)*resid; 3345 fsi->flags = 0; 3346 np = (char *)(void *)(fsi + 1); 3347 (void)strlcpy(np, attrname, attrnamelen); 3348 np += attrnamelen; 3349 (void)memcpy(np, (char *)attr, *resid); 3350 3351 if ((error = xchg_msg(pu, opc, pm, 3352 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 3353 goto out; 3354 3355 *resid = 0; 3356 out: 3357 ps->ps_destroy_msg(pm); 3358 3359 return error; 3360 } 3361 3362 /* ARGSUSED2 */ 3363 int 3364 perfuse_node_listextattr(pu, opc, attrns, attrsize, attrs, resid, flag, pcr) 3365 struct puffs_usermount *pu; 3366 puffs_cookie_t opc; 3367 int attrns; 3368 size_t *attrsize; 3369 uint8_t *attrs; 3370 size_t *resid; 3371 int flag; 3372 const struct puffs_cred *pcr; 3373 { 3374 struct perfuse_state *ps; 3375 perfuse_msg_t *pm; 3376 struct fuse_getxattr_in *fgi; 3377 struct fuse_getxattr_out *fgo; 3378 struct fuse_out_header *foh; 3379 char *np; 3380 size_t len, puffs_len; 3381 int error; 3382 3383 ps = puffs_getspecific(pu); 3384 len = sizeof(*fgi); 3385 3386 pm = ps->ps_new_msg(pu, opc, FUSE_LISTXATTR, len, pcr); 3387 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in); 3388 if (resid != NULL) 3389 fgi->size = (unsigned int)*resid; 3390 else 3391 fgi->size = 0; 3392 3393 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 3394 goto out; 3395 3396 /* 3397 * We just get fuse_getattr_out with list size if we requested 3398 * a null size. 3399 */ 3400 if (resid == NULL) { 3401 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out); 3402 3403 if (attrsize != NULL) 3404 *attrsize = fgo->size; 3405 3406 goto out; 3407 } 3408 3409 /* 3410 * And with a non null requested size, we get the list just 3411 * after the header 3412 */ 3413 foh = GET_OUTHDR(ps, pm); 3414 np = (char *)(void *)(foh + 1); 3415 puffs_len = foh->len - sizeof(*foh); 3416 3417 if (attrs != NULL) { 3418 #ifdef PUFFS_EXTATTR_LIST_LENPREFIX 3419 /* 3420 * Convert the FUSE reply to length prefixed strings 3421 * if this is what the kernel wants. 3422 */ 3423 if (flag & PUFFS_EXTATTR_LIST_LENPREFIX) { 3424 size_t i, attrlen; 3425 3426 for (i = 0; i < puffs_len; i += attrlen + 1) { 3427 attrlen = strlen(np + i); 3428 (void)memmove(np + i + 1, np + i, attrlen); 3429 *(np + i) = (uint8_t)attrlen; 3430 } 3431 } 3432 #endif /* PUFFS_EXTATTR_LIST_LENPREFIX */ 3433 (void)memcpy(attrs, np, puffs_len); 3434 *resid -= puffs_len; 3435 } 3436 3437 if (attrsize != NULL) 3438 *attrsize = puffs_len; 3439 3440 out: 3441 ps->ps_destroy_msg(pm); 3442 3443 return error; 3444 } 3445 3446 int 3447 perfuse_node_deleteextattr(pu, opc, attrns, attrname, pcr) 3448 struct puffs_usermount *pu; 3449 puffs_cookie_t opc; 3450 int attrns; 3451 const char *attrname; 3452 const struct puffs_cred *pcr; 3453 { 3454 struct perfuse_state *ps; 3455 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3456 perfuse_msg_t *pm; 3457 size_t attrnamelen; 3458 char *np; 3459 int error; 3460 3461 ps = puffs_getspecific(pu); 3462 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3463 attrnamelen = strlen(attrname) + 1; 3464 3465 pm = ps->ps_new_msg(pu, opc, FUSE_REMOVEXATTR, attrnamelen, pcr); 3466 np = _GET_INPAYLOAD(ps, pm, char *); 3467 (void)strlcpy(np, attrname, attrnamelen); 3468 3469 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply); 3470 3471 ps->ps_destroy_msg(pm); 3472 3473 return error; 3474 } 3475