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