1 /* $NetBSD: ops.c,v 1.26 2011/05/11 14:52:48 jakllsch 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 = 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 DPRINTF("%s unmounted, exit\n", ps->ps_target); 848 849 exit(0); 850 out: 851 ps->ps_destroy_msg(pm); 852 853 return error; 854 } 855 856 int 857 perfuse_fs_statvfs(pu, svfsb) 858 struct puffs_usermount *pu; 859 struct statvfs *svfsb; 860 { 861 struct perfuse_state *ps; 862 perfuse_msg_t *pm; 863 puffs_cookie_t opc; 864 struct fuse_statfs_out *fso; 865 int error; 866 867 ps = puffs_getspecific(pu); 868 opc = (puffs_cookie_t)puffs_getroot(pu); 869 pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL); 870 871 if ((error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply)) != 0) 872 goto out; 873 874 fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out); 875 svfsb->f_flag = ps->ps_mountflags; 876 svfsb->f_bsize = fso->st.bsize; 877 svfsb->f_frsize = fso->st.frsize; 878 svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize; 879 svfsb->f_blocks = fso->st.blocks; 880 svfsb->f_bfree = fso->st.bfree; 881 svfsb->f_bavail = fso->st.bavail; 882 svfsb->f_bresvd = fso->st.bfree - fso->st.bavail; 883 svfsb->f_files = fso->st.files; 884 svfsb->f_ffree = fso->st.ffree; 885 svfsb->f_favail = fso->st.ffree;/* files not reserved for root */ 886 svfsb->f_fresvd = 0; /* files reserved for root */ 887 888 svfsb->f_syncreads = ps->ps_syncreads; 889 svfsb->f_syncwrites = ps->ps_syncwrites; 890 891 svfsb->f_asyncreads = ps->ps_asyncreads; 892 svfsb->f_asyncwrites = ps->ps_asyncwrites; 893 894 (void)memcpy(&svfsb->f_fsidx, &ps->ps_fsid, sizeof(ps->ps_fsid)); 895 svfsb->f_fsid = (unsigned long)ps->ps_fsid; 896 svfsb->f_namemax = MAXPATHLEN; /* XXX */ 897 svfsb->f_owner = ps->ps_owner_uid; 898 899 (void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN); 900 901 if (ps->ps_filesystemtype != NULL) 902 (void)strlcpy(svfsb->f_fstypename, 903 ps->ps_filesystemtype, _VFS_NAMELEN); 904 else 905 (void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN); 906 907 if (ps->ps_source != NULL) 908 strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN); 909 else 910 strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN); 911 out: 912 ps->ps_destroy_msg(pm); 913 914 return error; 915 } 916 917 int 918 perfuse_fs_sync(pu, waitfor, pcr) 919 struct puffs_usermount *pu; 920 int waitfor; 921 const struct puffs_cred *pcr; 922 { 923 /* 924 * FUSE does not seem to have a FS sync callback. 925 * Maybe do not even register this callback 926 */ 927 return puffs_fsnop_sync(pu, waitfor, pcr); 928 } 929 930 /* ARGSUSED0 */ 931 int 932 perfuse_fs_fhtonode(pu, fid, fidsize, pni) 933 struct puffs_usermount *pu; 934 void *fid; 935 size_t fidsize; 936 struct puffs_newinfo *pni; 937 { 938 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 939 return 0; 940 } 941 942 /* ARGSUSED0 */ 943 int 944 perfuse_fs_nodetofh(pu, cookie, fid, fidsize) 945 struct puffs_usermount *pu; 946 puffs_cookie_t cookie; 947 void *fid; 948 size_t *fidsize; 949 { 950 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 951 return 0; 952 } 953 954 #if 0 955 /* ARGSUSED0 */ 956 void 957 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname) 958 struct puffs_usermount *pu; 959 int cmd, 960 puffs_cookie_t *cookie; 961 int flags; 962 int namespace; 963 const char *attrname; 964 { 965 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 966 return 0; 967 } 968 #endif /* 0 */ 969 970 /* ARGSUSED0 */ 971 void 972 perfuse_fs_suspend(pu, status) 973 struct puffs_usermount *pu; 974 int status; 975 { 976 return; 977 } 978 979 980 981 int 982 perfuse_node_lookup(pu, opc, pni, pcn) 983 struct puffs_usermount *pu; 984 puffs_cookie_t opc; 985 struct puffs_newinfo *pni; 986 const struct puffs_cn *pcn; 987 { 988 struct puffs_node *pn; 989 mode_t mode; 990 int error; 991 992 /* 993 * Check permissions 994 */ 995 switch(pcn->pcn_nameiop) { 996 case NAMEI_DELETE: /* FALLTHROUGH */ 997 case NAMEI_RENAME: /* FALLTHROUGH */ 998 case NAMEI_CREATE: 999 mode = PUFFS_VEXEC|PUFFS_VWRITE; 1000 break; 1001 case NAMEI_LOOKUP: /* FALLTHROUGH */ 1002 default: 1003 mode = PUFFS_VEXEC; 1004 break; 1005 } 1006 1007 if ((error = mode_access(opc, pcn->pcn_cred, mode)) != 0) 1008 return error; 1009 1010 /* 1011 * Special case for .. 1012 */ 1013 if (strcmp(pcn->pcn_name, "..") == 0) 1014 pn = PERFUSE_NODE_DATA(opc)->pnd_parent; 1015 else 1016 error = node_lookup_common(pu, (puffs_cookie_t)opc, 1017 pcn->pcn_name, &pn); 1018 if (error != 0) 1019 return error; 1020 1021 /* 1022 * Removed node 1023 */ 1024 if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_REMOVED) 1025 return ENOENT; 1026 1027 /* 1028 * Check for sticky bit. Unfortunately there is no way to 1029 * do this before creating the puffs_node, since we require 1030 * this operation to get the node owner. 1031 */ 1032 switch (pcn->pcn_nameiop) { 1033 case NAMEI_DELETE: /* FALLTHROUGH */ 1034 case NAMEI_RENAME: 1035 error = sticky_access(pn, pcn->pcn_cred); 1036 if (error != 0) { 1037 /* 1038 * kernel will never know about it and will 1039 * not reclaim it. The filesystem needs to 1040 * clean it up anyway, therefore mimick a forget. 1041 */ 1042 PERFUSE_NODE_DATA(pn)->pnd_flags |= PND_RECLAIMED; 1043 (void)perfuse_node_reclaim(pu, (puffs_cookie_t)pn); 1044 return error; 1045 } 1046 break; 1047 default: 1048 break; 1049 } 1050 1051 /* 1052 * If that node had a pending reclaim, wipe it out. 1053 */ 1054 PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED; 1055 1056 puffs_newinfo_setcookie(pni, pn); 1057 puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 1058 puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size); 1059 puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); 1060 1061 return error; 1062 } 1063 1064 int 1065 perfuse_node_create(pu, opc, pni, pcn, vap) 1066 struct puffs_usermount *pu; 1067 puffs_cookie_t opc; 1068 struct puffs_newinfo *pni; 1069 const struct puffs_cn *pcn; 1070 const struct vattr *vap; 1071 { 1072 perfuse_msg_t *pm; 1073 struct perfuse_state *ps; 1074 struct fuse_create_in *fci; 1075 struct fuse_entry_out *feo; 1076 struct fuse_open_out *foo; 1077 struct puffs_node *pn; 1078 const char *name; 1079 size_t namelen; 1080 size_t len; 1081 int error; 1082 1083 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1084 return ENOENT; 1085 1086 /* 1087 * If create is unimplemented: Check that it does not 1088 * already exists, and if not, do mknod and open 1089 */ 1090 ps = puffs_getspecific(pu); 1091 if (ps->ps_flags & PS_NO_CREAT) { 1092 error = node_lookup_common(pu, opc, pcn->pcn_name, &pn); 1093 if (error == 0) 1094 return EEXIST; 1095 1096 error = perfuse_node_mknod(pu, opc, pni, pcn, vap); 1097 if (error != 0) 1098 return error; 1099 1100 error = node_lookup_common(pu, opc, pcn->pcn_name, &pn); 1101 if (error != 0) 1102 return error; 1103 1104 /* 1105 * FUSE does the open at create time, while 1106 * NetBSD will open in a subsequent operation. 1107 * We need to open now, in order to retain FUSE 1108 * semantics. The calling process will not get 1109 * a file descriptor before the kernel sends 1110 * the open operation. 1111 */ 1112 opc = (puffs_cookie_t)pn; 1113 error = perfuse_node_open(pu, opc, FWRITE, pcn->pcn_cred); 1114 if (error != 0) 1115 return error; 1116 1117 return 0; 1118 } 1119 1120 name = pcn->pcn_name; 1121 namelen = pcn->pcn_namelen + 1; 1122 len = sizeof(*fci) + namelen; 1123 1124 /* 1125 * flags should use O_WRONLY instead of O_RDWR, but it 1126 * breaks when the caller tries to read from file. 1127 * 1128 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type) 1129 */ 1130 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, NULL); 1131 fci = GET_INPAYLOAD(ps, pm, fuse_create_in); 1132 fci->flags = O_CREAT | O_TRUNC | O_RDWR; 1133 fci->mode = vap->va_mode | VTTOIF(vap->va_type); 1134 fci->umask = 0; /* Seems unused by libfuse */ 1135 (void)strlcpy((char*)(void *)(fci + 1), name, namelen); 1136 1137 len = sizeof(*feo) + sizeof(*foo); 1138 if ((error = xchg_msg(pu, opc, pm, len, wait_reply)) != 0) 1139 goto out; 1140 1141 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 1142 foo = (struct fuse_open_out *)(void *)(feo + 1); 1143 if (feo->nodeid == PERFUSE_UNKNOWN_INO) 1144 DERRX(EX_SOFTWARE, "%s: no ino", __func__); 1145 1146 /* 1147 * Save the file handle and inode in node private data 1148 * so that we can reuse it later 1149 */ 1150 pn = perfuse_new_pn(pu, name, opc); 1151 perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE); 1152 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid; 1153 1154 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 1155 pn->pn_va.va_gen = (u_long)(feo->generation); 1156 1157 puffs_newinfo_setcookie(pni, pn); 1158 1159 #ifdef PERFUSE_DEBUG 1160 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1161 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x " 1162 "ino = %"PRId64", wfh = 0x%"PRIx64"\n", 1163 __func__, (void *)pn, pcn->pcn_name, 1164 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid, foo->fh); 1165 #endif 1166 1167 ps->ps_destroy_msg(pm); 1168 1169 return node_mk_common_final(pu, opc, pn, pcn); 1170 1171 out: 1172 ps->ps_destroy_msg(pm); 1173 1174 /* 1175 * create is unimplmented, remember it for later, 1176 * and start over using mknod and open instead. 1177 */ 1178 if (error == ENOSYS) { 1179 ps->ps_flags |= PS_NO_CREAT; 1180 return perfuse_node_create(pu, opc, pni, pcn, vap); 1181 } 1182 1183 return error; 1184 } 1185 1186 1187 int 1188 perfuse_node_mknod(pu, opc, pni, pcn, vap) 1189 struct puffs_usermount *pu; 1190 puffs_cookie_t opc; 1191 struct puffs_newinfo *pni; 1192 const struct puffs_cn *pcn; 1193 const struct vattr *vap; 1194 { 1195 struct perfuse_state *ps; 1196 perfuse_msg_t *pm; 1197 struct fuse_mknod_in *fmi; 1198 const char* path; 1199 size_t len; 1200 1201 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1202 return ENOENT; 1203 1204 /* 1205 * Only superuser can mknod objects other than 1206 * directories, files, socks, fifo and links. 1207 * 1208 * Create an object require -WX permission in the parent directory 1209 */ 1210 switch (vap->va_type) { 1211 case VDIR: /* FALLTHROUGH */ 1212 case VREG: /* FALLTHROUGH */ 1213 case VFIFO: /* FALLTHROUGH */ 1214 case VSOCK: 1215 break; 1216 default: /* VNON, VBLK, VCHR, VBAD */ 1217 if (!puffs_cred_isjuggernaut(pcn->pcn_cred)) 1218 return EACCES; 1219 break; 1220 } 1221 1222 1223 ps = puffs_getspecific(pu); 1224 path = pcn->pcn_name; 1225 len = sizeof(*fmi) + pcn->pcn_namelen + 1; 1226 1227 /* 1228 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type) 1229 */ 1230 pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, NULL); 1231 fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in); 1232 fmi->mode = vap->va_mode | VTTOIF(vap->va_type); 1233 fmi->rdev = (uint32_t)vap->va_rdev; 1234 fmi->umask = 0; /* Seems unused bu libfuse */ 1235 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 1236 1237 return node_mk_common(pu, opc, pni, pcn, pm); 1238 } 1239 1240 1241 int 1242 perfuse_node_open(pu, opc, mode, pcr) 1243 struct puffs_usermount *pu; 1244 puffs_cookie_t opc; 1245 int mode; 1246 const struct puffs_cred *pcr; 1247 { 1248 struct perfuse_state *ps; 1249 struct perfuse_node_data *pnd; 1250 perfuse_msg_t *pm; 1251 mode_t fmode; 1252 int op; 1253 struct fuse_open_in *foi; 1254 struct fuse_open_out *foo; 1255 struct puffs_node *pn; 1256 int error; 1257 1258 ps = puffs_getspecific(pu); 1259 pn = (struct puffs_node *)opc; 1260 pnd = PERFUSE_NODE_DATA(opc); 1261 pm = NULL; 1262 error = 0; 1263 1264 if (pnd->pnd_flags & PND_REMOVED) 1265 return ENOENT; 1266 1267 if (puffs_pn_getvap(pn)->va_type == VDIR) 1268 op = FUSE_OPENDIR; 1269 else 1270 op = FUSE_OPEN; 1271 1272 /* 1273 * libfuse docs says 1274 * - O_CREAT should never be set. 1275 * - O_TRUNC may be used if mount option atomic_o_trunc is used XXX 1276 * 1277 * O_APPEND makes no sense since FUSE always sends 1278 * the file offset for write operations. If the 1279 * filesystem uses pwrite(), O_APPEND would cause 1280 * the offset to be ignored and cause file corruption. 1281 */ 1282 mode &= ~(O_CREAT|O_APPEND); 1283 1284 /* 1285 * Do not open twice, and do not reopen for reading 1286 * if we already have write handle. 1287 */ 1288 if (((mode & FREAD) && (pnd->pnd_flags & PND_RFH)) || 1289 ((mode & FREAD) && (pnd->pnd_flags & PND_WFH)) || 1290 ((mode & FWRITE) && (pnd->pnd_flags & PND_WFH))) { 1291 error = 0; 1292 goto out; 1293 } 1294 1295 /* 1296 * Queue open on a node so that we do not open 1297 * twice. This would be better with read and 1298 * write distinguished. 1299 */ 1300 while (pnd->pnd_flags & PND_INOPEN) 1301 requeue_request(pu, opc, PCQ_OPEN); 1302 pnd->pnd_flags |= PND_INOPEN; 1303 1304 /* 1305 * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE 1306 * to O_RDONLY/O_WRONLY while perserving the other options. 1307 */ 1308 fmode = mode & ~(FREAD|FWRITE); 1309 fmode |= (mode & FWRITE) ? O_RDWR : O_RDONLY; 1310 1311 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr); 1312 foi = GET_INPAYLOAD(ps, pm, fuse_open_in); 1313 foi->flags = fmode; 1314 foi->unused = 0; 1315 1316 if ((error = xchg_msg(pu, opc, pm, sizeof(*foo), wait_reply)) != 0) 1317 goto out; 1318 1319 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out); 1320 1321 /* 1322 * Save the file handle in node private data 1323 * so that we can reuse it later 1324 */ 1325 perfuse_new_fh(opc, foo->fh, mode); 1326 1327 #ifdef PERFUSE_DEBUG 1328 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1329 DPRINTF("%s: opc = %p, file = \"%s\", " 1330 "ino = %"PRId64", %s%sfh = 0x%"PRIx64"\n", 1331 __func__, (void *)opc, perfuse_node_path(opc), 1332 pnd->pnd_ino, mode & FREAD ? "r" : "", 1333 mode & FWRITE ? "w" : "", foo->fh); 1334 #endif 1335 1336 out: 1337 if (pm != NULL) 1338 ps->ps_destroy_msg(pm); 1339 1340 pnd->pnd_flags &= ~PND_INOPEN; 1341 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL); 1342 1343 return error; 1344 } 1345 1346 /* ARGSUSED0 */ 1347 int 1348 perfuse_node_close(pu, opc, flags, pcr) 1349 struct puffs_usermount *pu; 1350 puffs_cookie_t opc; 1351 int flags; 1352 const struct puffs_cred *pcr; 1353 { 1354 struct perfuse_node_data *pnd; 1355 1356 pnd = PERFUSE_NODE_DATA(opc); 1357 1358 if (!(pnd->pnd_flags & PND_OPEN)) 1359 return EBADF; 1360 1361 /* 1362 * Actual close is postponed at inactive time. 1363 */ 1364 return 0; 1365 } 1366 1367 /* 1368 * XXX 1369 * This fails as unprivilegied, it should not: touch testa/testx/a 1370 * d-wx-wx-wx 2 root wheel 512 Oct 5 04:32 testa/testx 1371 * -rwxrwxrwx 1 root wheel 0 Oct 5 04:39 testa/testx/a 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 int error; 1443 1444 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1445 return ENOENT; 1446 1447 ps = puffs_getspecific(pu); 1448 1449 /* 1450 * FUSE_GETATTR_FH must be set in fgi->flags 1451 * if we use for fgi->fh 1452 */ 1453 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr); 1454 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in); 1455 fgi->getattr_flags = 0; 1456 fgi->dummy = 0; 1457 fgi->fh = 0; 1458 1459 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) { 1460 fgi->fh = perfuse_get_fh(opc, FREAD); 1461 fgi->getattr_flags |= FUSE_GETATTR_FH; 1462 } 1463 1464 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0) 1465 goto out; 1466 1467 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1468 1469 /* 1470 * The message from filesystem has a cache timeout 1471 * XXX this is ignored yet, is that right? 1472 * 1473 * We also set birthtime, flags, filerev,vaflags to 0. 1474 * This seems the best bet, since the information is 1475 * not available from filesystem. 1476 */ 1477 fuse_attr_to_vap(ps, vap, &fao->attr); 1478 1479 out: 1480 ps->ps_destroy_msg(pm); 1481 1482 return error; 1483 } 1484 1485 int 1486 perfuse_node_setattr(pu, opc, vap, pcr) 1487 struct puffs_usermount *pu; 1488 puffs_cookie_t opc; 1489 const struct vattr *vap; 1490 const struct puffs_cred *pcr; 1491 { 1492 perfuse_msg_t *pm; 1493 uint64_t fh; 1494 struct perfuse_state *ps; 1495 struct perfuse_node_data *pnd; 1496 struct fuse_setattr_in *fsi; 1497 struct fuse_attr_out *fao; 1498 struct vattr *old_va; 1499 int error; 1500 1501 ps = puffs_getspecific(pu); 1502 pnd = PERFUSE_NODE_DATA(opc); 1503 pm = NULL; 1504 1505 /* 1506 * The only operation we can do once the file is removed 1507 * is to resize it, and we can do it only if it is open. 1508 * Do not even send the operation to the filesystem: the 1509 * file is not there anymore. 1510 */ 1511 if (pnd->pnd_flags & PND_REMOVED) { 1512 if (!(pnd->pnd_flags & PND_OPEN)) 1513 return ENOENT; 1514 1515 error = 0; 1516 goto out; 1517 } 1518 1519 old_va = puffs_pn_getvap((struct puffs_node *)opc); 1520 1521 /* 1522 * Check for permission to change size 1523 */ 1524 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1525 (error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0) 1526 return error; 1527 1528 /* 1529 * Check for permission to change dates 1530 */ 1531 if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) || 1532 (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) && 1533 (puffs_access_times(old_va->va_uid, old_va->va_gid, 1534 old_va->va_mode, 0, pcr) != 0)) 1535 return EACCES; 1536 1537 /* 1538 * Check for permission to change owner and group 1539 */ 1540 if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) || 1541 (vap->va_gid != (gid_t)PUFFS_VNOVAL)) && 1542 (puffs_access_chown(old_va->va_uid, old_va->va_gid, 1543 vap->va_uid, vap->va_gid, pcr)) != 0) 1544 return EACCES; 1545 1546 /* 1547 * Check for permission to change permissions 1548 */ 1549 if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && 1550 (puffs_access_chmod(old_va->va_uid, old_va->va_gid, 1551 old_va->va_type, vap->va_mode, pcr)) != 0) 1552 return EACCES; 1553 1554 /* 1555 * It seems troublesome to resize a file while 1556 * a write is just beeing done. Wait for 1557 * it to finish. 1558 */ 1559 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) 1560 while (pnd->pnd_flags & PND_INWRITE) 1561 requeue_request(pu, opc, PCQ_AFTERWRITE); 1562 1563 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr); 1564 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 1565 fsi->valid = 0; 1566 1567 /* 1568 * Get a fh if the node is open for writing 1569 */ 1570 if (pnd->pnd_flags & PND_WFH) { 1571 fh = perfuse_get_fh(opc, FWRITE); 1572 fsi->fh = fh; 1573 fsi->valid |= FUSE_FATTR_FH; 1574 } 1575 1576 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) { 1577 fsi->size = vap->va_size; 1578 fsi->valid |= FUSE_FATTR_SIZE; 1579 } 1580 1581 /* 1582 * Setting mtime without atime or vice versa leads to 1583 * dates being reset to Epoch on glusterfs. If one 1584 * is missing, use the old value. 1585 */ 1586 if ((vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) || 1587 (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)) { 1588 1589 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) { 1590 fsi->atime = vap->va_atime.tv_sec; 1591 fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec; 1592 } else { 1593 fsi->atime = old_va->va_atime.tv_sec; 1594 fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec; 1595 } 1596 1597 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { 1598 fsi->mtime = vap->va_mtime.tv_sec; 1599 fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec; 1600 } else { 1601 fsi->mtime = old_va->va_mtime.tv_sec; 1602 fsi->mtimensec = (uint32_t)old_va->va_mtime.tv_nsec; 1603 } 1604 1605 fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_ATIME); 1606 } 1607 1608 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) { 1609 fsi->mode = vap->va_mode; 1610 fsi->valid |= FUSE_FATTR_MODE; 1611 } 1612 1613 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) { 1614 fsi->uid = vap->va_uid; 1615 fsi->valid |= FUSE_FATTR_UID; 1616 } 1617 1618 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) { 1619 fsi->gid = vap->va_gid; 1620 fsi->valid |= FUSE_FATTR_GID; 1621 } 1622 1623 if (pnd->pnd_lock_owner != 0) { 1624 fsi->lock_owner = pnd->pnd_lock_owner; 1625 fsi->valid |= FUSE_FATTR_LOCKOWNER; 1626 } 1627 1628 /* 1629 * If nothing remain, discard the operation. 1630 */ 1631 if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME| 1632 FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) { 1633 error = 0; 1634 goto out; 1635 } 1636 1637 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0) 1638 goto out; 1639 1640 /* 1641 * Copy back the new values 1642 */ 1643 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1644 fuse_attr_to_vap(ps, old_va, &fao->attr); 1645 out: 1646 1647 if (pm != NULL) 1648 ps->ps_destroy_msg(pm); 1649 1650 return error; 1651 } 1652 1653 int 1654 perfuse_node_poll(pu, opc, events) 1655 struct puffs_usermount *pu; 1656 puffs_cookie_t opc; 1657 int *events; 1658 { 1659 struct perfuse_state *ps; 1660 perfuse_msg_t *pm; 1661 struct fuse_poll_in *fpi; 1662 struct fuse_poll_out *fpo; 1663 int error; 1664 1665 ps = puffs_getspecific(pu); 1666 /* 1667 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set. 1668 */ 1669 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL); 1670 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in); 1671 fpi->fh = perfuse_get_fh(opc, FREAD); 1672 fpi->kh = 0; 1673 fpi->flags = 0; 1674 1675 #ifdef PERFUSE_DEBUG 1676 if (perfuse_diagflags & PDF_FH) 1677 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 1678 __func__, (void *)opc, 1679 PERFUSE_NODE_DATA(opc)->pnd_ino, fpi->fh); 1680 #endif 1681 if ((error = xchg_msg(pu, opc, pm, sizeof(*fpo), wait_reply)) != 0) 1682 goto out; 1683 1684 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out); 1685 *events = fpo->revents; 1686 out: 1687 ps->ps_destroy_msg(pm); 1688 1689 return error; 1690 } 1691 1692 /* ARGSUSED0 */ 1693 int 1694 perfuse_node_mmap(pu, opc, flags, pcr) 1695 struct puffs_usermount *pu; 1696 puffs_cookie_t opc; 1697 int flags; 1698 const struct puffs_cred *pcr; 1699 { 1700 /* 1701 * Not implemented anymore in libfuse 1702 */ 1703 return ENOSYS; 1704 } 1705 1706 /* ARGSUSED2 */ 1707 int 1708 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi) 1709 struct puffs_usermount *pu; 1710 puffs_cookie_t opc; 1711 const struct puffs_cred *pcr; 1712 int flags; 1713 off_t offlo; 1714 off_t offhi; 1715 { 1716 int op; 1717 perfuse_msg_t *pm; 1718 struct perfuse_state *ps; 1719 struct perfuse_node_data *pnd; 1720 struct fuse_fsync_in *ffi; 1721 uint64_t fh; 1722 int error; 1723 1724 pm = NULL; 1725 ps = puffs_getspecific(pu); 1726 pnd = PERFUSE_NODE_DATA(opc); 1727 1728 /* 1729 * No need to sync a removed node 1730 */ 1731 if (pnd->pnd_flags & PND_REMOVED) 1732 return 0; 1733 1734 /* 1735 * We do not sync closed files. They have been 1736 * sync at inactive time already. 1737 */ 1738 if (!(pnd->pnd_flags & PND_OPEN)) 1739 return 0; 1740 1741 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR) 1742 op = FUSE_FSYNCDIR; 1743 else /* VREG but also other types such as VLNK */ 1744 op = FUSE_FSYNC; 1745 1746 /* 1747 * Do not sync if there are no change to sync 1748 * XXX remove that test on files if we implement mmap 1749 */ 1750 #ifdef PERFUSE_DEBUG 1751 if (perfuse_diagflags & PDF_SYNC) 1752 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n", 1753 __func__, (void*)opc, perfuse_node_path(opc), 1754 pnd->pnd_flags & PND_DIRTY ? "" : "not "); 1755 #endif 1756 if (!(pnd->pnd_flags & PND_DIRTY)) 1757 return 0; 1758 1759 /* 1760 * It seems NetBSD can call fsync without open first 1761 * glusterfs complain in such a situation: 1762 * "FSYNC() ERR => -1 (Invalid argument)" 1763 * The file will be closed at inactive time. 1764 * 1765 * We open the directory for reading in order to sync. 1766 * This sounds rather counterintuitive, but it works. 1767 */ 1768 if (!(pnd->pnd_flags & PND_WFH)) { 1769 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 1770 goto out; 1771 } 1772 1773 if (op == FUSE_FSYNCDIR) 1774 fh = perfuse_get_fh(opc, FREAD); 1775 else 1776 fh = perfuse_get_fh(opc, FWRITE); 1777 1778 /* 1779 * If fsync_flags is set, meta data should not be flushed. 1780 */ 1781 pm = ps->ps_new_msg(pu, opc, op, sizeof(*ffi), NULL); 1782 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in); 1783 ffi->fh = fh; 1784 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1; 1785 1786 #ifdef PERFUSE_DEBUG 1787 if (perfuse_diagflags & PDF_FH) 1788 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 1789 __func__, (void *)opc, 1790 PERFUSE_NODE_DATA(opc)->pnd_ino, ffi->fh); 1791 #endif 1792 1793 if ((error = xchg_msg(pu, opc, pm, 1794 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 1795 goto out; 1796 1797 /* 1798 * No reply beyond fuse_out_header: nothing to do on success 1799 * just clear the dirty flag 1800 */ 1801 pnd->pnd_flags &= ~PND_DIRTY; 1802 1803 #ifdef PERFUSE_DEBUG 1804 if (perfuse_diagflags & PDF_SYNC) 1805 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n", 1806 __func__, (void*)opc, perfuse_node_path(opc)); 1807 #endif 1808 1809 out: 1810 /* 1811 * ENOSYS is not returned to kernel, 1812 */ 1813 if (error == ENOSYS) 1814 error = 0; 1815 1816 if (pm != NULL) 1817 ps->ps_destroy_msg(pm); 1818 1819 return error; 1820 } 1821 1822 /* ARGSUSED0 */ 1823 int 1824 perfuse_node_seek(pu, opc, oldoff, newoff, pcr) 1825 struct puffs_usermount *pu; 1826 puffs_cookie_t opc; 1827 off_t oldoff; 1828 off_t newoff; 1829 const struct puffs_cred *pcr; 1830 { 1831 return 0; 1832 } 1833 1834 int 1835 perfuse_node_remove(pu, opc, targ, pcn) 1836 struct puffs_usermount *pu; 1837 puffs_cookie_t opc; 1838 puffs_cookie_t targ; 1839 const struct puffs_cn *pcn; 1840 { 1841 struct perfuse_state *ps; 1842 struct perfuse_node_data *pnd; 1843 perfuse_msg_t *pm; 1844 char *path; 1845 const char *name; 1846 size_t len; 1847 int error; 1848 1849 pnd = PERFUSE_NODE_DATA(opc); 1850 1851 if ((pnd->pnd_flags & PND_REMOVED) || 1852 (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED)) 1853 return ENOENT; 1854 1855 #ifdef PERFUSE_DEBUG 1856 if (targ == NULL) 1857 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__); 1858 1859 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1860 DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n", 1861 __func__, (void *)opc, (void *)targ, pcn->pcn_name); 1862 #endif 1863 /* 1864 * Await for all operations on the deleted node to drain, 1865 * as the filesystem may be confused to have it deleted 1866 * during a getattr 1867 */ 1868 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 1869 requeue_request(pu, targ, PCQ_AFTERXCHG); 1870 1871 ps = puffs_getspecific(pu); 1872 pnd = PERFUSE_NODE_DATA(opc); 1873 name = pcn->pcn_name; 1874 len = pcn->pcn_namelen + 1; 1875 1876 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, NULL); 1877 path = _GET_INPAYLOAD(ps, pm, char *); 1878 (void)strlcpy(path, name, len); 1879 1880 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 1881 goto out; 1882 1883 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 1884 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN)) 1885 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 1886 1887 /* 1888 * The parent directory needs a sync 1889 */ 1890 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 1891 1892 #ifdef PERFUSE_DEBUG 1893 if (perfuse_diagflags & PDF_FILENAME) 1894 DPRINTF("%s: remove nodeid = %"PRId64" file = \"%s\"\n", 1895 __func__, PERFUSE_NODE_DATA(targ)->pnd_ino, 1896 pcn->pcn_name); 1897 #endif 1898 out: 1899 ps->ps_destroy_msg(pm); 1900 1901 return error; 1902 } 1903 1904 int 1905 perfuse_node_link(pu, opc, targ, pcn) 1906 struct puffs_usermount *pu; 1907 puffs_cookie_t opc; 1908 puffs_cookie_t targ; 1909 const struct puffs_cn *pcn; 1910 { 1911 struct perfuse_state *ps; 1912 perfuse_msg_t *pm; 1913 const char *name; 1914 size_t len; 1915 struct puffs_node *pn; 1916 struct fuse_link_in *fli; 1917 int error; 1918 1919 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1920 return ENOENT; 1921 1922 ps = puffs_getspecific(pu); 1923 pn = (struct puffs_node *)targ; 1924 name = pcn->pcn_name; 1925 len = sizeof(*fli) + pcn->pcn_namelen + 1; 1926 1927 pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, NULL); 1928 fli = GET_INPAYLOAD(ps, pm, fuse_link_in); 1929 fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_ino; 1930 (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli)); 1931 1932 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply); 1933 1934 ps->ps_destroy_msg(pm); 1935 1936 return error; 1937 } 1938 1939 int 1940 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ) 1941 struct puffs_usermount *pu; 1942 puffs_cookie_t opc; 1943 puffs_cookie_t src; 1944 const struct puffs_cn *pcn_src; 1945 puffs_cookie_t targ_dir; 1946 puffs_cookie_t targ; 1947 const struct puffs_cn *pcn_targ; 1948 { 1949 struct perfuse_state *ps; 1950 perfuse_msg_t *pm; 1951 struct fuse_rename_in *fri; 1952 const char *newname; 1953 const char *oldname; 1954 char *np; 1955 int error; 1956 size_t len; 1957 size_t newname_len; 1958 size_t oldname_len; 1959 1960 if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) || 1961 (PERFUSE_NODE_DATA(src)->pnd_flags & PND_REMOVED) || 1962 (PERFUSE_NODE_DATA(targ_dir)->pnd_flags & PND_REMOVED)) 1963 return ENOENT; 1964 1965 /* 1966 * Await for all operations on the deleted node to drain, 1967 * as the filesystem may be confused to have it deleted 1968 * during a getattr 1969 */ 1970 if ((struct puffs_node *)targ != NULL) { 1971 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 1972 requeue_request(pu, targ, PCQ_AFTERXCHG); 1973 } else { 1974 while (PERFUSE_NODE_DATA(src)->pnd_flags & PND_INXCHG) 1975 requeue_request(pu, src, PCQ_AFTERXCHG); 1976 } 1977 1978 ps = puffs_getspecific(pu); 1979 newname = pcn_targ->pcn_name; 1980 newname_len = pcn_targ->pcn_namelen + 1; 1981 oldname = pcn_src->pcn_name; 1982 oldname_len = pcn_src->pcn_namelen + 1; 1983 1984 len = sizeof(*fri) + oldname_len + newname_len; 1985 pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, NULL); 1986 fri = GET_INPAYLOAD(ps, pm, fuse_rename_in); 1987 fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_ino; 1988 np = (char *)(void *)(fri + 1); 1989 (void)strlcpy(np, oldname, oldname_len); 1990 np += oldname_len; 1991 (void)strlcpy(np, newname, newname_len); 1992 1993 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 1994 goto out; 1995 1996 if (opc != targ_dir) { 1997 struct perfuse_node_data *srcdir_pnd; 1998 struct perfuse_node_data *dstdir_pnd; 1999 struct perfuse_node_data *src_pnd; 2000 2001 srcdir_pnd = PERFUSE_NODE_DATA(opc); 2002 dstdir_pnd = PERFUSE_NODE_DATA(targ_dir); 2003 src_pnd = PERFUSE_NODE_DATA(src); 2004 2005 TAILQ_REMOVE(&srcdir_pnd->pnd_children, src_pnd, pnd_next); 2006 TAILQ_INSERT_TAIL(&dstdir_pnd->pnd_children, src_pnd, pnd_next); 2007 2008 srcdir_pnd->pnd_childcount--; 2009 dstdir_pnd->pnd_childcount++; 2010 2011 src_pnd->pnd_parent = targ_dir; 2012 2013 PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY; 2014 } 2015 2016 (void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, newname, MAXPATHLEN); 2017 2018 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2019 2020 if ((struct puffs_node *)targ != NULL) 2021 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2022 2023 #ifdef PERFUSE_DEBUG 2024 if (perfuse_diagflags & PDF_FILENAME) 2025 DPRINTF("%s: nodeid = %"PRId64" file = \"%s\" renamed \"%s\" " 2026 "nodeid = %"PRId64" -> nodeid = %"PRId64" \"%s\"\n", 2027 __func__, PERFUSE_NODE_DATA(src)->pnd_ino, 2028 pcn_src->pcn_name, pcn_targ->pcn_name, 2029 PERFUSE_NODE_DATA(opc)->pnd_ino, 2030 PERFUSE_NODE_DATA(targ_dir)->pnd_ino, 2031 perfuse_node_path(targ_dir)); 2032 #endif 2033 2034 out: 2035 if (pm != NULL) 2036 ps->ps_destroy_msg(pm); 2037 2038 return error; 2039 } 2040 2041 int 2042 perfuse_node_mkdir(pu, opc, pni, pcn, vap) 2043 struct puffs_usermount *pu; 2044 puffs_cookie_t opc; 2045 struct puffs_newinfo *pni; 2046 const struct puffs_cn *pcn; 2047 const struct vattr *vap; 2048 { 2049 struct perfuse_state *ps; 2050 perfuse_msg_t *pm; 2051 struct fuse_mkdir_in *fmi; 2052 const char *path; 2053 size_t len; 2054 2055 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2056 return ENOENT; 2057 2058 ps = puffs_getspecific(pu); 2059 path = pcn->pcn_name; 2060 len = sizeof(*fmi) + pcn->pcn_namelen + 1; 2061 2062 pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, NULL); 2063 fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in); 2064 fmi->mode = vap->va_mode; 2065 fmi->umask = 0; /* Seems unused by libfuse? */ 2066 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 2067 2068 return node_mk_common(pu, opc, pni, pcn, pm); 2069 } 2070 2071 2072 int 2073 perfuse_node_rmdir(pu, opc, targ, pcn) 2074 struct puffs_usermount *pu; 2075 puffs_cookie_t opc; 2076 puffs_cookie_t targ; 2077 const struct puffs_cn *pcn; 2078 { 2079 struct perfuse_state *ps; 2080 struct perfuse_node_data *pnd; 2081 perfuse_msg_t *pm; 2082 char *path; 2083 const char *name; 2084 size_t len; 2085 int error; 2086 2087 pnd = PERFUSE_NODE_DATA(opc); 2088 if (pnd->pnd_flags & PND_REMOVED) 2089 return ENOENT; 2090 2091 /* 2092 * Await for all operations on the deleted node to drain, 2093 * as the filesystem may be confused to have it deleted 2094 * during a getattr 2095 */ 2096 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 2097 requeue_request(pu, targ, PCQ_AFTERXCHG); 2098 2099 ps = puffs_getspecific(pu); 2100 name = pcn->pcn_name; 2101 len = pcn->pcn_namelen + 1; 2102 2103 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, NULL); 2104 path = _GET_INPAYLOAD(ps, pm, char *); 2105 (void)strlcpy(path, name, len); 2106 2107 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2108 goto out; 2109 2110 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2111 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN)) 2112 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 2113 2114 /* 2115 * The parent directory needs a sync 2116 */ 2117 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2118 2119 #ifdef PERFUSE_DEBUG 2120 if (perfuse_diagflags & PDF_FILENAME) 2121 DPRINTF("%s: remove nodeid = %"PRId64" file = \"%s\"\n", 2122 __func__, PERFUSE_NODE_DATA(targ)->pnd_ino, 2123 perfuse_node_path(targ)); 2124 #endif 2125 out: 2126 ps->ps_destroy_msg(pm); 2127 2128 return error; 2129 } 2130 2131 /* vap is unused */ 2132 /* ARGSUSED4 */ 2133 int 2134 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target) 2135 struct puffs_usermount *pu; 2136 puffs_cookie_t opc; 2137 struct puffs_newinfo *pni; 2138 const struct puffs_cn *pcn_src; 2139 const struct vattr *vap; 2140 const char *link_target; 2141 { 2142 struct perfuse_state *ps; 2143 perfuse_msg_t *pm; 2144 char *np; 2145 const char *path; 2146 size_t path_len; 2147 size_t linkname_len; 2148 size_t len; 2149 2150 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2151 return ENOENT; 2152 2153 ps = puffs_getspecific(pu); 2154 path = pcn_src->pcn_name; 2155 path_len = pcn_src->pcn_namelen + 1; 2156 linkname_len = strlen(link_target) + 1; 2157 len = path_len + linkname_len; 2158 2159 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, NULL); 2160 np = _GET_INPAYLOAD(ps, pm, char *); 2161 (void)strlcpy(np, path, path_len); 2162 np += path_len; 2163 (void)strlcpy(np, link_target, linkname_len); 2164 2165 return node_mk_common(pu, opc, pni, pcn_src, pm); 2166 } 2167 2168 int 2169 perfuse_node_readdir(pu, opc, dent, readoff, 2170 reslen, pcr, eofflag, cookies, ncookies) 2171 struct puffs_usermount *pu; 2172 puffs_cookie_t opc; 2173 struct dirent *dent; 2174 off_t *readoff; 2175 size_t *reslen; 2176 const struct puffs_cred *pcr; 2177 int *eofflag; 2178 off_t *cookies; 2179 size_t *ncookies; 2180 { 2181 perfuse_msg_t *pm; 2182 uint64_t fh; 2183 struct perfuse_state *ps; 2184 struct perfuse_node_data *pnd; 2185 struct fuse_read_in *fri; 2186 struct fuse_out_header *foh; 2187 struct fuse_dirent *fd; 2188 size_t foh_len; 2189 int error; 2190 uint64_t fd_offset; 2191 size_t fd_maxlen; 2192 2193 pm = NULL; 2194 error = 0; 2195 ps = puffs_getspecific(pu); 2196 2197 /* 2198 * readdir state is kept at node level, and several readdir 2199 * requests can be issued at the same time on the same node. 2200 * We need to queue requests so that only one is in readdir 2201 * code at the same time. 2202 */ 2203 pnd = PERFUSE_NODE_DATA(opc); 2204 while (pnd->pnd_flags & PND_INREADDIR) 2205 requeue_request(pu, opc, PCQ_READDIR); 2206 pnd->pnd_flags |= PND_INREADDIR; 2207 2208 #ifdef PERFUSE_DEBUG 2209 if (perfuse_diagflags & PDF_READDIR) 2210 DPRINTF("%s: READDIR opc = %p enter critical section\n", 2211 __func__, (void *)opc); 2212 #endif 2213 /* 2214 * Do we already have the data bufered? 2215 */ 2216 if (pnd->pnd_dirent != NULL) 2217 goto out; 2218 pnd->pnd_dirent_len = 0; 2219 2220 /* 2221 * It seems NetBSD can call readdir without open first 2222 * libfuse will crash if it is done that way, hence open first. 2223 */ 2224 if (!(pnd->pnd_flags & PND_OPEN)) { 2225 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 2226 goto out; 2227 } 2228 2229 fh = perfuse_get_fh(opc, FREAD); 2230 2231 #ifdef PERFUSE_DEBUG 2232 if (perfuse_diagflags & PDF_FH) 2233 DPRINTF("%s: opc = %p, ino = %"PRId64", rfh = 0x%"PRIx64"\n", 2234 __func__, (void *)opc, 2235 PERFUSE_NODE_DATA(opc)->pnd_ino, fh); 2236 #endif 2237 2238 pnd->pnd_all_fd = NULL; 2239 pnd->pnd_all_fd_len = 0; 2240 fd_offset = 0; 2241 fd_maxlen = ps->ps_max_readahead - sizeof(*foh); 2242 2243 do { 2244 size_t fd_len; 2245 char *afdp; 2246 2247 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr); 2248 2249 /* 2250 * read_flags, lock_owner and flags are unused in libfuse 2251 */ 2252 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2253 fri->fh = fh; 2254 fri->offset = fd_offset; 2255 fri->size = (uint32_t)fd_maxlen; 2256 fri->read_flags = 0; 2257 fri->lock_owner = 0; 2258 fri->flags = 0; 2259 2260 if ((error = xchg_msg(pu, opc, pm, 2261 UNSPEC_REPLY_LEN, wait_reply)) != 0) 2262 goto out; 2263 2264 /* 2265 * There are many puffs_framebufs calls later, 2266 * therefore foh will not be valid for a long time. 2267 * Just get the length and forget it. 2268 */ 2269 foh = GET_OUTHDR(ps, pm); 2270 foh_len = foh->len; 2271 2272 /* 2273 * Empty read: we reached the end of the buffer. 2274 */ 2275 if (foh_len == sizeof(*foh)) 2276 break; 2277 2278 /* 2279 * Corrupted message. 2280 */ 2281 if (foh_len < sizeof(*foh) + sizeof(*fd)) { 2282 DWARNX("readdir reply too short"); 2283 error = EIO; 2284 goto out; 2285 } 2286 2287 2288 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent); 2289 fd_len = foh_len - sizeof(*foh); 2290 2291 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd, 2292 pnd->pnd_all_fd_len + fd_len); 2293 if (pnd->pnd_all_fd == NULL) 2294 DERR(EX_OSERR, "malloc failed"); 2295 2296 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len; 2297 (void)memcpy(afdp, fd, fd_len); 2298 2299 pnd->pnd_all_fd_len += fd_len; 2300 fd_offset += fd_len; 2301 2302 ps->ps_destroy_msg(pm); 2303 pm = NULL; 2304 2305 /* 2306 * If the buffer was not completely filled, 2307 * that is, if there is room for the biggest 2308 * struct dirent possible, then we are done: 2309 * no need to issue another READDIR to see 2310 * an empty reply. 2311 */ 2312 } while (foh_len >= fd_maxlen - (sizeof(*fd) + MAXPATHLEN)); 2313 2314 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd, pnd->pnd_all_fd_len) == -1) 2315 error = EIO; 2316 2317 out: 2318 if (pnd->pnd_all_fd != NULL) { 2319 free(pnd->pnd_all_fd); 2320 pnd->pnd_all_fd = NULL; 2321 pnd->pnd_all_fd_len = 0; 2322 } 2323 2324 if (pm != NULL) 2325 ps->ps_destroy_msg(pm); 2326 2327 if (error == 0) 2328 error = readdir_buffered(opc, dent, readoff, 2329 reslen, pcr, eofflag, cookies, ncookies); 2330 2331 /* 2332 * Schedule queued readdir requests 2333 */ 2334 pnd->pnd_flags &= ~PND_INREADDIR; 2335 (void)dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL); 2336 2337 #ifdef PERFUSE_DEBUG 2338 if (perfuse_diagflags & PDF_READDIR) 2339 DPRINTF("%s: READDIR opc = %p exit critical section\n", 2340 __func__, (void *)opc); 2341 #endif 2342 2343 return error; 2344 } 2345 2346 int 2347 perfuse_node_readlink(pu, opc, pcr, linkname, linklen) 2348 struct puffs_usermount *pu; 2349 puffs_cookie_t opc; 2350 const struct puffs_cred *pcr; 2351 char *linkname; 2352 size_t *linklen; 2353 { 2354 struct perfuse_state *ps; 2355 perfuse_msg_t *pm; 2356 int error; 2357 size_t len; 2358 struct fuse_out_header *foh; 2359 2360 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2361 return ENOENT; 2362 2363 ps = puffs_getspecific(pu); 2364 2365 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr); 2366 2367 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2368 goto out; 2369 2370 foh = GET_OUTHDR(ps, pm); 2371 len = foh->len - sizeof(*foh); 2372 if (len > *linklen) 2373 DERRX(EX_PROTOCOL, "path len = %zd too long", len); 2374 if (len == 0) 2375 DERRX(EX_PROTOCOL, "path len = %zd too short", len); 2376 2377 /* 2378 * FUSE filesystems return a NUL terminated string, we 2379 * do not want to trailing \0 2380 */ 2381 *linklen = len - 1; 2382 (void)memcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len); 2383 out: 2384 ps->ps_destroy_msg(pm); 2385 2386 return error; 2387 } 2388 2389 int 2390 perfuse_node_reclaim(pu, opc) 2391 struct puffs_usermount *pu; 2392 puffs_cookie_t opc; 2393 { 2394 struct perfuse_state *ps; 2395 perfuse_msg_t *pm; 2396 struct perfuse_node_data *pnd; 2397 struct fuse_forget_in *ffi; 2398 struct puffs_node *pn; 2399 struct puffs_node *pn_root; 2400 2401 ps = puffs_getspecific(pu); 2402 pnd = PERFUSE_NODE_DATA(opc); 2403 2404 /* 2405 * Never forget the root. 2406 */ 2407 if (pnd->pnd_ino == FUSE_ROOT_ID) 2408 return 0; 2409 2410 pnd->pnd_flags |= PND_RECLAIMED; 2411 2412 #ifdef PERFUSE_DEBUG 2413 if (perfuse_diagflags & PDF_RECLAIM) 2414 DPRINTF("%s (nodeid %"PRId64") reclaimed\n", 2415 perfuse_node_path(opc), pnd->pnd_ino); 2416 #endif 2417 2418 pn_root = puffs_getroot(pu); 2419 pn = (struct puffs_node *)opc; 2420 while (pn != pn_root) { 2421 struct puffs_node *parent_pn; 2422 2423 pnd = PERFUSE_NODE_DATA(pn); 2424 2425 #ifdef PERFUSE_DEBUG 2426 if (perfuse_diagflags & PDF_RECLAIM) 2427 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, " 2428 "has childcount %d %s%s%s%s, pending ops:%s%s%s\n", 2429 perfuse_node_path((puffs_cookie_t)pn), pnd->pnd_ino, 2430 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ", 2431 pnd->pnd_childcount, 2432 pnd->pnd_flags & PND_OPEN ? "open " : "not open", 2433 pnd->pnd_flags & PND_RFH ? "r" : "", 2434 pnd->pnd_flags & PND_WFH ? "w" : "", 2435 pnd->pnd_flags & PND_BUSY ? "" : " none", 2436 pnd->pnd_flags & PND_INREADDIR ? " readdir" : "", 2437 pnd->pnd_flags & PND_INWRITE ? " write" : "", 2438 pnd->pnd_flags & PND_INOPEN ? " open" : ""); 2439 #endif 2440 2441 if (!(pnd->pnd_flags & PND_RECLAIMED) || 2442 (pnd->pnd_childcount != 0)) 2443 return 0; 2444 2445 #ifdef PERFUSE_DEBUG 2446 if ((pnd->pnd_flags & PND_OPEN) || 2447 !TAILQ_EMPTY(&pnd->pnd_pcq)) 2448 DERRX(EX_SOFTWARE, "%s: opc = %p: still open", 2449 __func__, (void *)opc); 2450 2451 if ((pnd->pnd_flags & PND_BUSY) || 2452 !TAILQ_EMPTY(&pnd->pnd_pcq)) 2453 DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations", 2454 __func__, (void *)opc); 2455 #endif 2456 2457 /* 2458 * Send the FORGET message 2459 */ 2460 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET, 2461 sizeof(*ffi), NULL); 2462 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in); 2463 ffi->nlookup = pnd->pnd_nlookup; 2464 2465 /* 2466 * No reply is expected, pm is freed in xchg_msg 2467 */ 2468 (void)xchg_msg(pu, (puffs_cookie_t)pn, 2469 pm, UNSPEC_REPLY_LEN, no_reply); 2470 2471 parent_pn = pnd->pnd_parent; 2472 2473 perfuse_destroy_pn(pn); 2474 2475 pn = parent_pn; 2476 } 2477 2478 return 0; 2479 } 2480 2481 int 2482 perfuse_node_inactive(pu, opc) 2483 struct puffs_usermount *pu; 2484 puffs_cookie_t opc; 2485 { 2486 struct perfuse_state *ps; 2487 struct perfuse_node_data *pnd; 2488 2489 ps = puffs_getspecific(pu); 2490 pnd = PERFUSE_NODE_DATA(opc); 2491 2492 if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED))) 2493 return 0; 2494 2495 /* 2496 * Make sure all operation are finished 2497 * There can be an ongoing write. Other 2498 * operation wait for all data before 2499 * the close/inactive. 2500 */ 2501 while (pnd->pnd_flags & PND_INWRITE) 2502 requeue_request(pu, opc, PCQ_AFTERWRITE); 2503 2504 /* 2505 * The inactive operation may be cancelled. 2506 * If no open is in progress, set PND_INOPEN 2507 * so that a new open will be queued. 2508 */ 2509 if (pnd->pnd_flags & PND_INOPEN) 2510 return 0; 2511 2512 pnd->pnd_flags |= PND_INOPEN; 2513 2514 /* 2515 * Sync data 2516 */ 2517 if (pnd->pnd_flags & PND_DIRTY) 2518 (void)perfuse_node_fsync(pu, opc, NULL, 0, 0, 0); 2519 2520 /* 2521 * Close handles 2522 */ 2523 if (pnd->pnd_flags & PND_WFH) 2524 (void)perfuse_node_close_common(pu, opc, FWRITE); 2525 2526 if (pnd->pnd_flags & PND_RFH) 2527 (void)perfuse_node_close_common(pu, opc, FREAD); 2528 2529 /* 2530 * This will cause a reclaim to be sent 2531 */ 2532 if (pnd->pnd_flags & PND_REMOVED) 2533 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 2534 2535 /* 2536 * Schedule awaiting operations 2537 */ 2538 pnd->pnd_flags &= ~PND_INOPEN; 2539 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL); 2540 2541 return 0; 2542 } 2543 2544 2545 /* ARGSUSED0 */ 2546 int 2547 perfuse_node_print(pu, opc) 2548 struct puffs_usermount *pu; 2549 puffs_cookie_t opc; 2550 { 2551 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2552 return 0; 2553 } 2554 2555 /* ARGSUSED0 */ 2556 int 2557 perfuse_node_pathconf(pu, opc, name, retval) 2558 struct puffs_usermount *pu; 2559 puffs_cookie_t opc; 2560 int name; 2561 int *retval; 2562 { 2563 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2564 return 0; 2565 } 2566 2567 /* id is unused */ 2568 /* ARGSUSED2 */ 2569 int 2570 perfuse_node_advlock(pu, opc, id, op, fl, flags) 2571 struct puffs_usermount *pu; 2572 puffs_cookie_t opc; 2573 void *id; 2574 int op; 2575 struct flock *fl; 2576 int flags; 2577 { 2578 struct perfuse_state *ps; 2579 int fop; 2580 perfuse_msg_t *pm; 2581 struct fuse_lk_in *fli; 2582 struct fuse_out_header *foh; 2583 struct fuse_lk_out *flo; 2584 uint32_t owner; 2585 size_t len; 2586 int error; 2587 2588 ps = puffs_getspecific(pu); 2589 2590 if (op == F_GETLK) 2591 fop = FUSE_GETLK; 2592 else 2593 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK; 2594 2595 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL); 2596 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in); 2597 fli->fh = perfuse_get_fh(opc, FWRITE); 2598 fli->owner = fl->l_pid; 2599 fli->lk.start = fl->l_start; 2600 fli->lk.end = fl->l_start + fl->l_len; 2601 fli->lk.type = fl->l_type; 2602 fli->lk.pid = fl->l_pid; 2603 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0; 2604 2605 owner = fl->l_pid; 2606 2607 #ifdef PERFUSE_DEBUG 2608 if (perfuse_diagflags & PDF_FH) 2609 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 2610 __func__, (void *)opc, 2611 PERFUSE_NODE_DATA(opc)->pnd_ino, fli->fh); 2612 #endif 2613 2614 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2615 goto out; 2616 2617 foh = GET_OUTHDR(ps, pm); 2618 len = foh->len - sizeof(*foh); 2619 2620 /* 2621 * Save or clear the lock 2622 */ 2623 switch (op) { 2624 case F_GETLK: 2625 if (len != sizeof(*flo)) 2626 DERRX(EX_SOFTWARE, 2627 "%s: Unexpected lock reply len %zd", 2628 __func__, len); 2629 2630 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out); 2631 fl->l_start = flo->lk.start; 2632 fl->l_len = flo->lk.end - flo->lk.start; 2633 fl->l_pid = flo->lk.pid; 2634 fl->l_type = flo->lk.type; 2635 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */ 2636 2637 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid; 2638 break; 2639 case F_UNLCK: 2640 owner = 0; 2641 /* FALLTHROUGH */ 2642 case F_SETLK: 2643 /* FALLTHROUGH */ 2644 case F_SETLKW: 2645 if (error != 0) 2646 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = owner; 2647 2648 if (len != 0) 2649 DERRX(EX_SOFTWARE, 2650 "%s: Unexpected unlock reply len %zd", 2651 __func__, len); 2652 2653 break; 2654 default: 2655 DERRX(EX_SOFTWARE, "%s: Unexpected op %d", __func__, op); 2656 break; 2657 } 2658 2659 out: 2660 ps->ps_destroy_msg(pm); 2661 2662 return error; 2663 } 2664 2665 int 2666 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag) 2667 struct puffs_usermount *pu; 2668 puffs_cookie_t opc; 2669 uint8_t *buf; 2670 off_t offset; 2671 size_t *resid; 2672 const struct puffs_cred *pcr; 2673 int ioflag; 2674 { 2675 struct perfuse_state *ps; 2676 struct perfuse_node_data *pnd; 2677 perfuse_msg_t *pm; 2678 struct fuse_read_in *fri; 2679 struct fuse_out_header *foh; 2680 size_t readen; 2681 int error; 2682 2683 ps = puffs_getspecific(pu); 2684 pnd = PERFUSE_NODE_DATA(opc); 2685 pm = NULL; 2686 2687 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR) 2688 return EBADF; 2689 2690 do { 2691 size_t max_read; 2692 2693 max_read = ps->ps_max_readahead - sizeof(*foh); 2694 /* 2695 * flags may be set to FUSE_READ_LOCKOWNER 2696 * if lock_owner is provided. 2697 */ 2698 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr); 2699 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2700 fri->fh = perfuse_get_fh(opc, FREAD); 2701 fri->offset = offset; 2702 fri->size = (uint32_t)MIN(*resid, max_read); 2703 fri->read_flags = 0; /* XXX Unused by libfuse? */ 2704 fri->lock_owner = pnd->pnd_lock_owner; 2705 fri->flags = 0; 2706 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0; 2707 2708 #ifdef PERFUSE_DEBUG 2709 if (perfuse_diagflags & PDF_FH) 2710 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 2711 __func__, (void *)opc, pnd->pnd_ino, fri->fh); 2712 #endif 2713 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply); 2714 2715 if (error != 0) 2716 goto out; 2717 2718 foh = GET_OUTHDR(ps, pm); 2719 readen = foh->len - sizeof(*foh); 2720 2721 #ifdef PERFUSE_DEBUG 2722 if (readen > *resid) 2723 DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd", 2724 __func__, readen); 2725 #endif 2726 2727 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen); 2728 2729 buf += readen; 2730 offset += readen; 2731 *resid -= readen; 2732 2733 ps->ps_destroy_msg(pm); 2734 pm = NULL; 2735 } while ((*resid != 0) && (readen != 0)); 2736 2737 if (ioflag & (IO_SYNC|IO_DSYNC)) 2738 ps->ps_syncreads++; 2739 else 2740 ps->ps_asyncreads++; 2741 2742 out: 2743 if (pm != NULL) 2744 ps->ps_destroy_msg(pm); 2745 2746 return error; 2747 } 2748 2749 int 2750 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag) 2751 struct puffs_usermount *pu; 2752 puffs_cookie_t opc; 2753 uint8_t *buf; 2754 off_t offset; 2755 size_t *resid; 2756 const struct puffs_cred *pcr; 2757 int ioflag; 2758 { 2759 struct perfuse_state *ps; 2760 struct perfuse_node_data *pnd; 2761 struct vattr *vap; 2762 perfuse_msg_t *pm; 2763 struct fuse_write_in *fwi; 2764 struct fuse_write_out *fwo; 2765 size_t data_len; 2766 size_t payload_len; 2767 size_t written; 2768 int error; 2769 2770 ps = puffs_getspecific(pu); 2771 pnd = PERFUSE_NODE_DATA(opc); 2772 vap = puffs_pn_getvap((struct puffs_node *)opc); 2773 written = 0; 2774 pm = NULL; 2775 2776 if (vap->va_type == VDIR) 2777 return EBADF; 2778 2779 /* 2780 * We need to queue write requests in order to avoid 2781 * dequeueing PCQ_AFTERWRITE when there are pending writes. 2782 */ 2783 while (pnd->pnd_flags & PND_INWRITE) 2784 requeue_request(pu, opc, PCQ_WRITE); 2785 pnd->pnd_flags |= PND_INWRITE; 2786 2787 /* 2788 * append flag: re-read the file size so that 2789 * we get the latest value. 2790 */ 2791 if (ioflag & PUFFS_IO_APPEND) { 2792 if ((error = perfuse_node_getattr(pu, opc, vap, pcr)) != 0) 2793 goto out; 2794 2795 offset = vap->va_size; 2796 } 2797 2798 pm = NULL; 2799 2800 do { 2801 size_t max_write; 2802 /* 2803 * There is a writepage flag when data 2804 * is aligned to page size. Use it for 2805 * everything but the data after the last 2806 * page boundary. 2807 */ 2808 max_write = ps->ps_max_write - sizeof(*fwi); 2809 2810 data_len = MIN(*resid, max_write); 2811 if (data_len > (size_t)sysconf(_SC_PAGESIZE)) 2812 data_len = data_len & ~(sysconf(_SC_PAGESIZE) - 1); 2813 2814 payload_len = data_len + sizeof(*fwi); 2815 2816 /* 2817 * flags may be set to FUSE_WRITE_CACHE (XXX usage?) 2818 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided. 2819 * write_flags is set to 1 for writepage. 2820 */ 2821 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr); 2822 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in); 2823 fwi->fh = perfuse_get_fh(opc, FWRITE); 2824 fwi->offset = offset; 2825 fwi->size = (uint32_t)data_len; 2826 fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1; 2827 fwi->lock_owner = pnd->pnd_lock_owner; 2828 fwi->flags = 0; 2829 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0; 2830 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE; 2831 (void)memcpy((fwi + 1), buf, data_len); 2832 2833 2834 #ifdef PERFUSE_DEBUG 2835 if (perfuse_diagflags & PDF_FH) 2836 DPRINTF("%s: opc = %p, ino = %"PRId64", " 2837 "fh = 0x%"PRIx64"\n", __func__, 2838 (void *)opc, pnd->pnd_ino, fwi->fh); 2839 #endif 2840 if ((error = xchg_msg(pu, opc, pm, 2841 sizeof(*fwo), wait_reply)) != 0) 2842 goto out; 2843 2844 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out); 2845 written = fwo->size; 2846 #ifdef PERFUSE_DEBUG 2847 if (written > *resid) 2848 DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd", 2849 __func__, written); 2850 #endif 2851 *resid -= written; 2852 offset += written; 2853 buf += written; 2854 2855 ps->ps_destroy_msg(pm); 2856 pm = NULL; 2857 } while (*resid != 0); 2858 2859 /* 2860 * puffs_ops(3) says 2861 * "everything must be written or an error will be generated" 2862 */ 2863 if (*resid != 0) 2864 error = EFBIG; 2865 2866 /* 2867 * Update file size if we wrote beyond the end 2868 */ 2869 if (offset > (off_t)vap->va_size) 2870 vap->va_size = offset; 2871 2872 /* 2873 * Statistics 2874 */ 2875 if (ioflag & (IO_SYNC|IO_DSYNC)) 2876 ps->ps_syncwrites++; 2877 else 2878 ps->ps_asyncwrites++; 2879 2880 /* 2881 * Remember to sync the file 2882 */ 2883 pnd->pnd_flags |= PND_DIRTY; 2884 2885 #ifdef PERFUSE_DEBUG 2886 if (perfuse_diagflags & PDF_SYNC) 2887 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n", 2888 __func__, (void*)opc, perfuse_node_path(opc)); 2889 #endif 2890 out: 2891 if (pm != NULL) 2892 ps->ps_destroy_msg(pm); 2893 2894 /* 2895 * If there are no more queued write, we can resume 2896 * an operation awaiting write completion. 2897 */ 2898 pnd->pnd_flags &= ~PND_INWRITE; 2899 if (dequeue_requests(ps, opc, PCQ_WRITE, 1) == 0) 2900 (void)dequeue_requests(ps, opc, PCQ_AFTERWRITE, DEQUEUE_ALL); 2901 2902 return error; 2903 } 2904 2905 /* ARGSUSED0 */ 2906 void 2907 perfuse_cache_write(pu, opc, size, runs) 2908 struct puffs_usermount *pu; 2909 puffs_cookie_t opc; 2910 size_t size; 2911 struct puffs_cacherun *runs; 2912 { 2913 return; 2914 } 2915 2916