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