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