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