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