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