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