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