fuse_internal.c revision 241519
1339631Sphilip/* 2339631Sphilip * Copyright (c) 2007-2009 Google Inc. and Amit Singh 3192886Sedwin * All rights reserved. 4192886Sedwin * 564499Swollman * Redistribution and use in source and binary forms, with or without 6273719Sedwin * modification, are permitted provided that the following conditions are 72742Swollman * met: 8273719Sedwin * 9273719Sedwin * * Redistributions of source code must retain the above copyright 102742Swollman * notice, this list of conditions and the following disclaimer. 11316350Sbapt * * Redistributions in binary form must reproduce the above 12274563Sedwin * copyright notice, this list of conditions and the following disclaimer 13274563Sedwin * in the documentation and/or other materials provided with the 14158421Swollman * distribution. 15158421Swollman * * Neither the name of Google Inc. nor the names of its 16274563Sedwin * contributors may be used to endorse or promote products derived from 172742Swollman * this software without specific prior written permission. 18316350Sbapt * 19316350Sbapt * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2020094Swollman * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2120094Swollman * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22274563Sedwin * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23274563Sedwin * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2420094Swollman * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25274563Sedwin * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26274563Sedwin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27325160Sphilip * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2820094Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29316350Sbapt * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30328476Sphilip * 31316350Sbapt * Copyright (C) 2005 Csaba Henk. 32316350Sbapt * All rights reserved. 332742Swollman * 342742Swollman * Redistribution and use in source and binary forms, with or without 352742Swollman * modification, are permitted provided that the following conditions 362742Swollman * are met: 372742Swollman * 1. Redistributions of source code must retain the above copyright 382742Swollman * notice, this list of conditions and the following disclaimer. 392742Swollman * 2. Redistributions in binary form must reproduce the above copyright 4019878Swollman * notice, this list of conditions and the following disclaimer in the 412742Swollman * documentation and/or other materials provided with the distribution. 422742Swollman * 432742Swollman * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 44270817Spluknet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 452742Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 462742Swollman * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 47149514Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4821217Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 499908Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 509908Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 512742Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52331663Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5319878Swollman * SUCH DAMAGE. 54331663Sphilip */ 5519878Swollman 56331663Sphilip#include <sys/cdefs.h> 57331663Sphilip__FBSDID("$FreeBSD: head/sys/fs/fuse/fuse_internal.c 241519 2012-10-13 23:54:26Z attilio $"); 5819878Swollman 59331663Sphilip#include <sys/types.h> 6019878Swollman#include <sys/module.h> 61331663Sphilip#include <sys/systm.h> 6219878Swollman#include <sys/errno.h> 63331663Sphilip#include <sys/param.h> 6419878Swollman#include <sys/kernel.h> 65331663Sphilip#include <sys/conf.h> 6619878Swollman#include <sys/uio.h> 67331663Sphilip#include <sys/malloc.h> 6893799Swollman#include <sys/queue.h> 69331663Sphilip#include <sys/lock.h> 7058787Sru#include <sys/mutex.h> 71331663Sphilip#include <sys/sx.h> 7219878Swollman#include <sys/proc.h> 73331663Sphilip#include <sys/mount.h> 749908Swollman#include <sys/vnode.h> 75149514Swollman#include <sys/namei.h> 769908Swollman#include <sys/stat.h> 779908Swollman#include <sys/unistd.h> 78270817Spluknet#include <sys/filedesc.h> 7921217Swollman#include <sys/file.h> 8019878Swollman#include <sys/fcntl.h> 81331663Sphilip#include <sys/dirent.h> 829908Swollman#include <sys/bio.h> 83149514Swollman#include <sys/buf.h> 849908Swollman#include <sys/sysctl.h> 859908Swollman#include <sys/priv.h> 869908Swollman 879908Swollman#include "fuse.h" 8858787Sru#include "fuse_file.h" 8958787Sru#include "fuse_internal.h" 9058787Sru#include "fuse_ipc.h" 9164499Swollman#include "fuse_node.h" 92331663Sphilip#include "fuse_file.h" 93175034Sedwin#include "fuse_param.h" 94175034Sedwin 95175034Sedwin#define FUSE_DEBUG_MODULE INTERNAL 96175034Sedwin#include "fuse_debug.h" 97175034Sedwin 9858787Sru#ifdef ZERO_PAD_INCOMPLETE_BUFS 9958787Srustatic int isbzero(void *buf, size_t len); 100270817Spluknet 10158787Sru#endif 10258787Sru 10358787Sru/* access */ 104270817Spluknet 10564499Swollmanint 106270817Spluknetfuse_internal_access(struct vnode *vp, 10764499Swollman mode_t mode, 10864499Swollman struct fuse_access_param *facp, 10986222Swollman struct thread *td, 11086222Swollman struct ucred *cred) 11186222Swollman{ 11286222Swollman int err = 0; 11386222Swollman uint32_t mask = 0; 114286751Sedwin int dataflags; 11586222Swollman int vtype; 11686222Swollman struct mount *mp; 11786222Swollman struct fuse_dispatcher fdi; 11886222Swollman struct fuse_access_in *fai; 11986222Swollman struct fuse_data *data; 12086222Swollman 12186222Swollman /* NOT YET DONE */ 12286222Swollman /* 12386222Swollman * If this vnop gives you trouble, just return 0 here for a lazy 12486222Swollman * kludge. 12586222Swollman */ 12686222Swollman /* return 0;*/ 12786222Swollman 12886222Swollman fuse_trace_printf_func(); 12986222Swollman 13086222Swollman mp = vnode_mount(vp); 13186222Swollman vtype = vnode_vtype(vp); 132175034Sedwin 133175034Sedwin data = fuse_get_mpdata(mp); 134175034Sedwin dataflags = data->dataflags; 135175034Sedwin 136175034Sedwin if ((mode & VWRITE) && vfs_isrdonly(mp)) { 137175034Sedwin return EACCES; 138175034Sedwin } 139270817Spluknet /* Unless explicitly permitted, deny everyone except the fs owner. */ 140175034Sedwin if (vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) { 141270817Spluknet if (!(dataflags & FSESS_DAEMON_CAN_SPY)) { 142175034Sedwin int denied = fuse_match_cred(data->daemoncred, 143175034Sedwin cred); 144175034Sedwin 145175034Sedwin if (denied) { 146175034Sedwin return EPERM; 147175034Sedwin } 148175034Sedwin } 149175034Sedwin facp->facc_flags |= FACCESS_NOCHECKSPY; 150183066Sedwin } 151183066Sedwin if (!(facp->facc_flags & FACCESS_DO_ACCESS)) { 152183066Sedwin return 0; 153183066Sedwin } 154183066Sedwin if (((vtype == VREG) && (mode & VEXEC))) { 155183066Sedwin#ifdef NEED_MOUNT_ARGUMENT_FOR_THIS 156183066Sedwin /* Let the kernel handle this through open / close heuristics.*/ 157183066Sedwin return ENOTSUP; 158286751Sedwin#else 159286751Sedwin /* Let the kernel handle this. */ 160286751Sedwin return 0; 161183864Sedwin#endif 162286751Sedwin } 163183864Sedwin if (!fsess_isimpl(mp, FUSE_ACCESS)) { 164183864Sedwin /* Let the kernel handle this. */ 165183864Sedwin return 0; 166184406Sedwin } 167273719Sedwin if (dataflags & FSESS_DEFAULT_PERMISSIONS) { 168273719Sedwin /* Let the kernel handle this. */ 169184406Sedwin return 0; 170184406Sedwin } 171270817Spluknet if ((mode & VADMIN) != 0) { 172270817Spluknet err = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); 173270817Spluknet if (err) { 174270817Spluknet return err; 175184406Sedwin } 176184406Sedwin } 177273719Sedwin if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) { 178273719Sedwin mask |= W_OK; 179273719Sedwin } 180184406Sedwin if ((mode & VREAD) != 0) { 181184406Sedwin mask |= R_OK; 182198515Sedwin } 183198515Sedwin if ((mode & VEXEC) != 0) { 184198515Sedwin mask |= X_OK; 185273719Sedwin } 186273719Sedwin bzero(&fdi, sizeof(fdi)); 187198515Sedwin 188270817Spluknet fdisp_init(&fdi, sizeof(*fai)); 189270817Spluknet fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred); 190270817Spluknet 191270817Spluknet fai = fdi.indata; 192270817Spluknet fai->mask = F_OK; 193270817Spluknet fai->mask |= mask; 194198515Sedwin 195331663Sphilip err = fdisp_wait_answ(&fdi); 196198515Sedwin fdisp_destroy(&fdi); 197331663Sphilip 198240457Sedwin if (err == ENOSYS) { 199136638Swollman fsess_set_notimpl(mp, FUSE_ACCESS); 200136638Swollman err = 0; 201136638Swollman } 202136638Swollman return err; 203136638Swollman} 204136638Swollman 205136638Swollman/* fsync */ 20693799Swollman 207331663Sphilipint 208273719Sedwinfuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio) 209273719Sedwin{ 210270817Spluknet fuse_trace_printf_func(); 21193799Swollman 212331663Sphilip if (tick->tk_aw_ohead.error == ENOSYS) { 213331663Sphilip fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick)); 214331663Sphilip } 215136638Swollman return 0; 216136638Swollman} 217136638Swollman 218136638Swollmanint 219136638Swollmanfuse_internal_fsync(struct vnode *vp, 220136638Swollman struct thread *td, 221136638Swollman struct ucred *cred, 222136638Swollman struct fuse_filehandle *fufh) 223136638Swollman{ 224136638Swollman int op = FUSE_FSYNC; 225136638Swollman struct fuse_fsync_in *ffsi; 226136638Swollman struct fuse_dispatcher fdi; 227270817Spluknet 228136638Swollman fuse_trace_printf_func(); 229136638Swollman 230270817Spluknet if (vnode_isdir(vp)) { 231136638Swollman op = FUSE_FSYNCDIR; 232136638Swollman } 233136638Swollman fdisp_init(&fdi, sizeof(*ffsi)); 234136638Swollman fdisp_make_vp(&fdi, op, vp, td, cred); 235136638Swollman ffsi = fdi.indata; 236136638Swollman ffsi->fh = fufh->fh_id; 237136638Swollman 238136638Swollman ffsi->fsync_flags = 1; /* datasync */ 239136638Swollman 240136638Swollman fuse_insert_callback(fdi.tick, fuse_internal_fsync_callback); 241136638Swollman fuse_insert_message(fdi.tick); 242136638Swollman 243136638Swollman fdisp_destroy(&fdi); 244136638Swollman 245136638Swollman return 0; 246136638Swollman 247136638Swollman} 248136638Swollman 249136638Swollman/* readdir */ 250136638Swollman 251136638Swollmanint 252136638Swollmanfuse_internal_readdir(struct vnode *vp, 253136638Swollman struct uio *uio, 254136638Swollman struct fuse_filehandle *fufh, 255136638Swollman struct fuse_iov *cookediov) 256136638Swollman{ 257136638Swollman int err = 0; 258136638Swollman struct fuse_dispatcher fdi; 259136638Swollman struct fuse_read_in *fri; 26093799Swollman 261177591Sedwin if (uio_resid(uio) == 0) { 262177591Sedwin return 0; 263177591Sedwin } 264177591Sedwin fdisp_init(&fdi, 0); 265270817Spluknet 266177591Sedwin /* 267177591Sedwin * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p 268177591Sedwin * I/O). 269177591Sedwin */ 270177591Sedwin 271177591Sedwin while (uio_resid(uio) > 0) { 272325160Sphilip 273325160Sphilip fdi.iosize = sizeof(*fri); 274177591Sedwin fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); 275270817Spluknet 276177591Sedwin fri = fdi.indata; 277177591Sedwin fri->fh = fufh->fh_id; 278177591Sedwin fri->offset = uio_offset(uio); 279177591Sedwin fri->size = min(uio_resid(uio), FUSE_DEFAULT_IOSIZE); 280177591Sedwin /* mp->max_read */ 281240457Sedwin 282240457Sedwin if ((err = fdisp_wait_answ(&fdi))) { 283240457Sedwin break; 284273719Sedwin } 285177591Sedwin if ((err = fuse_internal_readdir_processdata(uio, fri->size, fdi.answ, 286177591Sedwin fdi.iosize, cookediov))) { 287177591Sedwin break; 288177591Sedwin } 289177591Sedwin } 290270817Spluknet 291177591Sedwin fdisp_destroy(&fdi); 292177591Sedwin return ((err == -1) ? 0 : err); 293177591Sedwin} 294177591Sedwin 295177591Sedwinint 296177591Sedwinfuse_internal_readdir_processdata(struct uio *uio, 297177591Sedwin size_t reqsize, 298177591Sedwin void *buf, 299177591Sedwin size_t bufsize, 300177591Sedwin void *param) 301177591Sedwin{ 302177591Sedwin int err = 0; 303177591Sedwin int cou = 0; 304177591Sedwin int bytesavail; 305177591Sedwin size_t freclen; 306177591Sedwin 307177591Sedwin struct dirent *de; 308177591Sedwin struct fuse_dirent *fudge; 309177591Sedwin struct fuse_iov *cookediov = param; 310177591Sedwin 311177591Sedwin if (bufsize < FUSE_NAME_OFFSET) { 312177591Sedwin return -1; 313177591Sedwin } 314177591Sedwin for (;;) { 315177591Sedwin 316273719Sedwin if (bufsize < FUSE_NAME_OFFSET) { 317273719Sedwin err = -1; 318273719Sedwin break; 319181421Sedwin } 320181421Sedwin fudge = (struct fuse_dirent *)buf; 321181421Sedwin freclen = FUSE_DIRENT_SIZE(fudge); 322181421Sedwin 323181421Sedwin cou++; 324190372Sedwin 325190372Sedwin if (bufsize < freclen) { 326190372Sedwin err = ((cou == 1) ? -1 : 0); 327190372Sedwin break; 32893799Swollman } 329190372Sedwin#ifdef ZERO_PAD_INCOMPLETE_BUFS 330190372Sedwin if (isbzero(buf, FUSE_NAME_OFFSET)) { 331270817Spluknet err = -1; 332270817Spluknet break; 333190372Sedwin } 334248307Sedwin#endif 335190372Sedwin 336240457Sedwin if (!fudge->namelen || fudge->namelen > MAXNAMLEN) { 337248307Sedwin err = EINVAL; 338248307Sedwin break; 339190372Sedwin } 340190372Sedwin bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *) 341190372Sedwin &fudge->namelen); 342190372Sedwin 343190372Sedwin if (bytesavail > uio_resid(uio)) { 344190372Sedwin err = -1; 345198515Sedwin break; 346198515Sedwin } 347190372Sedwin fiov_refresh(cookediov); 348198515Sedwin fiov_adjust(cookediov, bytesavail); 349198515Sedwin 350198515Sedwin de = (struct dirent *)cookediov->base; 351198515Sedwin de->d_fileno = fudge->ino; /* XXX: truncation */ 352198515Sedwin de->d_reclen = bytesavail; 353198515Sedwin de->d_type = fudge->type; 354197597Sedwin de->d_namlen = fudge->namelen; 355198515Sedwin memcpy((char *)cookediov->base + sizeof(struct dirent) - 356197597Sedwin MAXNAMLEN - 1, 357198515Sedwin (char *)buf + FUSE_NAME_OFFSET, fudge->namelen); 358198515Sedwin ((char *)cookediov->base)[bytesavail] = '\0'; 359198515Sedwin 360198515Sedwin err = uiomove(cookediov->base, cookediov->len, uio); 361198515Sedwin if (err) { 362198515Sedwin break; 363198515Sedwin } 364198515Sedwin buf = (char *)buf + freclen; 365198515Sedwin bufsize -= freclen; 366198515Sedwin uio_setoffset(uio, fudge->off); 367198515Sedwin } 368198515Sedwin 369198515Sedwin return err; 370197597Sedwin} 371206868Sedwin 372273719Sedwin/* remove */ 373206868Sedwin 374270817Spluknet#ifdef XXXIP 375206868Sedwinstatic int 376206868Sedwinfuse_internal_remove_callback(struct vnode *vp, void *cargs) 377270817Spluknet{ 378206868Sedwin struct vattr *vap; 379206868Sedwin uint64_t target_nlink; 380206868Sedwin 381206868Sedwin vap = VTOVA(vp); 382206868Sedwin 383206868Sedwin target_nlink = *(uint64_t *)cargs; 384206868Sedwin 385206868Sedwin /* somewhat lame "heuristics", but you got better ideas? */ 386206868Sedwin if ((vap->va_nlink == target_nlink) && vnode_isreg(vp)) { 387206868Sedwin fuse_invalidate_attr(vp); 388331663Sphilip } 389307362Sbapt return 0; 390331663Sphilip} 391307362Sbapt 392325160Sphilip#endif 393257697Sedwin 394257697Sedwin#define INVALIDATE_CACHED_VATTRS_UPON_UNLINK 1 395257697Sedwinint 396257697Sedwinfuse_internal_remove(struct vnode *dvp, 397339631Sphilip struct vnode *vp, 398257697Sedwin struct componentname *cnp, 3992742Swollman enum fuse_opcode op) 40020094Swollman{ 401136638Swollman struct fuse_dispatcher fdi; 402273719Sedwin 403273719Sedwin struct vattr *vap = VTOVA(vp); 404316350Sbapt 405316350Sbapt#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK 406316350Sbapt int need_invalidate = 0; 407316350Sbapt uint64_t target_nlink = 0; 408316350Sbapt 40920094Swollman#endif 410270817Spluknet int err = 0; 411184406Sedwin 41220094Swollman debug_printf("dvp=%p, cnp=%p, op=%d\n", vp, cnp, op); 413158421Swollman 41493799Swollman fdisp_init(&fdi, cnp->cn_namelen + 1); 41593799Swollman fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred); 41693799Swollman 41793799Swollman memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 41893799Swollman ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 41993799Swollman 420136638Swollman#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK 42193799Swollman if (vap->va_nlink > 1) { 422316350Sbapt need_invalidate = 1; 423316350Sbapt target_nlink = vap->va_nlink; 424316350Sbapt } 425316350Sbapt#endif 426316350Sbapt 427316350Sbapt err = fdisp_wait_answ(&fdi); 428316350Sbapt fdisp_destroy(&fdi); 42920094Swollman 430270817Spluknet fuse_invalidate_attr(dvp); 431184406Sedwin fuse_invalidate_attr(vp); 432184406Sedwin 433316350Sbapt#ifdef XXXIP 434316350Sbapt /* 435316350Sbapt * XXX: INVALIDATE_CACHED_VATTRS_UPON_UNLINK 436316350Sbapt * 437316350Sbapt * Consider the case where vap->va_nlink > 1 for the entity being 438316350Sbapt * removed. In our world, other in-memory vnodes that share a link 439316350Sbapt * count each with this one may not know right way that this one just 440316350Sbapt * got deleted. We should let them know, say, through a vnode_iterate() 441184406Sedwin * here and a callback that does fuse_invalidate_attr(vp) on each 442270817Spluknet * relevant vnode. 443136638Swollman */ 444136638Swollman if (need_invalidate && !err) { 445316350Sbapt vnode_iterate(vnode_mount(vp), 0, fuse_internal_remove_callback, 446316350Sbapt (void *)&target_nlink); 447316350Sbapt } 448316350Sbapt#endif 449316350Sbapt 450316350Sbapt return err; 451316350Sbapt} 452316350Sbapt 453316350Sbapt/* rename */ 454136638Swollman 455136638Swollmanint 456136638Swollmanfuse_internal_rename(struct vnode *fdvp, 457136638Swollman struct componentname *fcnp, 458316350Sbapt struct vnode *tdvp, 459316350Sbapt struct componentname *tcnp) 460316350Sbapt{ 461316350Sbapt struct fuse_dispatcher fdi; 462316350Sbapt struct fuse_rename_in *fri; 463316350Sbapt int err = 0; 464316350Sbapt 465316350Sbapt fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2); 466316350Sbapt fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred); 467316350Sbapt 468136638Swollman fri = fdi.indata; 469136638Swollman fri->newdir = VTOI(tdvp); 470136638Swollman memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr, 471136638Swollman fcnp->cn_namelen); 472316350Sbapt ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0'; 473316350Sbapt memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1, 474316350Sbapt tcnp->cn_nameptr, tcnp->cn_namelen); 475316350Sbapt ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen + 476316350Sbapt tcnp->cn_namelen + 1] = '\0'; 477316350Sbapt 478316350Sbapt err = fdisp_wait_answ(&fdi); 479316350Sbapt fdisp_destroy(&fdi); 480316350Sbapt 481316350Sbapt fuse_invalidate_attr(fdvp); 482136638Swollman if (tdvp != fdvp) { 48320094Swollman fuse_invalidate_attr(tdvp); 484136638Swollman } 48593799Swollman return err; 486316350Sbapt} 487316350Sbapt 488316350Sbapt/* strategy */ 489316350Sbapt 490316350Sbapt/* entity creation */ 491316350Sbapt 492316350Sbaptvoid 493316350Sbaptfuse_internal_newentry_makerequest(struct mount *mp, 494316350Sbapt uint64_t dnid, 495316350Sbapt struct componentname *cnp, 496316350Sbapt enum fuse_opcode op, 49720094Swollman void *buf, 498149514Swollman size_t bufsize, 499136638Swollman struct fuse_dispatcher *fdip) 50093799Swollman{ 501316350Sbapt debug_printf("fdip=%p\n", fdip); 502316350Sbapt 503316350Sbapt fdip->iosize = bufsize + cnp->cn_namelen + 1; 504316350Sbapt 505316350Sbapt fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred); 506316350Sbapt memcpy(fdip->indata, buf, bufsize); 507316350Sbapt memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen); 508316350Sbapt ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0'; 509316350Sbapt} 510316350Sbapt 51120094Swollmanint 51220094Swollmanfuse_internal_newentry_core(struct vnode *dvp, 513136638Swollman struct vnode **vpp, 51493799Swollman struct componentname *cnp, 515316350Sbapt enum vtype vtyp, 516316350Sbapt struct fuse_dispatcher *fdip) 517316350Sbapt{ 518316350Sbapt int err = 0; 519316350Sbapt struct fuse_entry_out *feo; 520316350Sbapt struct mount *mp = vnode_mount(dvp); 521316350Sbapt 522316350Sbapt if ((err = fdisp_wait_answ(fdip))) { 523316350Sbapt return err; 524316350Sbapt } 525316350Sbapt feo = fdip->answ; 526316350Sbapt 527316350Sbapt if ((err = fuse_internal_checkentry(feo, vtyp))) { 528316350Sbapt return err; 529136638Swollman } 530177591Sedwin err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, vtyp); 531198515Sedwin if (err) { 532206868Sedwin fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred, 533331663Sphilip feo->nodeid, 1); 534198515Sedwin return err; 535177591Sedwin } 536177591Sedwin cache_attrs(*vpp, feo); 537316350Sbapt 538316350Sbapt return err; 539316350Sbapt} 540316350Sbapt 541316350Sbaptint 542316350Sbaptfuse_internal_newentry(struct vnode *dvp, 543316350Sbapt struct vnode **vpp, 544316350Sbapt struct componentname *cnp, 545316350Sbapt enum fuse_opcode op, 546316350Sbapt void *buf, 547316350Sbapt size_t bufsize, 548316350Sbapt enum vtype vtype) 549316350Sbapt{ 550316350Sbapt int err; 551177591Sedwin struct fuse_dispatcher fdi; 552136638Swollman struct mount *mp = vnode_mount(dvp); 553273719Sedwin 554316350Sbapt fdisp_init(&fdi, 0); 555316350Sbapt fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf, 556316350Sbapt bufsize, &fdi); 557316350Sbapt err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi); 558316350Sbapt fdisp_destroy(&fdi); 559316350Sbapt fuse_invalidate_attr(dvp); 560316350Sbapt 561316350Sbapt return err; 562316350Sbapt} 563136638Swollman 564270817Spluknet/* entity destruction */ 565273719Sedwin 566316350Sbaptint 567316350Sbaptfuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio) 568316350Sbapt{ 569316350Sbapt fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL, 570316350Sbapt ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1); 571316350Sbapt 572316350Sbapt return 0; 573316350Sbapt} 574316350Sbapt 5758029Swollmanvoid 57614343Swollmanfuse_internal_forget_send(struct mount *mp, 577257697Sedwin struct thread *td, 57814343Swollman struct ucred *cred, 5792742Swollman uint64_t nodeid, 5802742Swollman uint64_t nlookup) 5812742Swollman{ 58286222Swollman 583328476Sphilip struct fuse_dispatcher fdi; 584316350Sbapt struct fuse_forget_in *ffi; 5852742Swollman 5862742Swollman debug_printf("mp=%p, nodeid=%ju, nlookup=%ju\n", 5872742Swollman mp, (uintmax_t)nodeid, (uintmax_t)nlookup); 588149514Swollman 5892742Swollman /* 5902742Swollman * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu", 5912742Swollman * (long long unsigned) nodeid)); 5922742Swollman */ 5932742Swollman 5942742Swollman fdisp_init(&fdi, sizeof(*ffi)); 59520094Swollman fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred); 59620094Swollman 597270817Spluknet ffi = fdi.indata; 598270817Spluknet ffi->nlookup = nlookup; 59920094Swollman 60020094Swollman fuse_insert_message(fdi.tick); 60120094Swollman fdisp_destroy(&fdi); 60220094Swollman} 603270817Spluknet 60420094Swollmanvoid 60520094Swollmanfuse_internal_vnode_disappear(struct vnode *vp) 60620094Swollman{ 60720094Swollman struct fuse_vnode_data *fvdat = VTOFUD(vp); 60820094Swollman 60920094Swollman ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear"); 61020094Swollman fvdat->flag |= FN_REVOKED; 61120094Swollman cache_purge(vp); 61220094Swollman} 61320094Swollman 61420094Swollman/* fuse start/stop */ 61520094Swollman 61620094Swollmanint 617270817Spluknetfuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio) 618270817Spluknet{ 619270817Spluknet int err = 0; 62020094Swollman struct fuse_data *data = tick->tk_data; 62143014Swollman struct fuse_init_out *fiio; 622270817Spluknet 62375267Swollman if ((err = tick->tk_aw_ohead.error)) { 624270817Spluknet goto out; 62575267Swollman } 62675267Swollman if ((err = fticket_pull(tick, uio))) { 62775267Swollman goto out; 62875267Swollman } 629105196Swollman fiio = fticket_resp(tick)->base; 630105196Swollman 631105196Swollman /* XXX: Do we want to check anything further besides this? */ 632105196Swollman if (fiio->major < 7) { 633105196Swollman debug_printf("userpace version too low\n"); 634105196Swollman err = EPROTONOSUPPORT; 635105196Swollman goto out; 636105196Swollman } 637105196Swollman data->fuse_libabi_major = fiio->major; 638105196Swollman data->fuse_libabi_minor = fiio->minor; 639105196Swollman 640105196Swollman if (fuse_libabi_geq(data, 7, 5)) { 641105196Swollman if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) { 642105196Swollman data->max_write = fiio->max_write; 643105196Swollman } else { 644105196Swollman err = EINVAL; 645105196Swollman } 646136638Swollman } else { 647136638Swollman /* Old fix values */ 648136638Swollman data->max_write = 4096; 649136638Swollman } 650136638Swollman 651172479Sedwinout: 652172479Sedwin if (err) { 653172479Sedwin fdata_set_dead(data); 654172479Sedwin } 655181421Sedwin FUSE_LOCK(); 656181421Sedwin data->dataflags |= FSESS_INITED; 657270817Spluknet wakeup(&data->ticketer); 658181421Sedwin FUSE_UNLOCK(); 659181421Sedwin 660273719Sedwin return 0; 661181421Sedwin} 662181421Sedwin 663270817Spluknetvoid 664181421Sedwinfuse_internal_send_init(struct fuse_data *data, struct thread *td) 665181421Sedwin{ 666181421Sedwin struct fuse_init_in *fiii; 667181421Sedwin struct fuse_dispatcher fdi; 668181421Sedwin 669181421Sedwin fdisp_init(&fdi, sizeof(*fiii)); 670181421Sedwin fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL); 671181421Sedwin fiii = fdi.indata; 672181421Sedwin fiii->major = FUSE_KERNEL_VERSION; 673181421Sedwin fiii->minor = FUSE_KERNEL_MINOR_VERSION; 674181421Sedwin fiii->max_readahead = FUSE_DEFAULT_IOSIZE * 16; 675181421Sedwin fiii->flags = 0; 676192886Sedwin 677181421Sedwin fuse_insert_callback(fdi.tick, fuse_internal_init_callback); 678181421Sedwin fuse_insert_message(fdi.tick); 679181421Sedwin fdisp_destroy(&fdi); 680270817Spluknet} 681181421Sedwin 682181421Sedwin#ifdef ZERO_PAD_INCOMPLETE_BUFS 683181421Sedwinstatic int 684181421Sedwinisbzero(void *buf, size_t len) 685181421Sedwin{ 686181421Sedwin int i; 687181421Sedwin 688181421Sedwin for (i = 0; i < len; i++) { 689181421Sedwin if (((char *)buf)[i]) 690181421Sedwin return (0); 691270817Spluknet } 692270817Spluknet 693270817Spluknet return (1); 694181421Sedwin} 695105196Swollman 696105196Swollman#endif 697273719Sedwin