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