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