1*5fe58019SAttilio Rao /* 2*5fe58019SAttilio Rao * Copyright (c) 2007-2009 Google Inc. and Amit Singh 3*5fe58019SAttilio Rao * All rights reserved. 4*5fe58019SAttilio Rao * 5*5fe58019SAttilio Rao * Redistribution and use in source and binary forms, with or without 6*5fe58019SAttilio Rao * modification, are permitted provided that the following conditions are 7*5fe58019SAttilio Rao * met: 8*5fe58019SAttilio Rao * 9*5fe58019SAttilio Rao * * Redistributions of source code must retain the above copyright 10*5fe58019SAttilio Rao * notice, this list of conditions and the following disclaimer. 11*5fe58019SAttilio Rao * * Redistributions in binary form must reproduce the above 12*5fe58019SAttilio Rao * copyright notice, this list of conditions and the following disclaimer 13*5fe58019SAttilio Rao * in the documentation and/or other materials provided with the 14*5fe58019SAttilio Rao * distribution. 15*5fe58019SAttilio Rao * * Neither the name of Google Inc. nor the names of its 16*5fe58019SAttilio Rao * contributors may be used to endorse or promote products derived from 17*5fe58019SAttilio Rao * this software without specific prior written permission. 18*5fe58019SAttilio Rao * 19*5fe58019SAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20*5fe58019SAttilio Rao * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21*5fe58019SAttilio Rao * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22*5fe58019SAttilio Rao * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23*5fe58019SAttilio Rao * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24*5fe58019SAttilio Rao * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25*5fe58019SAttilio Rao * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26*5fe58019SAttilio Rao * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27*5fe58019SAttilio Rao * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28*5fe58019SAttilio Rao * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29*5fe58019SAttilio Rao * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30*5fe58019SAttilio Rao * 31*5fe58019SAttilio Rao * Copyright (C) 2005 Csaba Henk. 32*5fe58019SAttilio Rao * All rights reserved. 33*5fe58019SAttilio Rao * 34*5fe58019SAttilio Rao * Redistribution and use in source and binary forms, with or without 35*5fe58019SAttilio Rao * modification, are permitted provided that the following conditions 36*5fe58019SAttilio Rao * are met: 37*5fe58019SAttilio Rao * 1. Redistributions of source code must retain the above copyright 38*5fe58019SAttilio Rao * notice, this list of conditions and the following disclaimer. 39*5fe58019SAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright 40*5fe58019SAttilio Rao * notice, this list of conditions and the following disclaimer in the 41*5fe58019SAttilio Rao * documentation and/or other materials provided with the distribution. 42*5fe58019SAttilio Rao * 43*5fe58019SAttilio Rao * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 44*5fe58019SAttilio Rao * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45*5fe58019SAttilio Rao * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46*5fe58019SAttilio Rao * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 47*5fe58019SAttilio Rao * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48*5fe58019SAttilio Rao * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49*5fe58019SAttilio Rao * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50*5fe58019SAttilio Rao * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51*5fe58019SAttilio Rao * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52*5fe58019SAttilio Rao * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53*5fe58019SAttilio Rao * SUCH DAMAGE. 54*5fe58019SAttilio Rao */ 55*5fe58019SAttilio Rao 56*5fe58019SAttilio Rao #include <sys/cdefs.h> 57*5fe58019SAttilio Rao __FBSDID("$FreeBSD$"); 58*5fe58019SAttilio Rao 59*5fe58019SAttilio Rao #include <sys/types.h> 60*5fe58019SAttilio Rao #include <sys/module.h> 61*5fe58019SAttilio Rao #include <sys/systm.h> 62*5fe58019SAttilio Rao #include <sys/errno.h> 63*5fe58019SAttilio Rao #include <sys/param.h> 64*5fe58019SAttilio Rao #include <sys/kernel.h> 65*5fe58019SAttilio Rao #include <sys/conf.h> 66*5fe58019SAttilio Rao #include <sys/uio.h> 67*5fe58019SAttilio Rao #include <sys/malloc.h> 68*5fe58019SAttilio Rao #include <sys/queue.h> 69*5fe58019SAttilio Rao #include <sys/lock.h> 70*5fe58019SAttilio Rao #include <sys/mutex.h> 71*5fe58019SAttilio Rao #include <sys/sx.h> 72*5fe58019SAttilio Rao #include <sys/proc.h> 73*5fe58019SAttilio Rao #include <sys/mount.h> 74*5fe58019SAttilio Rao #include <sys/vnode.h> 75*5fe58019SAttilio Rao #include <sys/namei.h> 76*5fe58019SAttilio Rao #include <sys/stat.h> 77*5fe58019SAttilio Rao #include <sys/unistd.h> 78*5fe58019SAttilio Rao #include <sys/filedesc.h> 79*5fe58019SAttilio Rao #include <sys/file.h> 80*5fe58019SAttilio Rao #include <sys/fcntl.h> 81*5fe58019SAttilio Rao #include <sys/dirent.h> 82*5fe58019SAttilio Rao #include <sys/bio.h> 83*5fe58019SAttilio Rao #include <sys/buf.h> 84*5fe58019SAttilio Rao #include <sys/sysctl.h> 85*5fe58019SAttilio Rao 86*5fe58019SAttilio Rao #include <vm/vm.h> 87*5fe58019SAttilio Rao #include <vm/vm_extern.h> 88*5fe58019SAttilio Rao #include <vm/pmap.h> 89*5fe58019SAttilio Rao #include <vm/vm_map.h> 90*5fe58019SAttilio Rao #include <vm/vm_page.h> 91*5fe58019SAttilio Rao #include <vm/vm_param.h> 92*5fe58019SAttilio Rao #include <vm/vm_object.h> 93*5fe58019SAttilio Rao #include <vm/vm_pager.h> 94*5fe58019SAttilio Rao #include <vm/vnode_pager.h> 95*5fe58019SAttilio Rao #include <vm/vm_object.h> 96*5fe58019SAttilio Rao 97*5fe58019SAttilio Rao #include "fuse.h" 98*5fe58019SAttilio Rao #include "fuse_file.h" 99*5fe58019SAttilio Rao #include "fuse_internal.h" 100*5fe58019SAttilio Rao #include "fuse_ipc.h" 101*5fe58019SAttilio Rao #include "fuse_node.h" 102*5fe58019SAttilio Rao #include "fuse_param.h" 103*5fe58019SAttilio Rao #include "fuse_io.h" 104*5fe58019SAttilio Rao 105*5fe58019SAttilio Rao #include <sys/priv.h> 106*5fe58019SAttilio Rao 107*5fe58019SAttilio Rao #define FUSE_DEBUG_MODULE VNOPS 108*5fe58019SAttilio Rao #include "fuse_debug.h" 109*5fe58019SAttilio Rao 110*5fe58019SAttilio Rao /* vnode ops */ 111*5fe58019SAttilio Rao static vop_access_t fuse_vnop_access; 112*5fe58019SAttilio Rao static vop_close_t fuse_vnop_close; 113*5fe58019SAttilio Rao static vop_create_t fuse_vnop_create; 114*5fe58019SAttilio Rao static vop_fsync_t fuse_vnop_fsync; 115*5fe58019SAttilio Rao static vop_getattr_t fuse_vnop_getattr; 116*5fe58019SAttilio Rao static vop_inactive_t fuse_vnop_inactive; 117*5fe58019SAttilio Rao static vop_link_t fuse_vnop_link; 118*5fe58019SAttilio Rao static vop_lookup_t fuse_vnop_lookup; 119*5fe58019SAttilio Rao static vop_mkdir_t fuse_vnop_mkdir; 120*5fe58019SAttilio Rao static vop_mknod_t fuse_vnop_mknod; 121*5fe58019SAttilio Rao static vop_open_t fuse_vnop_open; 122*5fe58019SAttilio Rao static vop_read_t fuse_vnop_read; 123*5fe58019SAttilio Rao static vop_readdir_t fuse_vnop_readdir; 124*5fe58019SAttilio Rao static vop_readlink_t fuse_vnop_readlink; 125*5fe58019SAttilio Rao static vop_reclaim_t fuse_vnop_reclaim; 126*5fe58019SAttilio Rao static vop_remove_t fuse_vnop_remove; 127*5fe58019SAttilio Rao static vop_rename_t fuse_vnop_rename; 128*5fe58019SAttilio Rao static vop_rmdir_t fuse_vnop_rmdir; 129*5fe58019SAttilio Rao static vop_setattr_t fuse_vnop_setattr; 130*5fe58019SAttilio Rao static vop_strategy_t fuse_vnop_strategy; 131*5fe58019SAttilio Rao static vop_symlink_t fuse_vnop_symlink; 132*5fe58019SAttilio Rao static vop_write_t fuse_vnop_write; 133*5fe58019SAttilio Rao static vop_getpages_t fuse_vnop_getpages; 134*5fe58019SAttilio Rao static vop_putpages_t fuse_vnop_putpages; 135*5fe58019SAttilio Rao static vop_print_t fuse_vnop_print; 136*5fe58019SAttilio Rao 137*5fe58019SAttilio Rao struct vop_vector fuse_vnops = { 138*5fe58019SAttilio Rao .vop_default = &default_vnodeops, 139*5fe58019SAttilio Rao .vop_access = fuse_vnop_access, 140*5fe58019SAttilio Rao .vop_close = fuse_vnop_close, 141*5fe58019SAttilio Rao .vop_create = fuse_vnop_create, 142*5fe58019SAttilio Rao .vop_fsync = fuse_vnop_fsync, 143*5fe58019SAttilio Rao .vop_getattr = fuse_vnop_getattr, 144*5fe58019SAttilio Rao .vop_inactive = fuse_vnop_inactive, 145*5fe58019SAttilio Rao .vop_link = fuse_vnop_link, 146*5fe58019SAttilio Rao .vop_lookup = fuse_vnop_lookup, 147*5fe58019SAttilio Rao .vop_mkdir = fuse_vnop_mkdir, 148*5fe58019SAttilio Rao .vop_mknod = fuse_vnop_mknod, 149*5fe58019SAttilio Rao .vop_open = fuse_vnop_open, 150*5fe58019SAttilio Rao .vop_pathconf = vop_stdpathconf, 151*5fe58019SAttilio Rao .vop_read = fuse_vnop_read, 152*5fe58019SAttilio Rao .vop_readdir = fuse_vnop_readdir, 153*5fe58019SAttilio Rao .vop_readlink = fuse_vnop_readlink, 154*5fe58019SAttilio Rao .vop_reclaim = fuse_vnop_reclaim, 155*5fe58019SAttilio Rao .vop_remove = fuse_vnop_remove, 156*5fe58019SAttilio Rao .vop_rename = fuse_vnop_rename, 157*5fe58019SAttilio Rao .vop_rmdir = fuse_vnop_rmdir, 158*5fe58019SAttilio Rao .vop_setattr = fuse_vnop_setattr, 159*5fe58019SAttilio Rao .vop_strategy = fuse_vnop_strategy, 160*5fe58019SAttilio Rao .vop_symlink = fuse_vnop_symlink, 161*5fe58019SAttilio Rao .vop_write = fuse_vnop_write, 162*5fe58019SAttilio Rao .vop_getpages = fuse_vnop_getpages, 163*5fe58019SAttilio Rao .vop_putpages = fuse_vnop_putpages, 164*5fe58019SAttilio Rao .vop_print = fuse_vnop_print, 165*5fe58019SAttilio Rao }; 166*5fe58019SAttilio Rao 167*5fe58019SAttilio Rao static u_long fuse_lookup_cache_hits = 0; 168*5fe58019SAttilio Rao 169*5fe58019SAttilio Rao SYSCTL_ULONG(_vfs_fuse, OID_AUTO, lookup_cache_hits, CTLFLAG_RD, 170*5fe58019SAttilio Rao &fuse_lookup_cache_hits, 0, ""); 171*5fe58019SAttilio Rao 172*5fe58019SAttilio Rao static u_long fuse_lookup_cache_misses = 0; 173*5fe58019SAttilio Rao 174*5fe58019SAttilio Rao SYSCTL_ULONG(_vfs_fuse, OID_AUTO, lookup_cache_misses, CTLFLAG_RD, 175*5fe58019SAttilio Rao &fuse_lookup_cache_misses, 0, ""); 176*5fe58019SAttilio Rao 177*5fe58019SAttilio Rao int fuse_lookup_cache_enable = 1; 178*5fe58019SAttilio Rao 179*5fe58019SAttilio Rao SYSCTL_INT(_vfs_fuse, OID_AUTO, lookup_cache_enable, CTLFLAG_RW, 180*5fe58019SAttilio Rao &fuse_lookup_cache_enable, 0, ""); 181*5fe58019SAttilio Rao 182*5fe58019SAttilio Rao /* 183*5fe58019SAttilio Rao * XXX: This feature is highly experimental and can bring to instabilities, 184*5fe58019SAttilio Rao * needs revisiting before to be enabled by default. 185*5fe58019SAttilio Rao */ 186*5fe58019SAttilio Rao static int fuse_reclaim_revoked = 0; 187*5fe58019SAttilio Rao 188*5fe58019SAttilio Rao SYSCTL_INT(_vfs_fuse, OID_AUTO, reclaim_revoked, CTLFLAG_RW, 189*5fe58019SAttilio Rao &fuse_reclaim_revoked, 0, ""); 190*5fe58019SAttilio Rao 191*5fe58019SAttilio Rao int fuse_pbuf_freecnt = -1; 192*5fe58019SAttilio Rao 193*5fe58019SAttilio Rao #define fuse_vm_page_lock(m) vm_page_lock((m)); 194*5fe58019SAttilio Rao #define fuse_vm_page_unlock(m) vm_page_unlock((m)); 195*5fe58019SAttilio Rao #define fuse_vm_page_lock_queues() ((void)0) 196*5fe58019SAttilio Rao #define fuse_vm_page_unlock_queues() ((void)0) 197*5fe58019SAttilio Rao 198*5fe58019SAttilio Rao /* 199*5fe58019SAttilio Rao struct vnop_access_args { 200*5fe58019SAttilio Rao struct vnode *a_vp; 201*5fe58019SAttilio Rao #if VOP_ACCESS_TAKES_ACCMODE_T 202*5fe58019SAttilio Rao accmode_t a_accmode; 203*5fe58019SAttilio Rao #else 204*5fe58019SAttilio Rao int a_mode; 205*5fe58019SAttilio Rao #endif 206*5fe58019SAttilio Rao struct ucred *a_cred; 207*5fe58019SAttilio Rao struct thread *a_td; 208*5fe58019SAttilio Rao }; 209*5fe58019SAttilio Rao */ 210*5fe58019SAttilio Rao static int 211*5fe58019SAttilio Rao fuse_vnop_access(struct vop_access_args *ap) 212*5fe58019SAttilio Rao { 213*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 214*5fe58019SAttilio Rao int accmode = ap->a_accmode; 215*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 216*5fe58019SAttilio Rao 217*5fe58019SAttilio Rao struct fuse_access_param facp; 218*5fe58019SAttilio Rao struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp)); 219*5fe58019SAttilio Rao 220*5fe58019SAttilio Rao int err; 221*5fe58019SAttilio Rao 222*5fe58019SAttilio Rao DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); 223*5fe58019SAttilio Rao 224*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 225*5fe58019SAttilio Rao if (vnode_isvroot(vp)) { 226*5fe58019SAttilio Rao return 0; 227*5fe58019SAttilio Rao } 228*5fe58019SAttilio Rao return ENXIO; 229*5fe58019SAttilio Rao } 230*5fe58019SAttilio Rao if (!(data->dataflags & FSESS_INITED)) { 231*5fe58019SAttilio Rao if (vnode_isvroot(vp)) { 232*5fe58019SAttilio Rao if (priv_check_cred(cred, PRIV_VFS_ADMIN, 0) || 233*5fe58019SAttilio Rao (fuse_match_cred(data->daemoncred, cred) == 0)) { 234*5fe58019SAttilio Rao return 0; 235*5fe58019SAttilio Rao } 236*5fe58019SAttilio Rao } 237*5fe58019SAttilio Rao return EBADF; 238*5fe58019SAttilio Rao } 239*5fe58019SAttilio Rao if (vnode_islnk(vp)) { 240*5fe58019SAttilio Rao return 0; 241*5fe58019SAttilio Rao } 242*5fe58019SAttilio Rao bzero(&facp, sizeof(facp)); 243*5fe58019SAttilio Rao 244*5fe58019SAttilio Rao err = fuse_internal_access(vp, accmode, &facp, ap->a_td, ap->a_cred); 245*5fe58019SAttilio Rao DEBUG2G("err=%d accmode=0x%x\n", err, accmode); 246*5fe58019SAttilio Rao return err; 247*5fe58019SAttilio Rao } 248*5fe58019SAttilio Rao 249*5fe58019SAttilio Rao /* 250*5fe58019SAttilio Rao struct vnop_close_args { 251*5fe58019SAttilio Rao struct vnode *a_vp; 252*5fe58019SAttilio Rao int a_fflag; 253*5fe58019SAttilio Rao struct ucred *a_cred; 254*5fe58019SAttilio Rao struct thread *a_td; 255*5fe58019SAttilio Rao }; 256*5fe58019SAttilio Rao */ 257*5fe58019SAttilio Rao static int 258*5fe58019SAttilio Rao fuse_vnop_close(struct vop_close_args *ap) 259*5fe58019SAttilio Rao { 260*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 261*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 262*5fe58019SAttilio Rao int fflag = ap->a_fflag; 263*5fe58019SAttilio Rao fufh_type_t fufh_type; 264*5fe58019SAttilio Rao 265*5fe58019SAttilio Rao fuse_trace_printf_vnop(); 266*5fe58019SAttilio Rao 267*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 268*5fe58019SAttilio Rao return 0; 269*5fe58019SAttilio Rao } 270*5fe58019SAttilio Rao if (vnode_isdir(vp)) { 271*5fe58019SAttilio Rao if (fuse_filehandle_valid(vp, FUFH_RDONLY)) { 272*5fe58019SAttilio Rao fuse_filehandle_close(vp, FUFH_RDONLY, NULL, cred); 273*5fe58019SAttilio Rao } 274*5fe58019SAttilio Rao return 0; 275*5fe58019SAttilio Rao } 276*5fe58019SAttilio Rao if (fflag & IO_NDELAY) { 277*5fe58019SAttilio Rao return 0; 278*5fe58019SAttilio Rao } 279*5fe58019SAttilio Rao fufh_type = fuse_filehandle_xlate_from_fflags(fflag); 280*5fe58019SAttilio Rao 281*5fe58019SAttilio Rao if (!fuse_filehandle_valid(vp, fufh_type)) { 282*5fe58019SAttilio Rao int i; 283*5fe58019SAttilio Rao 284*5fe58019SAttilio Rao for (i = 0; i < FUFH_MAXTYPE; i++) 285*5fe58019SAttilio Rao if (fuse_filehandle_valid(vp, i)) 286*5fe58019SAttilio Rao break; 287*5fe58019SAttilio Rao if (i == FUFH_MAXTYPE) 288*5fe58019SAttilio Rao panic("FUSE: fufh type %d found to be invalid in close" 289*5fe58019SAttilio Rao " (fflag=0x%x)\n", 290*5fe58019SAttilio Rao fufh_type, fflag); 291*5fe58019SAttilio Rao } 292*5fe58019SAttilio Rao if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) { 293*5fe58019SAttilio Rao fuse_vnode_savesize(vp, cred); 294*5fe58019SAttilio Rao } 295*5fe58019SAttilio Rao return 0; 296*5fe58019SAttilio Rao } 297*5fe58019SAttilio Rao 298*5fe58019SAttilio Rao /* 299*5fe58019SAttilio Rao struct vnop_create_args { 300*5fe58019SAttilio Rao struct vnode *a_dvp; 301*5fe58019SAttilio Rao struct vnode **a_vpp; 302*5fe58019SAttilio Rao struct componentname *a_cnp; 303*5fe58019SAttilio Rao struct vattr *a_vap; 304*5fe58019SAttilio Rao }; 305*5fe58019SAttilio Rao */ 306*5fe58019SAttilio Rao static int 307*5fe58019SAttilio Rao fuse_vnop_create(struct vop_create_args *ap) 308*5fe58019SAttilio Rao { 309*5fe58019SAttilio Rao struct vnode *dvp = ap->a_dvp; 310*5fe58019SAttilio Rao struct vnode **vpp = ap->a_vpp; 311*5fe58019SAttilio Rao struct componentname *cnp = ap->a_cnp; 312*5fe58019SAttilio Rao struct vattr *vap = ap->a_vap; 313*5fe58019SAttilio Rao struct thread *td = cnp->cn_thread; 314*5fe58019SAttilio Rao struct ucred *cred = cnp->cn_cred; 315*5fe58019SAttilio Rao 316*5fe58019SAttilio Rao struct fuse_open_in *foi; 317*5fe58019SAttilio Rao struct fuse_entry_out *feo; 318*5fe58019SAttilio Rao struct fuse_dispatcher fdi; 319*5fe58019SAttilio Rao struct fuse_dispatcher *fdip = &fdi; 320*5fe58019SAttilio Rao 321*5fe58019SAttilio Rao int err; 322*5fe58019SAttilio Rao 323*5fe58019SAttilio Rao struct mount *mp = vnode_mount(dvp); 324*5fe58019SAttilio Rao uint64_t parentnid = VTOFUD(dvp)->nid; 325*5fe58019SAttilio Rao mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode); 326*5fe58019SAttilio Rao uint64_t x_fh_id; 327*5fe58019SAttilio Rao uint32_t x_open_flags; 328*5fe58019SAttilio Rao 329*5fe58019SAttilio Rao fuse_trace_printf_vnop(); 330*5fe58019SAttilio Rao 331*5fe58019SAttilio Rao if (fuse_isdeadfs(dvp)) { 332*5fe58019SAttilio Rao return ENXIO; 333*5fe58019SAttilio Rao } 334*5fe58019SAttilio Rao bzero(&fdi, sizeof(fdi)); 335*5fe58019SAttilio Rao 336*5fe58019SAttilio Rao /* XXX: Will we ever want devices ? */ 337*5fe58019SAttilio Rao if ((vap->va_type != VREG)) { 338*5fe58019SAttilio Rao MPASS(vap->va_type != VFIFO); 339*5fe58019SAttilio Rao goto bringup; 340*5fe58019SAttilio Rao } 341*5fe58019SAttilio Rao debug_printf("parent nid = %ju, mode = %x\n", (uintmax_t)parentnid, 342*5fe58019SAttilio Rao mode); 343*5fe58019SAttilio Rao 344*5fe58019SAttilio Rao fdisp_init(fdip, sizeof(*foi) + cnp->cn_namelen + 1); 345*5fe58019SAttilio Rao if (!fsess_isimpl(mp, FUSE_CREATE)) { 346*5fe58019SAttilio Rao debug_printf("eh, daemon doesn't implement create?\n"); 347*5fe58019SAttilio Rao return (EINVAL); 348*5fe58019SAttilio Rao } 349*5fe58019SAttilio Rao fdisp_make(fdip, FUSE_CREATE, vnode_mount(dvp), parentnid, td, cred); 350*5fe58019SAttilio Rao 351*5fe58019SAttilio Rao foi = fdip->indata; 352*5fe58019SAttilio Rao foi->mode = mode; 353*5fe58019SAttilio Rao foi->flags = O_CREAT | O_RDWR; 354*5fe58019SAttilio Rao 355*5fe58019SAttilio Rao memcpy((char *)fdip->indata + sizeof(*foi), cnp->cn_nameptr, 356*5fe58019SAttilio Rao cnp->cn_namelen); 357*5fe58019SAttilio Rao ((char *)fdip->indata)[sizeof(*foi) + cnp->cn_namelen] = '\0'; 358*5fe58019SAttilio Rao 359*5fe58019SAttilio Rao err = fdisp_wait_answ(fdip); 360*5fe58019SAttilio Rao 361*5fe58019SAttilio Rao if (err == ENOSYS) { 362*5fe58019SAttilio Rao debug_printf("create: got ENOSYS from daemon\n"); 363*5fe58019SAttilio Rao fsess_set_notimpl(mp, FUSE_CREATE); 364*5fe58019SAttilio Rao fdisp_destroy(fdip); 365*5fe58019SAttilio Rao } else if (err) { 366*5fe58019SAttilio Rao debug_printf("create: darn, got err=%d from daemon\n", err); 367*5fe58019SAttilio Rao goto out; 368*5fe58019SAttilio Rao } 369*5fe58019SAttilio Rao bringup: 370*5fe58019SAttilio Rao feo = fdip->answ; 371*5fe58019SAttilio Rao 372*5fe58019SAttilio Rao if ((err = fuse_internal_checkentry(feo, VREG))) { 373*5fe58019SAttilio Rao goto out; 374*5fe58019SAttilio Rao } 375*5fe58019SAttilio Rao err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, VREG); 376*5fe58019SAttilio Rao if (err) { 377*5fe58019SAttilio Rao struct fuse_release_in *fri; 378*5fe58019SAttilio Rao uint64_t nodeid = feo->nodeid; 379*5fe58019SAttilio Rao uint64_t fh_id = ((struct fuse_open_out *)(feo + 1))->fh; 380*5fe58019SAttilio Rao 381*5fe58019SAttilio Rao fdisp_init(fdip, sizeof(*fri)); 382*5fe58019SAttilio Rao fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred); 383*5fe58019SAttilio Rao fri = fdip->indata; 384*5fe58019SAttilio Rao fri->fh = fh_id; 385*5fe58019SAttilio Rao fri->flags = OFLAGS(mode); 386*5fe58019SAttilio Rao fuse_insert_callback(fdip->tick, fuse_internal_forget_callback); 387*5fe58019SAttilio Rao fuse_insert_message(fdip->tick); 388*5fe58019SAttilio Rao return err; 389*5fe58019SAttilio Rao } 390*5fe58019SAttilio Rao ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create"); 391*5fe58019SAttilio Rao 392*5fe58019SAttilio Rao fdip->answ = feo + 1; 393*5fe58019SAttilio Rao 394*5fe58019SAttilio Rao x_fh_id = ((struct fuse_open_out *)(feo + 1))->fh; 395*5fe58019SAttilio Rao x_open_flags = ((struct fuse_open_out *)(feo + 1))->open_flags; 396*5fe58019SAttilio Rao fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, x_fh_id); 397*5fe58019SAttilio Rao fuse_vnode_open(*vpp, x_open_flags, td); 398*5fe58019SAttilio Rao cache_purge_negative(dvp); 399*5fe58019SAttilio Rao 400*5fe58019SAttilio Rao out: 401*5fe58019SAttilio Rao fdisp_destroy(fdip); 402*5fe58019SAttilio Rao return err; 403*5fe58019SAttilio Rao } 404*5fe58019SAttilio Rao 405*5fe58019SAttilio Rao /* 406*5fe58019SAttilio Rao * Our vnop_fsync roughly corresponds to the FUSE_FSYNC method. The Linux 407*5fe58019SAttilio Rao * version of FUSE also has a FUSE_FLUSH method. 408*5fe58019SAttilio Rao * 409*5fe58019SAttilio Rao * On Linux, fsync() synchronizes a file's complete in-core state with that 410*5fe58019SAttilio Rao * on disk. The call is not supposed to return until the system has completed 411*5fe58019SAttilio Rao * that action or until an error is detected. 412*5fe58019SAttilio Rao * 413*5fe58019SAttilio Rao * Linux also has an fdatasync() call that is similar to fsync() but is not 414*5fe58019SAttilio Rao * required to update the metadata such as access time and modification time. 415*5fe58019SAttilio Rao */ 416*5fe58019SAttilio Rao 417*5fe58019SAttilio Rao /* 418*5fe58019SAttilio Rao struct vnop_fsync_args { 419*5fe58019SAttilio Rao struct vnodeop_desc *a_desc; 420*5fe58019SAttilio Rao struct vnode * a_vp; 421*5fe58019SAttilio Rao struct ucred * a_cred; 422*5fe58019SAttilio Rao int a_waitfor; 423*5fe58019SAttilio Rao struct thread * a_td; 424*5fe58019SAttilio Rao }; 425*5fe58019SAttilio Rao */ 426*5fe58019SAttilio Rao static int 427*5fe58019SAttilio Rao fuse_vnop_fsync(struct vop_fsync_args *ap) 428*5fe58019SAttilio Rao { 429*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 430*5fe58019SAttilio Rao struct thread *td = ap->a_td; 431*5fe58019SAttilio Rao 432*5fe58019SAttilio Rao struct fuse_filehandle *fufh; 433*5fe58019SAttilio Rao struct fuse_vnode_data *fvdat = VTOFUD(vp); 434*5fe58019SAttilio Rao 435*5fe58019SAttilio Rao int type, err = 0; 436*5fe58019SAttilio Rao 437*5fe58019SAttilio Rao fuse_trace_printf_vnop(); 438*5fe58019SAttilio Rao 439*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 440*5fe58019SAttilio Rao return 0; 441*5fe58019SAttilio Rao } 442*5fe58019SAttilio Rao if ((err = vop_stdfsync(ap))) 443*5fe58019SAttilio Rao return err; 444*5fe58019SAttilio Rao 445*5fe58019SAttilio Rao if (!fsess_isimpl(vnode_mount(vp), 446*5fe58019SAttilio Rao (vnode_vtype(vp) == VDIR ? FUSE_FSYNCDIR : FUSE_FSYNC))) { 447*5fe58019SAttilio Rao goto out; 448*5fe58019SAttilio Rao } 449*5fe58019SAttilio Rao for (type = 0; type < FUFH_MAXTYPE; type++) { 450*5fe58019SAttilio Rao fufh = &(fvdat->fufh[type]); 451*5fe58019SAttilio Rao if (FUFH_IS_VALID(fufh)) { 452*5fe58019SAttilio Rao fuse_internal_fsync(vp, td, NULL, fufh); 453*5fe58019SAttilio Rao } 454*5fe58019SAttilio Rao } 455*5fe58019SAttilio Rao 456*5fe58019SAttilio Rao out: 457*5fe58019SAttilio Rao return 0; 458*5fe58019SAttilio Rao } 459*5fe58019SAttilio Rao 460*5fe58019SAttilio Rao /* 461*5fe58019SAttilio Rao struct vnop_getattr_args { 462*5fe58019SAttilio Rao struct vnode *a_vp; 463*5fe58019SAttilio Rao struct vattr *a_vap; 464*5fe58019SAttilio Rao struct ucred *a_cred; 465*5fe58019SAttilio Rao struct thread *a_td; 466*5fe58019SAttilio Rao }; 467*5fe58019SAttilio Rao */ 468*5fe58019SAttilio Rao static int 469*5fe58019SAttilio Rao fuse_vnop_getattr(struct vop_getattr_args *ap) 470*5fe58019SAttilio Rao { 471*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 472*5fe58019SAttilio Rao struct vattr *vap = ap->a_vap; 473*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 474*5fe58019SAttilio Rao struct thread *td = curthread; 475*5fe58019SAttilio Rao struct fuse_vnode_data *fvdat = VTOFUD(vp); 476*5fe58019SAttilio Rao 477*5fe58019SAttilio Rao int err = 0; 478*5fe58019SAttilio Rao int dataflags; 479*5fe58019SAttilio Rao struct fuse_dispatcher fdi; 480*5fe58019SAttilio Rao 481*5fe58019SAttilio Rao DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); 482*5fe58019SAttilio Rao 483*5fe58019SAttilio Rao dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags; 484*5fe58019SAttilio Rao 485*5fe58019SAttilio Rao /* Note that we are not bailing out on a dead file system just yet. */ 486*5fe58019SAttilio Rao 487*5fe58019SAttilio Rao /* look for cached attributes */ 488*5fe58019SAttilio Rao if (fuse_isvalid_attr(vp)) { 489*5fe58019SAttilio Rao if (vap != VTOVA(vp)) { 490*5fe58019SAttilio Rao memcpy(vap, VTOVA(vp), sizeof(*vap)); 491*5fe58019SAttilio Rao } 492*5fe58019SAttilio Rao if ((fvdat->flag & FN_SIZECHANGE) != 0) { 493*5fe58019SAttilio Rao vap->va_size = fvdat->filesize; 494*5fe58019SAttilio Rao } 495*5fe58019SAttilio Rao debug_printf("return cached: inode=%ju\n", (uintmax_t)VTOI(vp)); 496*5fe58019SAttilio Rao return 0; 497*5fe58019SAttilio Rao } 498*5fe58019SAttilio Rao if (!(dataflags & FSESS_INITED)) { 499*5fe58019SAttilio Rao if (!vnode_isvroot(vp)) { 500*5fe58019SAttilio Rao fdata_set_dead(fuse_get_mpdata(vnode_mount(vp))); 501*5fe58019SAttilio Rao err = ENOTCONN; 502*5fe58019SAttilio Rao debug_printf("fuse_getattr b: returning ENOTCONN\n"); 503*5fe58019SAttilio Rao return err; 504*5fe58019SAttilio Rao } else { 505*5fe58019SAttilio Rao goto fake; 506*5fe58019SAttilio Rao } 507*5fe58019SAttilio Rao } 508*5fe58019SAttilio Rao fdisp_init(&fdi, 0); 509*5fe58019SAttilio Rao if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) { 510*5fe58019SAttilio Rao if ((err == ENOTCONN) && vnode_isvroot(vp)) { 511*5fe58019SAttilio Rao /* see comment at similar place in fuse_statfs() */ 512*5fe58019SAttilio Rao fdisp_destroy(&fdi); 513*5fe58019SAttilio Rao goto fake; 514*5fe58019SAttilio Rao } 515*5fe58019SAttilio Rao if (err == ENOENT) { 516*5fe58019SAttilio Rao fuse_internal_vnode_disappear(vp); 517*5fe58019SAttilio Rao } 518*5fe58019SAttilio Rao goto out; 519*5fe58019SAttilio Rao } 520*5fe58019SAttilio Rao cache_attrs(vp, (struct fuse_attr_out *)fdi.answ); 521*5fe58019SAttilio Rao if (vap != VTOVA(vp)) { 522*5fe58019SAttilio Rao memcpy(vap, VTOVA(vp), sizeof(*vap)); 523*5fe58019SAttilio Rao } 524*5fe58019SAttilio Rao if ((fvdat->flag & FN_SIZECHANGE) != 0) 525*5fe58019SAttilio Rao vap->va_size = fvdat->filesize; 526*5fe58019SAttilio Rao 527*5fe58019SAttilio Rao if (vnode_isreg(vp) && (fvdat->flag & FN_SIZECHANGE) == 0) { 528*5fe58019SAttilio Rao /* 529*5fe58019SAttilio Rao * This is for those cases when the file size changed without us 530*5fe58019SAttilio Rao * knowing, and we want to catch up. 531*5fe58019SAttilio Rao */ 532*5fe58019SAttilio Rao off_t new_filesize = ((struct fuse_attr_out *) 533*5fe58019SAttilio Rao fdi.answ)->attr.size; 534*5fe58019SAttilio Rao 535*5fe58019SAttilio Rao if (fvdat->filesize != new_filesize) { 536*5fe58019SAttilio Rao fuse_vnode_setsize(vp, cred, new_filesize); 537*5fe58019SAttilio Rao } 538*5fe58019SAttilio Rao } 539*5fe58019SAttilio Rao KASSERT(vnode_vtype(vp) == vap->va_type, ("stale vnode")); 540*5fe58019SAttilio Rao debug_printf("fuse_getattr e: returning 0\n"); 541*5fe58019SAttilio Rao 542*5fe58019SAttilio Rao out: 543*5fe58019SAttilio Rao fdisp_destroy(&fdi); 544*5fe58019SAttilio Rao return err; 545*5fe58019SAttilio Rao 546*5fe58019SAttilio Rao fake: 547*5fe58019SAttilio Rao bzero(vap, sizeof(*vap)); 548*5fe58019SAttilio Rao vap->va_type = vnode_vtype(vp); 549*5fe58019SAttilio Rao 550*5fe58019SAttilio Rao return 0; 551*5fe58019SAttilio Rao } 552*5fe58019SAttilio Rao 553*5fe58019SAttilio Rao /* 554*5fe58019SAttilio Rao struct vnop_inactive_args { 555*5fe58019SAttilio Rao struct vnode *a_vp; 556*5fe58019SAttilio Rao struct thread *a_td; 557*5fe58019SAttilio Rao }; 558*5fe58019SAttilio Rao */ 559*5fe58019SAttilio Rao static int 560*5fe58019SAttilio Rao fuse_vnop_inactive(struct vop_inactive_args *ap) 561*5fe58019SAttilio Rao { 562*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 563*5fe58019SAttilio Rao struct thread *td = ap->a_td; 564*5fe58019SAttilio Rao 565*5fe58019SAttilio Rao struct fuse_vnode_data *fvdat = VTOFUD(vp); 566*5fe58019SAttilio Rao struct fuse_filehandle *fufh = NULL; 567*5fe58019SAttilio Rao 568*5fe58019SAttilio Rao int type, need_flush = 1; 569*5fe58019SAttilio Rao 570*5fe58019SAttilio Rao DEBUG("inode=%ju\n", (uintmax_t)VTOI(vp)); 571*5fe58019SAttilio Rao 572*5fe58019SAttilio Rao for (type = 0; type < FUFH_MAXTYPE; type++) { 573*5fe58019SAttilio Rao fufh = &(fvdat->fufh[type]); 574*5fe58019SAttilio Rao if (FUFH_IS_VALID(fufh)) { 575*5fe58019SAttilio Rao if (need_flush && vp->v_type == VREG) { 576*5fe58019SAttilio Rao if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) { 577*5fe58019SAttilio Rao fuse_vnode_savesize(vp, NULL); 578*5fe58019SAttilio Rao } 579*5fe58019SAttilio Rao if (fuse_data_cache_invalidate || 580*5fe58019SAttilio Rao (fvdat->flag & FN_REVOKED) != 0) 581*5fe58019SAttilio Rao fuse_io_invalbuf(vp, td); 582*5fe58019SAttilio Rao else 583*5fe58019SAttilio Rao fuse_io_flushbuf(vp, MNT_WAIT, td); 584*5fe58019SAttilio Rao need_flush = 0; 585*5fe58019SAttilio Rao } 586*5fe58019SAttilio Rao fuse_filehandle_close(vp, type, td, NULL); 587*5fe58019SAttilio Rao } 588*5fe58019SAttilio Rao } 589*5fe58019SAttilio Rao 590*5fe58019SAttilio Rao if ((fvdat->flag & FN_REVOKED) != 0 && fuse_reclaim_revoked) { 591*5fe58019SAttilio Rao vrecycle(vp); 592*5fe58019SAttilio Rao } 593*5fe58019SAttilio Rao return 0; 594*5fe58019SAttilio Rao } 595*5fe58019SAttilio Rao 596*5fe58019SAttilio Rao /* 597*5fe58019SAttilio Rao struct vnop_link_args { 598*5fe58019SAttilio Rao struct vnode *a_tdvp; 599*5fe58019SAttilio Rao struct vnode *a_vp; 600*5fe58019SAttilio Rao struct componentname *a_cnp; 601*5fe58019SAttilio Rao }; 602*5fe58019SAttilio Rao */ 603*5fe58019SAttilio Rao static int 604*5fe58019SAttilio Rao fuse_vnop_link(struct vop_link_args *ap) 605*5fe58019SAttilio Rao { 606*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 607*5fe58019SAttilio Rao struct vnode *tdvp = ap->a_tdvp; 608*5fe58019SAttilio Rao struct componentname *cnp = ap->a_cnp; 609*5fe58019SAttilio Rao 610*5fe58019SAttilio Rao struct vattr *vap = VTOVA(vp); 611*5fe58019SAttilio Rao 612*5fe58019SAttilio Rao struct fuse_dispatcher fdi; 613*5fe58019SAttilio Rao struct fuse_entry_out *feo; 614*5fe58019SAttilio Rao struct fuse_link_in fli; 615*5fe58019SAttilio Rao 616*5fe58019SAttilio Rao int err; 617*5fe58019SAttilio Rao 618*5fe58019SAttilio Rao fuse_trace_printf_vnop(); 619*5fe58019SAttilio Rao 620*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 621*5fe58019SAttilio Rao return ENXIO; 622*5fe58019SAttilio Rao } 623*5fe58019SAttilio Rao if (vnode_mount(tdvp) != vnode_mount(vp)) { 624*5fe58019SAttilio Rao return EXDEV; 625*5fe58019SAttilio Rao } 626*5fe58019SAttilio Rao if (vap->va_nlink >= FUSE_LINK_MAX) { 627*5fe58019SAttilio Rao return EMLINK; 628*5fe58019SAttilio Rao } 629*5fe58019SAttilio Rao fli.oldnodeid = VTOI(vp); 630*5fe58019SAttilio Rao 631*5fe58019SAttilio Rao fdisp_init(&fdi, 0); 632*5fe58019SAttilio Rao fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp, 633*5fe58019SAttilio Rao FUSE_LINK, &fli, sizeof(fli), &fdi); 634*5fe58019SAttilio Rao if ((err = fdisp_wait_answ(&fdi))) { 635*5fe58019SAttilio Rao goto out; 636*5fe58019SAttilio Rao } 637*5fe58019SAttilio Rao feo = fdi.answ; 638*5fe58019SAttilio Rao 639*5fe58019SAttilio Rao err = fuse_internal_checkentry(feo, vnode_vtype(vp)); 640*5fe58019SAttilio Rao fuse_invalidate_attr(tdvp); 641*5fe58019SAttilio Rao fuse_invalidate_attr(vp); 642*5fe58019SAttilio Rao 643*5fe58019SAttilio Rao out: 644*5fe58019SAttilio Rao fdisp_destroy(&fdi); 645*5fe58019SAttilio Rao return err; 646*5fe58019SAttilio Rao } 647*5fe58019SAttilio Rao 648*5fe58019SAttilio Rao /* 649*5fe58019SAttilio Rao struct vnop_lookup_args { 650*5fe58019SAttilio Rao struct vnodeop_desc *a_desc; 651*5fe58019SAttilio Rao struct vnode *a_dvp; 652*5fe58019SAttilio Rao struct vnode **a_vpp; 653*5fe58019SAttilio Rao struct componentname *a_cnp; 654*5fe58019SAttilio Rao }; 655*5fe58019SAttilio Rao */ 656*5fe58019SAttilio Rao int 657*5fe58019SAttilio Rao fuse_vnop_lookup(struct vop_lookup_args *ap) 658*5fe58019SAttilio Rao { 659*5fe58019SAttilio Rao struct vnode *dvp = ap->a_dvp; 660*5fe58019SAttilio Rao struct vnode **vpp = ap->a_vpp; 661*5fe58019SAttilio Rao struct componentname *cnp = ap->a_cnp; 662*5fe58019SAttilio Rao struct thread *td = cnp->cn_thread; 663*5fe58019SAttilio Rao struct ucred *cred = cnp->cn_cred; 664*5fe58019SAttilio Rao 665*5fe58019SAttilio Rao int nameiop = cnp->cn_nameiop; 666*5fe58019SAttilio Rao int flags = cnp->cn_flags; 667*5fe58019SAttilio Rao int wantparent = flags & (LOCKPARENT | WANTPARENT); 668*5fe58019SAttilio Rao int islastcn = flags & ISLASTCN; 669*5fe58019SAttilio Rao struct mount *mp = vnode_mount(dvp); 670*5fe58019SAttilio Rao 671*5fe58019SAttilio Rao int err = 0; 672*5fe58019SAttilio Rao int lookup_err = 0; 673*5fe58019SAttilio Rao struct vnode *vp = NULL; 674*5fe58019SAttilio Rao 675*5fe58019SAttilio Rao struct fuse_dispatcher fdi; 676*5fe58019SAttilio Rao enum fuse_opcode op; 677*5fe58019SAttilio Rao 678*5fe58019SAttilio Rao uint64_t nid; 679*5fe58019SAttilio Rao struct fuse_access_param facp; 680*5fe58019SAttilio Rao 681*5fe58019SAttilio Rao DEBUG2G("parent_inode=%ju - %*s\n", 682*5fe58019SAttilio Rao (uintmax_t)VTOI(dvp), (int)cnp->cn_namelen, cnp->cn_nameptr); 683*5fe58019SAttilio Rao 684*5fe58019SAttilio Rao if (fuse_isdeadfs(dvp)) { 685*5fe58019SAttilio Rao *vpp = NULL; 686*5fe58019SAttilio Rao return ENXIO; 687*5fe58019SAttilio Rao } 688*5fe58019SAttilio Rao if (!vnode_isdir(dvp)) { 689*5fe58019SAttilio Rao return ENOTDIR; 690*5fe58019SAttilio Rao } 691*5fe58019SAttilio Rao if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP)) { 692*5fe58019SAttilio Rao return EROFS; 693*5fe58019SAttilio Rao } 694*5fe58019SAttilio Rao /* 695*5fe58019SAttilio Rao * We do access check prior to doing anything else only in the case 696*5fe58019SAttilio Rao * when we are at fs root (we'd like to say, "we are at the first 697*5fe58019SAttilio Rao * component", but that's not exactly the same... nevermind). 698*5fe58019SAttilio Rao * See further comments at further access checks. 699*5fe58019SAttilio Rao */ 700*5fe58019SAttilio Rao 701*5fe58019SAttilio Rao bzero(&facp, sizeof(facp)); 702*5fe58019SAttilio Rao if (vnode_isvroot(dvp)) { /* early permission check hack */ 703*5fe58019SAttilio Rao if ((err = fuse_internal_access(dvp, VEXEC, &facp, td, cred))) { 704*5fe58019SAttilio Rao return err; 705*5fe58019SAttilio Rao } 706*5fe58019SAttilio Rao } 707*5fe58019SAttilio Rao if (flags & ISDOTDOT) { 708*5fe58019SAttilio Rao nid = VTOFUD(dvp)->parent_nid; 709*5fe58019SAttilio Rao if (nid == 0) { 710*5fe58019SAttilio Rao return ENOENT; 711*5fe58019SAttilio Rao } 712*5fe58019SAttilio Rao fdisp_init(&fdi, 0); 713*5fe58019SAttilio Rao op = FUSE_GETATTR; 714*5fe58019SAttilio Rao goto calldaemon; 715*5fe58019SAttilio Rao } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') { 716*5fe58019SAttilio Rao nid = VTOI(dvp); 717*5fe58019SAttilio Rao fdisp_init(&fdi, 0); 718*5fe58019SAttilio Rao op = FUSE_GETATTR; 719*5fe58019SAttilio Rao goto calldaemon; 720*5fe58019SAttilio Rao } else if (fuse_lookup_cache_enable) { 721*5fe58019SAttilio Rao err = cache_lookup(dvp, vpp, cnp, NULL, NULL); 722*5fe58019SAttilio Rao switch (err) { 723*5fe58019SAttilio Rao 724*5fe58019SAttilio Rao case -1: /* positive match */ 725*5fe58019SAttilio Rao atomic_add_acq_long(&fuse_lookup_cache_hits, 1); 726*5fe58019SAttilio Rao return 0; 727*5fe58019SAttilio Rao 728*5fe58019SAttilio Rao case 0: /* no match in cache */ 729*5fe58019SAttilio Rao atomic_add_acq_long(&fuse_lookup_cache_misses, 1); 730*5fe58019SAttilio Rao break; 731*5fe58019SAttilio Rao 732*5fe58019SAttilio Rao case ENOENT: /* negative match */ 733*5fe58019SAttilio Rao /* fall through */ 734*5fe58019SAttilio Rao default: 735*5fe58019SAttilio Rao return err; 736*5fe58019SAttilio Rao } 737*5fe58019SAttilio Rao } 738*5fe58019SAttilio Rao nid = VTOI(dvp); 739*5fe58019SAttilio Rao fdisp_init(&fdi, cnp->cn_namelen + 1); 740*5fe58019SAttilio Rao op = FUSE_LOOKUP; 741*5fe58019SAttilio Rao 742*5fe58019SAttilio Rao calldaemon: 743*5fe58019SAttilio Rao fdisp_make(&fdi, op, mp, nid, td, cred); 744*5fe58019SAttilio Rao 745*5fe58019SAttilio Rao if (op == FUSE_LOOKUP) { 746*5fe58019SAttilio Rao memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 747*5fe58019SAttilio Rao ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 748*5fe58019SAttilio Rao } 749*5fe58019SAttilio Rao lookup_err = fdisp_wait_answ(&fdi); 750*5fe58019SAttilio Rao 751*5fe58019SAttilio Rao if ((op == FUSE_LOOKUP) && !lookup_err) { /* lookup call succeeded */ 752*5fe58019SAttilio Rao nid = ((struct fuse_entry_out *)fdi.answ)->nodeid; 753*5fe58019SAttilio Rao if (!nid) { 754*5fe58019SAttilio Rao /* 755*5fe58019SAttilio Rao * zero nodeid is the same as "not found", 756*5fe58019SAttilio Rao * but it's also cacheable (which we keep 757*5fe58019SAttilio Rao * keep on doing not as of writing this) 758*5fe58019SAttilio Rao */ 759*5fe58019SAttilio Rao lookup_err = ENOENT; 760*5fe58019SAttilio Rao } else if (nid == FUSE_ROOT_ID) { 761*5fe58019SAttilio Rao lookup_err = EINVAL; 762*5fe58019SAttilio Rao } 763*5fe58019SAttilio Rao } 764*5fe58019SAttilio Rao if (lookup_err && 765*5fe58019SAttilio Rao (!fdi.answ_stat || lookup_err != ENOENT || op != FUSE_LOOKUP)) { 766*5fe58019SAttilio Rao fdisp_destroy(&fdi); 767*5fe58019SAttilio Rao return lookup_err; 768*5fe58019SAttilio Rao } 769*5fe58019SAttilio Rao /* lookup_err, if non-zero, must be ENOENT at this point */ 770*5fe58019SAttilio Rao 771*5fe58019SAttilio Rao if (lookup_err) { 772*5fe58019SAttilio Rao 773*5fe58019SAttilio Rao if ((nameiop == CREATE || nameiop == RENAME) && islastcn 774*5fe58019SAttilio Rao /* && directory dvp has not been removed */ ) { 775*5fe58019SAttilio Rao 776*5fe58019SAttilio Rao if (vfs_isrdonly(mp)) { 777*5fe58019SAttilio Rao err = EROFS; 778*5fe58019SAttilio Rao goto out; 779*5fe58019SAttilio Rao } 780*5fe58019SAttilio Rao #if 0 /* THINK_ABOUT_THIS */ 781*5fe58019SAttilio Rao if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) { 782*5fe58019SAttilio Rao goto out; 783*5fe58019SAttilio Rao } 784*5fe58019SAttilio Rao #endif 785*5fe58019SAttilio Rao 786*5fe58019SAttilio Rao /* 787*5fe58019SAttilio Rao * Possibly record the position of a slot in the 788*5fe58019SAttilio Rao * directory large enough for the new component name. 789*5fe58019SAttilio Rao * This can be recorded in the vnode private data for 790*5fe58019SAttilio Rao * dvp. Set the SAVENAME flag to hold onto the 791*5fe58019SAttilio Rao * pathname for use later in VOP_CREATE or VOP_RENAME. 792*5fe58019SAttilio Rao */ 793*5fe58019SAttilio Rao cnp->cn_flags |= SAVENAME; 794*5fe58019SAttilio Rao 795*5fe58019SAttilio Rao err = EJUSTRETURN; 796*5fe58019SAttilio Rao goto out; 797*5fe58019SAttilio Rao } 798*5fe58019SAttilio Rao /* Consider inserting name into cache. */ 799*5fe58019SAttilio Rao 800*5fe58019SAttilio Rao /* 801*5fe58019SAttilio Rao * No we can't use negative caching, as the fs 802*5fe58019SAttilio Rao * changes are out of our control. 803*5fe58019SAttilio Rao * False positives' falseness turns out just as things 804*5fe58019SAttilio Rao * go by, but false negatives' falseness doesn't. 805*5fe58019SAttilio Rao * (and aiding the caching mechanism with extra control 806*5fe58019SAttilio Rao * mechanisms comes quite close to beating the whole purpose 807*5fe58019SAttilio Rao * caching...) 808*5fe58019SAttilio Rao */ 809*5fe58019SAttilio Rao #if 0 810*5fe58019SAttilio Rao if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) { 811*5fe58019SAttilio Rao DEBUG("inserting NULL into cache\n"); 812*5fe58019SAttilio Rao cache_enter(dvp, NULL, cnp); 813*5fe58019SAttilio Rao } 814*5fe58019SAttilio Rao #endif 815*5fe58019SAttilio Rao err = ENOENT; 816*5fe58019SAttilio Rao goto out; 817*5fe58019SAttilio Rao 818*5fe58019SAttilio Rao } else { 819*5fe58019SAttilio Rao 820*5fe58019SAttilio Rao /* !lookup_err */ 821*5fe58019SAttilio Rao 822*5fe58019SAttilio Rao struct fuse_entry_out *feo = NULL; 823*5fe58019SAttilio Rao struct fuse_attr *fattr = NULL; 824*5fe58019SAttilio Rao 825*5fe58019SAttilio Rao if (op == FUSE_GETATTR) { 826*5fe58019SAttilio Rao fattr = &((struct fuse_attr_out *)fdi.answ)->attr; 827*5fe58019SAttilio Rao } else { 828*5fe58019SAttilio Rao feo = (struct fuse_entry_out *)fdi.answ; 829*5fe58019SAttilio Rao fattr = &(feo->attr); 830*5fe58019SAttilio Rao } 831*5fe58019SAttilio Rao 832*5fe58019SAttilio Rao /* 833*5fe58019SAttilio Rao * If deleting, and at end of pathname, return parameters 834*5fe58019SAttilio Rao * which can be used to remove file. If the wantparent flag 835*5fe58019SAttilio Rao * isn't set, we return only the directory, otherwise we go on 836*5fe58019SAttilio Rao * and lock the inode, being careful with ".". 837*5fe58019SAttilio Rao */ 838*5fe58019SAttilio Rao if (nameiop == DELETE && islastcn) { 839*5fe58019SAttilio Rao /* 840*5fe58019SAttilio Rao * Check for write access on directory. 841*5fe58019SAttilio Rao */ 842*5fe58019SAttilio Rao facp.xuid = fattr->uid; 843*5fe58019SAttilio Rao facp.facc_flags |= FACCESS_STICKY; 844*5fe58019SAttilio Rao err = fuse_internal_access(dvp, VWRITE, &facp, td, cred); 845*5fe58019SAttilio Rao facp.facc_flags &= ~FACCESS_XQUERIES; 846*5fe58019SAttilio Rao 847*5fe58019SAttilio Rao if (err) { 848*5fe58019SAttilio Rao goto out; 849*5fe58019SAttilio Rao } 850*5fe58019SAttilio Rao if (nid == VTOI(dvp)) { 851*5fe58019SAttilio Rao vref(dvp); 852*5fe58019SAttilio Rao *vpp = dvp; 853*5fe58019SAttilio Rao } else { 854*5fe58019SAttilio Rao err = fuse_vnode_get(dvp->v_mount, nid, dvp, 855*5fe58019SAttilio Rao &vp, cnp, IFTOVT(fattr->mode)); 856*5fe58019SAttilio Rao if (err) 857*5fe58019SAttilio Rao goto out; 858*5fe58019SAttilio Rao *vpp = vp; 859*5fe58019SAttilio Rao } 860*5fe58019SAttilio Rao 861*5fe58019SAttilio Rao /* 862*5fe58019SAttilio Rao * Save the name for use in VOP_RMDIR and VOP_REMOVE 863*5fe58019SAttilio Rao * later. 864*5fe58019SAttilio Rao */ 865*5fe58019SAttilio Rao cnp->cn_flags |= SAVENAME; 866*5fe58019SAttilio Rao goto out; 867*5fe58019SAttilio Rao 868*5fe58019SAttilio Rao } 869*5fe58019SAttilio Rao /* 870*5fe58019SAttilio Rao * If rewriting (RENAME), return the inode and the 871*5fe58019SAttilio Rao * information required to rewrite the present directory 872*5fe58019SAttilio Rao * Must get inode of directory entry to verify it's a 873*5fe58019SAttilio Rao * regular file, or empty directory. 874*5fe58019SAttilio Rao */ 875*5fe58019SAttilio Rao if (nameiop == RENAME && wantparent && islastcn) { 876*5fe58019SAttilio Rao 877*5fe58019SAttilio Rao #if 0 /* THINK_ABOUT_THIS */ 878*5fe58019SAttilio Rao if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) { 879*5fe58019SAttilio Rao goto out; 880*5fe58019SAttilio Rao } 881*5fe58019SAttilio Rao #endif 882*5fe58019SAttilio Rao 883*5fe58019SAttilio Rao /* 884*5fe58019SAttilio Rao * Check for "." 885*5fe58019SAttilio Rao */ 886*5fe58019SAttilio Rao if (nid == VTOI(dvp)) { 887*5fe58019SAttilio Rao err = EISDIR; 888*5fe58019SAttilio Rao goto out; 889*5fe58019SAttilio Rao } 890*5fe58019SAttilio Rao err = fuse_vnode_get(vnode_mount(dvp), 891*5fe58019SAttilio Rao nid, 892*5fe58019SAttilio Rao dvp, 893*5fe58019SAttilio Rao &vp, 894*5fe58019SAttilio Rao cnp, 895*5fe58019SAttilio Rao IFTOVT(fattr->mode)); 896*5fe58019SAttilio Rao if (err) { 897*5fe58019SAttilio Rao goto out; 898*5fe58019SAttilio Rao } 899*5fe58019SAttilio Rao *vpp = vp; 900*5fe58019SAttilio Rao /* 901*5fe58019SAttilio Rao * Save the name for use in VOP_RENAME later. 902*5fe58019SAttilio Rao */ 903*5fe58019SAttilio Rao cnp->cn_flags |= SAVENAME; 904*5fe58019SAttilio Rao 905*5fe58019SAttilio Rao goto out; 906*5fe58019SAttilio Rao } 907*5fe58019SAttilio Rao if (flags & ISDOTDOT) { 908*5fe58019SAttilio Rao struct mount *mp; 909*5fe58019SAttilio Rao int ltype; 910*5fe58019SAttilio Rao 911*5fe58019SAttilio Rao /* 912*5fe58019SAttilio Rao * Expanded copy of vn_vget_ino() so that 913*5fe58019SAttilio Rao * fuse_vnode_get() can be used. 914*5fe58019SAttilio Rao */ 915*5fe58019SAttilio Rao mp = dvp->v_mount; 916*5fe58019SAttilio Rao ltype = VOP_ISLOCKED(dvp); 917*5fe58019SAttilio Rao err = vfs_busy(mp, MBF_NOWAIT); 918*5fe58019SAttilio Rao if (err != 0) { 919*5fe58019SAttilio Rao vfs_ref(mp); 920*5fe58019SAttilio Rao VOP_UNLOCK(dvp, 0); 921*5fe58019SAttilio Rao err = vfs_busy(mp, 0); 922*5fe58019SAttilio Rao vn_lock(dvp, ltype | LK_RETRY); 923*5fe58019SAttilio Rao vfs_rel(mp); 924*5fe58019SAttilio Rao if (err) 925*5fe58019SAttilio Rao goto out; 926*5fe58019SAttilio Rao if ((dvp->v_iflag & VI_DOOMED) != 0) { 927*5fe58019SAttilio Rao err = ENOENT; 928*5fe58019SAttilio Rao vfs_unbusy(mp); 929*5fe58019SAttilio Rao goto out; 930*5fe58019SAttilio Rao } 931*5fe58019SAttilio Rao } 932*5fe58019SAttilio Rao VOP_UNLOCK(dvp, 0); 933*5fe58019SAttilio Rao err = fuse_vnode_get(vnode_mount(dvp), 934*5fe58019SAttilio Rao nid, 935*5fe58019SAttilio Rao NULL, 936*5fe58019SAttilio Rao &vp, 937*5fe58019SAttilio Rao cnp, 938*5fe58019SAttilio Rao IFTOVT(fattr->mode)); 939*5fe58019SAttilio Rao vfs_unbusy(mp); 940*5fe58019SAttilio Rao vn_lock(dvp, ltype | LK_RETRY); 941*5fe58019SAttilio Rao if ((dvp->v_iflag & VI_DOOMED) != 0) { 942*5fe58019SAttilio Rao if (err == 0) 943*5fe58019SAttilio Rao vput(vp); 944*5fe58019SAttilio Rao err = ENOENT; 945*5fe58019SAttilio Rao } 946*5fe58019SAttilio Rao if (err) 947*5fe58019SAttilio Rao goto out; 948*5fe58019SAttilio Rao *vpp = vp; 949*5fe58019SAttilio Rao } else if (nid == VTOI(dvp)) { 950*5fe58019SAttilio Rao vref(dvp); 951*5fe58019SAttilio Rao *vpp = dvp; 952*5fe58019SAttilio Rao } else { 953*5fe58019SAttilio Rao err = fuse_vnode_get(vnode_mount(dvp), 954*5fe58019SAttilio Rao nid, 955*5fe58019SAttilio Rao dvp, 956*5fe58019SAttilio Rao &vp, 957*5fe58019SAttilio Rao cnp, 958*5fe58019SAttilio Rao IFTOVT(fattr->mode)); 959*5fe58019SAttilio Rao if (err) { 960*5fe58019SAttilio Rao goto out; 961*5fe58019SAttilio Rao } 962*5fe58019SAttilio Rao fuse_vnode_setparent(vp, dvp); 963*5fe58019SAttilio Rao *vpp = vp; 964*5fe58019SAttilio Rao } 965*5fe58019SAttilio Rao 966*5fe58019SAttilio Rao if (op == FUSE_GETATTR) { 967*5fe58019SAttilio Rao cache_attrs(*vpp, (struct fuse_attr_out *)fdi.answ); 968*5fe58019SAttilio Rao } else { 969*5fe58019SAttilio Rao cache_attrs(*vpp, (struct fuse_entry_out *)fdi.answ); 970*5fe58019SAttilio Rao } 971*5fe58019SAttilio Rao 972*5fe58019SAttilio Rao /* Insert name into cache if appropriate. */ 973*5fe58019SAttilio Rao 974*5fe58019SAttilio Rao /* 975*5fe58019SAttilio Rao * Nooo, caching is evil. With caching, we can't avoid stale 976*5fe58019SAttilio Rao * information taking over the playground (cached info is not 977*5fe58019SAttilio Rao * just positive/negative, it does have qualitative aspects, 978*5fe58019SAttilio Rao * too). And a (VOP/FUSE)_GETATTR is always thrown anyway, when 979*5fe58019SAttilio Rao * walking down along cached path components, and that's not 980*5fe58019SAttilio Rao * any cheaper than FUSE_LOOKUP. This might change with 981*5fe58019SAttilio Rao * implementing kernel side attr caching, but... In Linux, 982*5fe58019SAttilio Rao * lookup results are not cached, and the daemon is bombarded 983*5fe58019SAttilio Rao * with FUSE_LOOKUPS on and on. This shows that by design, the 984*5fe58019SAttilio Rao * daemon is expected to handle frequent lookup queries 985*5fe58019SAttilio Rao * efficiently, do its caching in userspace, and so on. 986*5fe58019SAttilio Rao * 987*5fe58019SAttilio Rao * So just leave the name cache alone. 988*5fe58019SAttilio Rao */ 989*5fe58019SAttilio Rao 990*5fe58019SAttilio Rao /* 991*5fe58019SAttilio Rao * Well, now I know, Linux caches lookups, but with a 992*5fe58019SAttilio Rao * timeout... So it's the same thing as attribute caching: 993*5fe58019SAttilio Rao * we can deal with it when implement timeouts. 994*5fe58019SAttilio Rao */ 995*5fe58019SAttilio Rao #if 0 996*5fe58019SAttilio Rao if (cnp->cn_flags & MAKEENTRY) { 997*5fe58019SAttilio Rao cache_enter(dvp, *vpp, cnp); 998*5fe58019SAttilio Rao } 999*5fe58019SAttilio Rao #endif 1000*5fe58019SAttilio Rao } 1001*5fe58019SAttilio Rao out: 1002*5fe58019SAttilio Rao if (!lookup_err) { 1003*5fe58019SAttilio Rao 1004*5fe58019SAttilio Rao /* No lookup error; need to clean up. */ 1005*5fe58019SAttilio Rao 1006*5fe58019SAttilio Rao if (err) { /* Found inode; exit with no vnode. */ 1007*5fe58019SAttilio Rao if (op == FUSE_LOOKUP) { 1008*5fe58019SAttilio Rao fuse_internal_forget_send(vnode_mount(dvp), td, cred, 1009*5fe58019SAttilio Rao nid, 1); 1010*5fe58019SAttilio Rao } 1011*5fe58019SAttilio Rao fdisp_destroy(&fdi); 1012*5fe58019SAttilio Rao return err; 1013*5fe58019SAttilio Rao } else { 1014*5fe58019SAttilio Rao #ifndef NO_EARLY_PERM_CHECK_HACK 1015*5fe58019SAttilio Rao if (!islastcn) { 1016*5fe58019SAttilio Rao /* 1017*5fe58019SAttilio Rao * We have the attributes of the next item 1018*5fe58019SAttilio Rao * *now*, and it's a fact, and we do not 1019*5fe58019SAttilio Rao * have to do extra work for it (ie, beg the 1020*5fe58019SAttilio Rao * daemon), and it neither depends on such 1021*5fe58019SAttilio Rao * accidental things like attr caching. So 1022*5fe58019SAttilio Rao * the big idea: check credentials *now*, 1023*5fe58019SAttilio Rao * not at the beginning of the next call to 1024*5fe58019SAttilio Rao * lookup. 1025*5fe58019SAttilio Rao * 1026*5fe58019SAttilio Rao * The first item of the lookup chain (fs root) 1027*5fe58019SAttilio Rao * won't be checked then here, of course, as 1028*5fe58019SAttilio Rao * its never "the next". But go and see that 1029*5fe58019SAttilio Rao * the root is taken care about at the very 1030*5fe58019SAttilio Rao * beginning of this function. 1031*5fe58019SAttilio Rao * 1032*5fe58019SAttilio Rao * Now, given we want to do the access check 1033*5fe58019SAttilio Rao * this way, one might ask: so then why not 1034*5fe58019SAttilio Rao * do the access check just after fetching 1035*5fe58019SAttilio Rao * the inode and its attributes from the 1036*5fe58019SAttilio Rao * daemon? Why bother with producing the 1037*5fe58019SAttilio Rao * corresponding vnode at all if something 1038*5fe58019SAttilio Rao * is not OK? We know what's the deal as 1039*5fe58019SAttilio Rao * soon as we get those attrs... There is 1040*5fe58019SAttilio Rao * one bit of info though not given us by 1041*5fe58019SAttilio Rao * the daemon: whether his response is 1042*5fe58019SAttilio Rao * authorative or not... His response should 1043*5fe58019SAttilio Rao * be ignored if something is mounted over 1044*5fe58019SAttilio Rao * the dir in question. But that can be 1045*5fe58019SAttilio Rao * known only by having the vnode... 1046*5fe58019SAttilio Rao */ 1047*5fe58019SAttilio Rao int tmpvtype = vnode_vtype(*vpp); 1048*5fe58019SAttilio Rao 1049*5fe58019SAttilio Rao bzero(&facp, sizeof(facp)); 1050*5fe58019SAttilio Rao /*the early perm check hack */ 1051*5fe58019SAttilio Rao facp.facc_flags |= FACCESS_VA_VALID; 1052*5fe58019SAttilio Rao 1053*5fe58019SAttilio Rao if ((tmpvtype != VDIR) && (tmpvtype != VLNK)) { 1054*5fe58019SAttilio Rao err = ENOTDIR; 1055*5fe58019SAttilio Rao } 1056*5fe58019SAttilio Rao if (!err && !vnode_mountedhere(*vpp)) { 1057*5fe58019SAttilio Rao err = fuse_internal_access(*vpp, VEXEC, &facp, td, cred); 1058*5fe58019SAttilio Rao } 1059*5fe58019SAttilio Rao if (err) { 1060*5fe58019SAttilio Rao if (tmpvtype == VLNK) 1061*5fe58019SAttilio Rao DEBUG("weird, permission error with a symlink?\n"); 1062*5fe58019SAttilio Rao vput(*vpp); 1063*5fe58019SAttilio Rao *vpp = NULL; 1064*5fe58019SAttilio Rao } 1065*5fe58019SAttilio Rao } 1066*5fe58019SAttilio Rao #endif 1067*5fe58019SAttilio Rao } 1068*5fe58019SAttilio Rao } 1069*5fe58019SAttilio Rao fdisp_destroy(&fdi); 1070*5fe58019SAttilio Rao 1071*5fe58019SAttilio Rao return err; 1072*5fe58019SAttilio Rao } 1073*5fe58019SAttilio Rao 1074*5fe58019SAttilio Rao /* 1075*5fe58019SAttilio Rao struct vnop_mkdir_args { 1076*5fe58019SAttilio Rao struct vnode *a_dvp; 1077*5fe58019SAttilio Rao struct vnode **a_vpp; 1078*5fe58019SAttilio Rao struct componentname *a_cnp; 1079*5fe58019SAttilio Rao struct vattr *a_vap; 1080*5fe58019SAttilio Rao }; 1081*5fe58019SAttilio Rao */ 1082*5fe58019SAttilio Rao static int 1083*5fe58019SAttilio Rao fuse_vnop_mkdir(struct vop_mkdir_args *ap) 1084*5fe58019SAttilio Rao { 1085*5fe58019SAttilio Rao struct vnode *dvp = ap->a_dvp; 1086*5fe58019SAttilio Rao struct vnode **vpp = ap->a_vpp; 1087*5fe58019SAttilio Rao struct componentname *cnp = ap->a_cnp; 1088*5fe58019SAttilio Rao struct vattr *vap = ap->a_vap; 1089*5fe58019SAttilio Rao 1090*5fe58019SAttilio Rao int err = 0; 1091*5fe58019SAttilio Rao 1092*5fe58019SAttilio Rao struct fuse_mkdir_in fmdi; 1093*5fe58019SAttilio Rao 1094*5fe58019SAttilio Rao fuse_trace_printf_vnop(); 1095*5fe58019SAttilio Rao 1096*5fe58019SAttilio Rao if (fuse_isdeadfs(dvp)) { 1097*5fe58019SAttilio Rao return ENXIO; 1098*5fe58019SAttilio Rao } 1099*5fe58019SAttilio Rao fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode); 1100*5fe58019SAttilio Rao 1101*5fe58019SAttilio Rao err = fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi, 1102*5fe58019SAttilio Rao sizeof(fmdi), VDIR); 1103*5fe58019SAttilio Rao 1104*5fe58019SAttilio Rao if (err == 0) { 1105*5fe58019SAttilio Rao fuse_invalidate_attr(dvp); 1106*5fe58019SAttilio Rao } 1107*5fe58019SAttilio Rao return err; 1108*5fe58019SAttilio Rao } 1109*5fe58019SAttilio Rao 1110*5fe58019SAttilio Rao /* 1111*5fe58019SAttilio Rao struct vnop_mknod_args { 1112*5fe58019SAttilio Rao struct vnode *a_dvp; 1113*5fe58019SAttilio Rao struct vnode **a_vpp; 1114*5fe58019SAttilio Rao struct componentname *a_cnp; 1115*5fe58019SAttilio Rao struct vattr *a_vap; 1116*5fe58019SAttilio Rao }; 1117*5fe58019SAttilio Rao */ 1118*5fe58019SAttilio Rao static int 1119*5fe58019SAttilio Rao fuse_vnop_mknod(struct vop_mknod_args *ap) 1120*5fe58019SAttilio Rao { 1121*5fe58019SAttilio Rao 1122*5fe58019SAttilio Rao return (EINVAL); 1123*5fe58019SAttilio Rao } 1124*5fe58019SAttilio Rao 1125*5fe58019SAttilio Rao 1126*5fe58019SAttilio Rao /* 1127*5fe58019SAttilio Rao struct vnop_open_args { 1128*5fe58019SAttilio Rao struct vnode *a_vp; 1129*5fe58019SAttilio Rao int a_mode; 1130*5fe58019SAttilio Rao struct ucred *a_cred; 1131*5fe58019SAttilio Rao struct thread *a_td; 1132*5fe58019SAttilio Rao int a_fdidx; / struct file *a_fp; 1133*5fe58019SAttilio Rao }; 1134*5fe58019SAttilio Rao */ 1135*5fe58019SAttilio Rao static int 1136*5fe58019SAttilio Rao fuse_vnop_open(struct vop_open_args *ap) 1137*5fe58019SAttilio Rao { 1138*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1139*5fe58019SAttilio Rao int mode = ap->a_mode; 1140*5fe58019SAttilio Rao struct thread *td = ap->a_td; 1141*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 1142*5fe58019SAttilio Rao 1143*5fe58019SAttilio Rao fufh_type_t fufh_type; 1144*5fe58019SAttilio Rao struct fuse_vnode_data *fvdat; 1145*5fe58019SAttilio Rao 1146*5fe58019SAttilio Rao int error, isdir = 0; 1147*5fe58019SAttilio Rao 1148*5fe58019SAttilio Rao DEBUG2G("inode=%ju mode=0x%x\n", (uintmax_t)VTOI(vp), mode); 1149*5fe58019SAttilio Rao 1150*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 1151*5fe58019SAttilio Rao return ENXIO; 1152*5fe58019SAttilio Rao } 1153*5fe58019SAttilio Rao fvdat = VTOFUD(vp); 1154*5fe58019SAttilio Rao 1155*5fe58019SAttilio Rao if (vnode_isdir(vp)) { 1156*5fe58019SAttilio Rao isdir = 1; 1157*5fe58019SAttilio Rao } 1158*5fe58019SAttilio Rao if (isdir) { 1159*5fe58019SAttilio Rao fufh_type = FUFH_RDONLY; 1160*5fe58019SAttilio Rao } else { 1161*5fe58019SAttilio Rao fufh_type = fuse_filehandle_xlate_from_fflags(mode); 1162*5fe58019SAttilio Rao } 1163*5fe58019SAttilio Rao 1164*5fe58019SAttilio Rao if (fuse_filehandle_valid(vp, fufh_type)) { 1165*5fe58019SAttilio Rao fuse_vnode_open(vp, 0, td); 1166*5fe58019SAttilio Rao return 0; 1167*5fe58019SAttilio Rao } 1168*5fe58019SAttilio Rao error = fuse_filehandle_open(vp, fufh_type, NULL, td, cred); 1169*5fe58019SAttilio Rao 1170*5fe58019SAttilio Rao return error; 1171*5fe58019SAttilio Rao } 1172*5fe58019SAttilio Rao 1173*5fe58019SAttilio Rao /* 1174*5fe58019SAttilio Rao struct vnop_read_args { 1175*5fe58019SAttilio Rao struct vnode *a_vp; 1176*5fe58019SAttilio Rao struct uio *a_uio; 1177*5fe58019SAttilio Rao int a_ioflag; 1178*5fe58019SAttilio Rao struct ucred *a_cred; 1179*5fe58019SAttilio Rao }; 1180*5fe58019SAttilio Rao */ 1181*5fe58019SAttilio Rao static int 1182*5fe58019SAttilio Rao fuse_vnop_read(struct vop_read_args *ap) 1183*5fe58019SAttilio Rao { 1184*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1185*5fe58019SAttilio Rao struct uio *uio = ap->a_uio; 1186*5fe58019SAttilio Rao int ioflag = ap->a_ioflag; 1187*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 1188*5fe58019SAttilio Rao 1189*5fe58019SAttilio Rao DEBUG2G("inode=%ju offset=%jd resid=%zd\n", 1190*5fe58019SAttilio Rao (uintmax_t)VTOI(vp), uio->uio_offset, uio->uio_resid); 1191*5fe58019SAttilio Rao 1192*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 1193*5fe58019SAttilio Rao return ENXIO; 1194*5fe58019SAttilio Rao } 1195*5fe58019SAttilio Rao return fuse_io_dispatch(vp, uio, ioflag, cred); 1196*5fe58019SAttilio Rao } 1197*5fe58019SAttilio Rao 1198*5fe58019SAttilio Rao /* 1199*5fe58019SAttilio Rao struct vnop_readdir_args { 1200*5fe58019SAttilio Rao struct vnode *a_vp; 1201*5fe58019SAttilio Rao struct uio *a_uio; 1202*5fe58019SAttilio Rao struct ucred *a_cred; 1203*5fe58019SAttilio Rao int *a_eofflag; 1204*5fe58019SAttilio Rao int *ncookies; 1205*5fe58019SAttilio Rao u_long **a_cookies; 1206*5fe58019SAttilio Rao }; 1207*5fe58019SAttilio Rao */ 1208*5fe58019SAttilio Rao static int 1209*5fe58019SAttilio Rao fuse_vnop_readdir(struct vop_readdir_args *ap) 1210*5fe58019SAttilio Rao { 1211*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1212*5fe58019SAttilio Rao struct uio *uio = ap->a_uio; 1213*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 1214*5fe58019SAttilio Rao 1215*5fe58019SAttilio Rao struct fuse_filehandle *fufh = NULL; 1216*5fe58019SAttilio Rao struct fuse_vnode_data *fvdat; 1217*5fe58019SAttilio Rao struct fuse_iov cookediov; 1218*5fe58019SAttilio Rao 1219*5fe58019SAttilio Rao int err = 0; 1220*5fe58019SAttilio Rao int freefufh = 0; 1221*5fe58019SAttilio Rao 1222*5fe58019SAttilio Rao DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); 1223*5fe58019SAttilio Rao 1224*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 1225*5fe58019SAttilio Rao return ENXIO; 1226*5fe58019SAttilio Rao } 1227*5fe58019SAttilio Rao if ( /* XXXIP ((uio_iovcnt(uio) > 1)) || */ 1228*5fe58019SAttilio Rao (uio_resid(uio) < sizeof(struct dirent))) { 1229*5fe58019SAttilio Rao return EINVAL; 1230*5fe58019SAttilio Rao } 1231*5fe58019SAttilio Rao fvdat = VTOFUD(vp); 1232*5fe58019SAttilio Rao 1233*5fe58019SAttilio Rao if (!fuse_filehandle_valid(vp, FUFH_RDONLY)) { 1234*5fe58019SAttilio Rao DEBUG("calling readdir() before open()"); 1235*5fe58019SAttilio Rao err = fuse_filehandle_open(vp, FUFH_RDONLY, &fufh, NULL, cred); 1236*5fe58019SAttilio Rao freefufh = 1; 1237*5fe58019SAttilio Rao } else { 1238*5fe58019SAttilio Rao err = fuse_filehandle_get(vp, FUFH_RDONLY, &fufh); 1239*5fe58019SAttilio Rao } 1240*5fe58019SAttilio Rao if (err) { 1241*5fe58019SAttilio Rao return (err); 1242*5fe58019SAttilio Rao } 1243*5fe58019SAttilio Rao #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1) 1244*5fe58019SAttilio Rao fiov_init(&cookediov, DIRCOOKEDSIZE); 1245*5fe58019SAttilio Rao 1246*5fe58019SAttilio Rao err = fuse_internal_readdir(vp, uio, fufh, &cookediov); 1247*5fe58019SAttilio Rao 1248*5fe58019SAttilio Rao fiov_teardown(&cookediov); 1249*5fe58019SAttilio Rao if (freefufh) { 1250*5fe58019SAttilio Rao fuse_filehandle_close(vp, FUFH_RDONLY, NULL, cred); 1251*5fe58019SAttilio Rao } 1252*5fe58019SAttilio Rao return err; 1253*5fe58019SAttilio Rao } 1254*5fe58019SAttilio Rao 1255*5fe58019SAttilio Rao /* 1256*5fe58019SAttilio Rao struct vnop_readlink_args { 1257*5fe58019SAttilio Rao struct vnode *a_vp; 1258*5fe58019SAttilio Rao struct uio *a_uio; 1259*5fe58019SAttilio Rao struct ucred *a_cred; 1260*5fe58019SAttilio Rao }; 1261*5fe58019SAttilio Rao */ 1262*5fe58019SAttilio Rao static int 1263*5fe58019SAttilio Rao fuse_vnop_readlink(struct vop_readlink_args *ap) 1264*5fe58019SAttilio Rao { 1265*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1266*5fe58019SAttilio Rao struct uio *uio = ap->a_uio; 1267*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 1268*5fe58019SAttilio Rao 1269*5fe58019SAttilio Rao struct fuse_dispatcher fdi; 1270*5fe58019SAttilio Rao int err; 1271*5fe58019SAttilio Rao 1272*5fe58019SAttilio Rao DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); 1273*5fe58019SAttilio Rao 1274*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 1275*5fe58019SAttilio Rao return ENXIO; 1276*5fe58019SAttilio Rao } 1277*5fe58019SAttilio Rao if (!vnode_islnk(vp)) { 1278*5fe58019SAttilio Rao return EINVAL; 1279*5fe58019SAttilio Rao } 1280*5fe58019SAttilio Rao fdisp_init(&fdi, 0); 1281*5fe58019SAttilio Rao err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred); 1282*5fe58019SAttilio Rao if (err) { 1283*5fe58019SAttilio Rao goto out; 1284*5fe58019SAttilio Rao } 1285*5fe58019SAttilio Rao if (((char *)fdi.answ)[0] == '/' && 1286*5fe58019SAttilio Rao fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) { 1287*5fe58019SAttilio Rao char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname; 1288*5fe58019SAttilio Rao 1289*5fe58019SAttilio Rao err = uiomove(mpth, strlen(mpth), uio); 1290*5fe58019SAttilio Rao } 1291*5fe58019SAttilio Rao if (!err) { 1292*5fe58019SAttilio Rao err = uiomove(fdi.answ, fdi.iosize, uio); 1293*5fe58019SAttilio Rao } 1294*5fe58019SAttilio Rao out: 1295*5fe58019SAttilio Rao fdisp_destroy(&fdi); 1296*5fe58019SAttilio Rao return err; 1297*5fe58019SAttilio Rao } 1298*5fe58019SAttilio Rao 1299*5fe58019SAttilio Rao /* 1300*5fe58019SAttilio Rao struct vnop_reclaim_args { 1301*5fe58019SAttilio Rao struct vnode *a_vp; 1302*5fe58019SAttilio Rao struct thread *a_td; 1303*5fe58019SAttilio Rao }; 1304*5fe58019SAttilio Rao */ 1305*5fe58019SAttilio Rao static int 1306*5fe58019SAttilio Rao fuse_vnop_reclaim(struct vop_reclaim_args *ap) 1307*5fe58019SAttilio Rao { 1308*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1309*5fe58019SAttilio Rao struct thread *td = ap->a_td; 1310*5fe58019SAttilio Rao 1311*5fe58019SAttilio Rao struct fuse_vnode_data *fvdat = VTOFUD(vp); 1312*5fe58019SAttilio Rao struct fuse_filehandle *fufh = NULL; 1313*5fe58019SAttilio Rao 1314*5fe58019SAttilio Rao int type; 1315*5fe58019SAttilio Rao 1316*5fe58019SAttilio Rao if (!fvdat) { 1317*5fe58019SAttilio Rao panic("FUSE: no vnode data during recycling"); 1318*5fe58019SAttilio Rao } 1319*5fe58019SAttilio Rao DEBUG("inode=%ju\n", (uintmax_t)VTOI(vp)); 1320*5fe58019SAttilio Rao 1321*5fe58019SAttilio Rao for (type = 0; type < FUFH_MAXTYPE; type++) { 1322*5fe58019SAttilio Rao fufh = &(fvdat->fufh[type]); 1323*5fe58019SAttilio Rao if (FUFH_IS_VALID(fufh)) { 1324*5fe58019SAttilio Rao printf("FUSE: vnode being reclaimed but fufh (type=%d) is valid", 1325*5fe58019SAttilio Rao type); 1326*5fe58019SAttilio Rao fuse_filehandle_close(vp, type, td, NULL); 1327*5fe58019SAttilio Rao } 1328*5fe58019SAttilio Rao } 1329*5fe58019SAttilio Rao 1330*5fe58019SAttilio Rao if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) { 1331*5fe58019SAttilio Rao fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp), 1332*5fe58019SAttilio Rao fvdat->nlookup); 1333*5fe58019SAttilio Rao } 1334*5fe58019SAttilio Rao fuse_vnode_setparent(vp, NULL); 1335*5fe58019SAttilio Rao cache_purge(vp); 1336*5fe58019SAttilio Rao vfs_hash_remove(vp); 1337*5fe58019SAttilio Rao vnode_destroy_vobject(vp); 1338*5fe58019SAttilio Rao fuse_vnode_destroy(vp); 1339*5fe58019SAttilio Rao 1340*5fe58019SAttilio Rao return 0; 1341*5fe58019SAttilio Rao } 1342*5fe58019SAttilio Rao 1343*5fe58019SAttilio Rao /* 1344*5fe58019SAttilio Rao struct vnop_remove_args { 1345*5fe58019SAttilio Rao struct vnode *a_dvp; 1346*5fe58019SAttilio Rao struct vnode *a_vp; 1347*5fe58019SAttilio Rao struct componentname *a_cnp; 1348*5fe58019SAttilio Rao }; 1349*5fe58019SAttilio Rao */ 1350*5fe58019SAttilio Rao static int 1351*5fe58019SAttilio Rao fuse_vnop_remove(struct vop_remove_args *ap) 1352*5fe58019SAttilio Rao { 1353*5fe58019SAttilio Rao struct vnode *dvp = ap->a_dvp; 1354*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1355*5fe58019SAttilio Rao struct componentname *cnp = ap->a_cnp; 1356*5fe58019SAttilio Rao 1357*5fe58019SAttilio Rao int err; 1358*5fe58019SAttilio Rao 1359*5fe58019SAttilio Rao DEBUG2G("inode=%ju name=%*s\n", 1360*5fe58019SAttilio Rao (uintmax_t)VTOI(vp), (int)cnp->cn_namelen, cnp->cn_nameptr); 1361*5fe58019SAttilio Rao 1362*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 1363*5fe58019SAttilio Rao return ENXIO; 1364*5fe58019SAttilio Rao } 1365*5fe58019SAttilio Rao if (vnode_isdir(vp)) { 1366*5fe58019SAttilio Rao return EPERM; 1367*5fe58019SAttilio Rao } 1368*5fe58019SAttilio Rao cache_purge(vp); 1369*5fe58019SAttilio Rao 1370*5fe58019SAttilio Rao err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK); 1371*5fe58019SAttilio Rao 1372*5fe58019SAttilio Rao if (err == 0) { 1373*5fe58019SAttilio Rao fuse_internal_vnode_disappear(vp); 1374*5fe58019SAttilio Rao fuse_invalidate_attr(dvp); 1375*5fe58019SAttilio Rao } 1376*5fe58019SAttilio Rao return err; 1377*5fe58019SAttilio Rao } 1378*5fe58019SAttilio Rao 1379*5fe58019SAttilio Rao /* 1380*5fe58019SAttilio Rao struct vnop_rename_args { 1381*5fe58019SAttilio Rao struct vnode *a_fdvp; 1382*5fe58019SAttilio Rao struct vnode *a_fvp; 1383*5fe58019SAttilio Rao struct componentname *a_fcnp; 1384*5fe58019SAttilio Rao struct vnode *a_tdvp; 1385*5fe58019SAttilio Rao struct vnode *a_tvp; 1386*5fe58019SAttilio Rao struct componentname *a_tcnp; 1387*5fe58019SAttilio Rao }; 1388*5fe58019SAttilio Rao */ 1389*5fe58019SAttilio Rao static int 1390*5fe58019SAttilio Rao fuse_vnop_rename(struct vop_rename_args *ap) 1391*5fe58019SAttilio Rao { 1392*5fe58019SAttilio Rao struct vnode *fdvp = ap->a_fdvp; 1393*5fe58019SAttilio Rao struct vnode *fvp = ap->a_fvp; 1394*5fe58019SAttilio Rao struct componentname *fcnp = ap->a_fcnp; 1395*5fe58019SAttilio Rao struct vnode *tdvp = ap->a_tdvp; 1396*5fe58019SAttilio Rao struct vnode *tvp = ap->a_tvp; 1397*5fe58019SAttilio Rao struct componentname *tcnp = ap->a_tcnp; 1398*5fe58019SAttilio Rao struct fuse_data *data; 1399*5fe58019SAttilio Rao 1400*5fe58019SAttilio Rao int err = 0; 1401*5fe58019SAttilio Rao 1402*5fe58019SAttilio Rao DEBUG2G("from: inode=%ju name=%*s -> to: inode=%ju name=%*s\n", 1403*5fe58019SAttilio Rao (uintmax_t)VTOI(fvp), (int)fcnp->cn_namelen, fcnp->cn_nameptr, 1404*5fe58019SAttilio Rao (uintmax_t)(tvp == NULL ? -1 : VTOI(tvp)), 1405*5fe58019SAttilio Rao (int)tcnp->cn_namelen, tcnp->cn_nameptr); 1406*5fe58019SAttilio Rao 1407*5fe58019SAttilio Rao if (fuse_isdeadfs(fdvp)) { 1408*5fe58019SAttilio Rao return ENXIO; 1409*5fe58019SAttilio Rao } 1410*5fe58019SAttilio Rao if (fvp->v_mount != tdvp->v_mount || 1411*5fe58019SAttilio Rao (tvp && fvp->v_mount != tvp->v_mount)) { 1412*5fe58019SAttilio Rao DEBUG("cross-device rename: %s -> %s\n", 1413*5fe58019SAttilio Rao fcnp->cn_nameptr, (tcnp != NULL ? tcnp->cn_nameptr : "(NULL)")); 1414*5fe58019SAttilio Rao err = EXDEV; 1415*5fe58019SAttilio Rao goto out; 1416*5fe58019SAttilio Rao } 1417*5fe58019SAttilio Rao cache_purge(fvp); 1418*5fe58019SAttilio Rao 1419*5fe58019SAttilio Rao /* 1420*5fe58019SAttilio Rao * FUSE library is expected to check if target directory is not 1421*5fe58019SAttilio Rao * under the source directory in the file system tree. 1422*5fe58019SAttilio Rao * Linux performs this check at VFS level. 1423*5fe58019SAttilio Rao */ 1424*5fe58019SAttilio Rao data = fuse_get_mpdata(vnode_mount(tdvp)); 1425*5fe58019SAttilio Rao sx_xlock(&data->rename_lock); 1426*5fe58019SAttilio Rao err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp); 1427*5fe58019SAttilio Rao if (err == 0) { 1428*5fe58019SAttilio Rao fuse_invalidate_attr(fdvp); 1429*5fe58019SAttilio Rao if (tdvp != fdvp) { 1430*5fe58019SAttilio Rao fuse_vnode_setparent(fvp, tdvp); 1431*5fe58019SAttilio Rao fuse_invalidate_attr(tdvp); 1432*5fe58019SAttilio Rao } 1433*5fe58019SAttilio Rao if (tvp != NULL) 1434*5fe58019SAttilio Rao fuse_vnode_setparent(tvp, NULL); 1435*5fe58019SAttilio Rao } 1436*5fe58019SAttilio Rao sx_unlock(&data->rename_lock); 1437*5fe58019SAttilio Rao 1438*5fe58019SAttilio Rao if (tvp != NULL && tvp != fvp) { 1439*5fe58019SAttilio Rao cache_purge(tvp); 1440*5fe58019SAttilio Rao } 1441*5fe58019SAttilio Rao if (vnode_isdir(fvp)) { 1442*5fe58019SAttilio Rao if ((tvp != NULL) && vnode_isdir(tvp)) { 1443*5fe58019SAttilio Rao cache_purge(tdvp); 1444*5fe58019SAttilio Rao } 1445*5fe58019SAttilio Rao cache_purge(fdvp); 1446*5fe58019SAttilio Rao } 1447*5fe58019SAttilio Rao out: 1448*5fe58019SAttilio Rao if (tdvp == tvp) { 1449*5fe58019SAttilio Rao vrele(tdvp); 1450*5fe58019SAttilio Rao } else { 1451*5fe58019SAttilio Rao vput(tdvp); 1452*5fe58019SAttilio Rao } 1453*5fe58019SAttilio Rao if (tvp != NULL) { 1454*5fe58019SAttilio Rao vput(tvp); 1455*5fe58019SAttilio Rao } 1456*5fe58019SAttilio Rao vrele(fdvp); 1457*5fe58019SAttilio Rao vrele(fvp); 1458*5fe58019SAttilio Rao 1459*5fe58019SAttilio Rao return err; 1460*5fe58019SAttilio Rao } 1461*5fe58019SAttilio Rao 1462*5fe58019SAttilio Rao /* 1463*5fe58019SAttilio Rao struct vnop_rmdir_args { 1464*5fe58019SAttilio Rao struct vnode *a_dvp; 1465*5fe58019SAttilio Rao struct vnode *a_vp; 1466*5fe58019SAttilio Rao struct componentname *a_cnp; 1467*5fe58019SAttilio Rao } *ap; 1468*5fe58019SAttilio Rao */ 1469*5fe58019SAttilio Rao static int 1470*5fe58019SAttilio Rao fuse_vnop_rmdir(struct vop_rmdir_args *ap) 1471*5fe58019SAttilio Rao { 1472*5fe58019SAttilio Rao struct vnode *dvp = ap->a_dvp; 1473*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1474*5fe58019SAttilio Rao 1475*5fe58019SAttilio Rao int err; 1476*5fe58019SAttilio Rao 1477*5fe58019SAttilio Rao DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); 1478*5fe58019SAttilio Rao 1479*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 1480*5fe58019SAttilio Rao return ENXIO; 1481*5fe58019SAttilio Rao } 1482*5fe58019SAttilio Rao if (VTOFUD(vp) == VTOFUD(dvp)) { 1483*5fe58019SAttilio Rao return EINVAL; 1484*5fe58019SAttilio Rao } 1485*5fe58019SAttilio Rao err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR); 1486*5fe58019SAttilio Rao 1487*5fe58019SAttilio Rao if (err == 0) { 1488*5fe58019SAttilio Rao fuse_internal_vnode_disappear(vp); 1489*5fe58019SAttilio Rao fuse_invalidate_attr(dvp); 1490*5fe58019SAttilio Rao } 1491*5fe58019SAttilio Rao return err; 1492*5fe58019SAttilio Rao } 1493*5fe58019SAttilio Rao 1494*5fe58019SAttilio Rao /* 1495*5fe58019SAttilio Rao struct vnop_setattr_args { 1496*5fe58019SAttilio Rao struct vnode *a_vp; 1497*5fe58019SAttilio Rao struct vattr *a_vap; 1498*5fe58019SAttilio Rao struct ucred *a_cred; 1499*5fe58019SAttilio Rao struct thread *a_td; 1500*5fe58019SAttilio Rao }; 1501*5fe58019SAttilio Rao */ 1502*5fe58019SAttilio Rao static int 1503*5fe58019SAttilio Rao fuse_vnop_setattr(struct vop_setattr_args *ap) 1504*5fe58019SAttilio Rao { 1505*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1506*5fe58019SAttilio Rao struct vattr *vap = ap->a_vap; 1507*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 1508*5fe58019SAttilio Rao struct thread *td = curthread; 1509*5fe58019SAttilio Rao 1510*5fe58019SAttilio Rao struct fuse_dispatcher fdi; 1511*5fe58019SAttilio Rao struct fuse_setattr_in *fsai; 1512*5fe58019SAttilio Rao struct fuse_access_param facp; 1513*5fe58019SAttilio Rao 1514*5fe58019SAttilio Rao int err = 0; 1515*5fe58019SAttilio Rao enum vtype vtyp; 1516*5fe58019SAttilio Rao int sizechanged = 0; 1517*5fe58019SAttilio Rao uint64_t newsize = 0; 1518*5fe58019SAttilio Rao 1519*5fe58019SAttilio Rao DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); 1520*5fe58019SAttilio Rao 1521*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 1522*5fe58019SAttilio Rao return ENXIO; 1523*5fe58019SAttilio Rao } 1524*5fe58019SAttilio Rao fdisp_init(&fdi, sizeof(*fsai)); 1525*5fe58019SAttilio Rao fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred); 1526*5fe58019SAttilio Rao fsai = fdi.indata; 1527*5fe58019SAttilio Rao fsai->valid = 0; 1528*5fe58019SAttilio Rao 1529*5fe58019SAttilio Rao bzero(&facp, sizeof(facp)); 1530*5fe58019SAttilio Rao 1531*5fe58019SAttilio Rao facp.xuid = vap->va_uid; 1532*5fe58019SAttilio Rao facp.xgid = vap->va_gid; 1533*5fe58019SAttilio Rao 1534*5fe58019SAttilio Rao if (vap->va_uid != (uid_t)VNOVAL) { 1535*5fe58019SAttilio Rao facp.facc_flags |= FACCESS_CHOWN; 1536*5fe58019SAttilio Rao fsai->uid = vap->va_uid; 1537*5fe58019SAttilio Rao fsai->valid |= FATTR_UID; 1538*5fe58019SAttilio Rao } 1539*5fe58019SAttilio Rao if (vap->va_gid != (gid_t)VNOVAL) { 1540*5fe58019SAttilio Rao facp.facc_flags |= FACCESS_CHOWN; 1541*5fe58019SAttilio Rao fsai->gid = vap->va_gid; 1542*5fe58019SAttilio Rao fsai->valid |= FATTR_GID; 1543*5fe58019SAttilio Rao } 1544*5fe58019SAttilio Rao if (vap->va_size != VNOVAL) { 1545*5fe58019SAttilio Rao 1546*5fe58019SAttilio Rao struct fuse_filehandle *fufh = NULL; 1547*5fe58019SAttilio Rao 1548*5fe58019SAttilio Rao /*Truncate to a new value. */ 1549*5fe58019SAttilio Rao fsai->size = vap->va_size; 1550*5fe58019SAttilio Rao sizechanged = 1; 1551*5fe58019SAttilio Rao newsize = vap->va_size; 1552*5fe58019SAttilio Rao fsai->valid |= FATTR_SIZE; 1553*5fe58019SAttilio Rao 1554*5fe58019SAttilio Rao fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh); 1555*5fe58019SAttilio Rao if (fufh) { 1556*5fe58019SAttilio Rao fsai->fh = fufh->fh_id; 1557*5fe58019SAttilio Rao fsai->valid |= FATTR_FH; 1558*5fe58019SAttilio Rao } 1559*5fe58019SAttilio Rao } 1560*5fe58019SAttilio Rao if (vap->va_atime.tv_sec != VNOVAL) { 1561*5fe58019SAttilio Rao fsai->atime = vap->va_atime.tv_sec; 1562*5fe58019SAttilio Rao fsai->atimensec = vap->va_atime.tv_nsec; 1563*5fe58019SAttilio Rao fsai->valid |= FATTR_ATIME; 1564*5fe58019SAttilio Rao } 1565*5fe58019SAttilio Rao if (vap->va_mtime.tv_sec != VNOVAL) { 1566*5fe58019SAttilio Rao fsai->mtime = vap->va_mtime.tv_sec; 1567*5fe58019SAttilio Rao fsai->mtimensec = vap->va_mtime.tv_nsec; 1568*5fe58019SAttilio Rao fsai->valid |= FATTR_MTIME; 1569*5fe58019SAttilio Rao } 1570*5fe58019SAttilio Rao if (vap->va_mode != (mode_t)VNOVAL) { 1571*5fe58019SAttilio Rao fsai->mode = vap->va_mode & ALLPERMS; 1572*5fe58019SAttilio Rao fsai->valid |= FATTR_MODE; 1573*5fe58019SAttilio Rao } 1574*5fe58019SAttilio Rao if (!fsai->valid) { 1575*5fe58019SAttilio Rao goto out; 1576*5fe58019SAttilio Rao } 1577*5fe58019SAttilio Rao vtyp = vnode_vtype(vp); 1578*5fe58019SAttilio Rao 1579*5fe58019SAttilio Rao if (fsai->valid & FATTR_SIZE && vtyp == VDIR) { 1580*5fe58019SAttilio Rao err = EISDIR; 1581*5fe58019SAttilio Rao goto out; 1582*5fe58019SAttilio Rao } 1583*5fe58019SAttilio Rao if (vfs_isrdonly(vnode_mount(vp)) && (fsai->valid & ~FATTR_SIZE || vtyp == VREG)) { 1584*5fe58019SAttilio Rao err = EROFS; 1585*5fe58019SAttilio Rao goto out; 1586*5fe58019SAttilio Rao } 1587*5fe58019SAttilio Rao if (fsai->valid & ~FATTR_SIZE) { 1588*5fe58019SAttilio Rao /*err = fuse_internal_access(vp, VADMIN, context, &facp); */ 1589*5fe58019SAttilio Rao /*XXX */ 1590*5fe58019SAttilio Rao err = 0; 1591*5fe58019SAttilio Rao } 1592*5fe58019SAttilio Rao facp.facc_flags &= ~FACCESS_XQUERIES; 1593*5fe58019SAttilio Rao 1594*5fe58019SAttilio Rao if (err && !(fsai->valid & ~(FATTR_ATIME | FATTR_MTIME)) && 1595*5fe58019SAttilio Rao vap->va_vaflags & VA_UTIMES_NULL) { 1596*5fe58019SAttilio Rao err = fuse_internal_access(vp, VWRITE, &facp, td, cred); 1597*5fe58019SAttilio Rao } 1598*5fe58019SAttilio Rao if (err) { 1599*5fe58019SAttilio Rao fuse_invalidate_attr(vp); 1600*5fe58019SAttilio Rao goto out; 1601*5fe58019SAttilio Rao } 1602*5fe58019SAttilio Rao if ((err = fdisp_wait_answ(&fdi))) { 1603*5fe58019SAttilio Rao fuse_invalidate_attr(vp); 1604*5fe58019SAttilio Rao goto out; 1605*5fe58019SAttilio Rao } 1606*5fe58019SAttilio Rao vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode); 1607*5fe58019SAttilio Rao 1608*5fe58019SAttilio Rao if (vnode_vtype(vp) != vtyp) { 1609*5fe58019SAttilio Rao if (vnode_vtype(vp) == VNON && vtyp != VNON) { 1610*5fe58019SAttilio Rao debug_printf("FUSE: Dang! vnode_vtype is VNON and vtype isn't.\n"); 1611*5fe58019SAttilio Rao } else { 1612*5fe58019SAttilio Rao /* 1613*5fe58019SAttilio Rao * STALE vnode, ditch 1614*5fe58019SAttilio Rao * 1615*5fe58019SAttilio Rao * The vnode has changed its type "behind our back". There's 1616*5fe58019SAttilio Rao * nothing really we can do, so let us just force an internal 1617*5fe58019SAttilio Rao * revocation and tell the caller to try again, if interested. 1618*5fe58019SAttilio Rao */ 1619*5fe58019SAttilio Rao fuse_internal_vnode_disappear(vp); 1620*5fe58019SAttilio Rao err = EAGAIN; 1621*5fe58019SAttilio Rao } 1622*5fe58019SAttilio Rao } 1623*5fe58019SAttilio Rao if (!err && !sizechanged) { 1624*5fe58019SAttilio Rao cache_attrs(vp, (struct fuse_attr_out *)fdi.answ); 1625*5fe58019SAttilio Rao } 1626*5fe58019SAttilio Rao out: 1627*5fe58019SAttilio Rao fdisp_destroy(&fdi); 1628*5fe58019SAttilio Rao if (!err && sizechanged) { 1629*5fe58019SAttilio Rao fuse_invalidate_attr(vp); 1630*5fe58019SAttilio Rao fuse_vnode_setsize(vp, cred, newsize); 1631*5fe58019SAttilio Rao VTOFUD(vp)->flag &= ~FN_SIZECHANGE; 1632*5fe58019SAttilio Rao } 1633*5fe58019SAttilio Rao return err; 1634*5fe58019SAttilio Rao } 1635*5fe58019SAttilio Rao 1636*5fe58019SAttilio Rao /* 1637*5fe58019SAttilio Rao struct vnop_strategy_args { 1638*5fe58019SAttilio Rao struct vnode *a_vp; 1639*5fe58019SAttilio Rao struct buf *a_bp; 1640*5fe58019SAttilio Rao }; 1641*5fe58019SAttilio Rao */ 1642*5fe58019SAttilio Rao static int 1643*5fe58019SAttilio Rao fuse_vnop_strategy(struct vop_strategy_args *ap) 1644*5fe58019SAttilio Rao { 1645*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1646*5fe58019SAttilio Rao struct buf *bp = ap->a_bp; 1647*5fe58019SAttilio Rao 1648*5fe58019SAttilio Rao fuse_trace_printf_vnop(); 1649*5fe58019SAttilio Rao 1650*5fe58019SAttilio Rao if (!vp || fuse_isdeadfs(vp)) { 1651*5fe58019SAttilio Rao bp->b_ioflags |= BIO_ERROR; 1652*5fe58019SAttilio Rao bp->b_error = ENXIO; 1653*5fe58019SAttilio Rao bufdone(bp); 1654*5fe58019SAttilio Rao return ENXIO; 1655*5fe58019SAttilio Rao } 1656*5fe58019SAttilio Rao if (bp->b_iocmd == BIO_WRITE) 1657*5fe58019SAttilio Rao fuse_vnode_refreshsize(vp, NOCRED); 1658*5fe58019SAttilio Rao 1659*5fe58019SAttilio Rao (void)fuse_io_strategy(vp, bp); 1660*5fe58019SAttilio Rao 1661*5fe58019SAttilio Rao /* 1662*5fe58019SAttilio Rao * This is a dangerous function. If returns error, that might mean a 1663*5fe58019SAttilio Rao * panic. We prefer pretty much anything over being forced to panic 1664*5fe58019SAttilio Rao * by a malicious daemon (a demon?). So we just return 0 anyway. You 1665*5fe58019SAttilio Rao * should never mind this: this function has its own error 1666*5fe58019SAttilio Rao * propagation mechanism via the argument buffer, so 1667*5fe58019SAttilio Rao * not-that-melodramatic residents of the call chain still will be 1668*5fe58019SAttilio Rao * able to know what to do. 1669*5fe58019SAttilio Rao */ 1670*5fe58019SAttilio Rao return 0; 1671*5fe58019SAttilio Rao } 1672*5fe58019SAttilio Rao 1673*5fe58019SAttilio Rao 1674*5fe58019SAttilio Rao /* 1675*5fe58019SAttilio Rao struct vnop_symlink_args { 1676*5fe58019SAttilio Rao struct vnode *a_dvp; 1677*5fe58019SAttilio Rao struct vnode **a_vpp; 1678*5fe58019SAttilio Rao struct componentname *a_cnp; 1679*5fe58019SAttilio Rao struct vattr *a_vap; 1680*5fe58019SAttilio Rao char *a_target; 1681*5fe58019SAttilio Rao }; 1682*5fe58019SAttilio Rao */ 1683*5fe58019SAttilio Rao static int 1684*5fe58019SAttilio Rao fuse_vnop_symlink(struct vop_symlink_args *ap) 1685*5fe58019SAttilio Rao { 1686*5fe58019SAttilio Rao struct vnode *dvp = ap->a_dvp; 1687*5fe58019SAttilio Rao struct vnode **vpp = ap->a_vpp; 1688*5fe58019SAttilio Rao struct componentname *cnp = ap->a_cnp; 1689*5fe58019SAttilio Rao char *target = ap->a_target; 1690*5fe58019SAttilio Rao 1691*5fe58019SAttilio Rao struct fuse_dispatcher fdi; 1692*5fe58019SAttilio Rao 1693*5fe58019SAttilio Rao int err; 1694*5fe58019SAttilio Rao size_t len; 1695*5fe58019SAttilio Rao 1696*5fe58019SAttilio Rao DEBUG2G("inode=%ju name=%*s\n", 1697*5fe58019SAttilio Rao (uintmax_t)VTOI(dvp), (int)cnp->cn_namelen, cnp->cn_nameptr); 1698*5fe58019SAttilio Rao 1699*5fe58019SAttilio Rao if (fuse_isdeadfs(dvp)) { 1700*5fe58019SAttilio Rao return ENXIO; 1701*5fe58019SAttilio Rao } 1702*5fe58019SAttilio Rao /* 1703*5fe58019SAttilio Rao * Unlike the other creator type calls, here we have to create a message 1704*5fe58019SAttilio Rao * where the name of the new entry comes first, and the data describing 1705*5fe58019SAttilio Rao * the entry comes second. 1706*5fe58019SAttilio Rao * Hence we can't rely on our handy fuse_internal_newentry() routine, 1707*5fe58019SAttilio Rao * but put together the message manually and just call the core part. 1708*5fe58019SAttilio Rao */ 1709*5fe58019SAttilio Rao 1710*5fe58019SAttilio Rao len = strlen(target) + 1; 1711*5fe58019SAttilio Rao fdisp_init(&fdi, len + cnp->cn_namelen + 1); 1712*5fe58019SAttilio Rao fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL); 1713*5fe58019SAttilio Rao 1714*5fe58019SAttilio Rao memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 1715*5fe58019SAttilio Rao ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 1716*5fe58019SAttilio Rao memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len); 1717*5fe58019SAttilio Rao 1718*5fe58019SAttilio Rao err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi); 1719*5fe58019SAttilio Rao fdisp_destroy(&fdi); 1720*5fe58019SAttilio Rao 1721*5fe58019SAttilio Rao if (err == 0) { 1722*5fe58019SAttilio Rao fuse_invalidate_attr(dvp); 1723*5fe58019SAttilio Rao } 1724*5fe58019SAttilio Rao return err; 1725*5fe58019SAttilio Rao } 1726*5fe58019SAttilio Rao 1727*5fe58019SAttilio Rao /* 1728*5fe58019SAttilio Rao struct vnop_write_args { 1729*5fe58019SAttilio Rao struct vnode *a_vp; 1730*5fe58019SAttilio Rao struct uio *a_uio; 1731*5fe58019SAttilio Rao int a_ioflag; 1732*5fe58019SAttilio Rao struct ucred *a_cred; 1733*5fe58019SAttilio Rao }; 1734*5fe58019SAttilio Rao */ 1735*5fe58019SAttilio Rao static int 1736*5fe58019SAttilio Rao fuse_vnop_write(struct vop_write_args *ap) 1737*5fe58019SAttilio Rao { 1738*5fe58019SAttilio Rao struct vnode *vp = ap->a_vp; 1739*5fe58019SAttilio Rao struct uio *uio = ap->a_uio; 1740*5fe58019SAttilio Rao int ioflag = ap->a_ioflag; 1741*5fe58019SAttilio Rao struct ucred *cred = ap->a_cred; 1742*5fe58019SAttilio Rao 1743*5fe58019SAttilio Rao fuse_trace_printf_vnop(); 1744*5fe58019SAttilio Rao 1745*5fe58019SAttilio Rao if (fuse_isdeadfs(vp)) { 1746*5fe58019SAttilio Rao return ENXIO; 1747*5fe58019SAttilio Rao } 1748*5fe58019SAttilio Rao fuse_vnode_refreshsize(vp, cred); 1749*5fe58019SAttilio Rao 1750*5fe58019SAttilio Rao return fuse_io_dispatch(vp, uio, ioflag, cred); 1751*5fe58019SAttilio Rao } 1752*5fe58019SAttilio Rao 1753*5fe58019SAttilio Rao /* 1754*5fe58019SAttilio Rao struct vnop_getpages_args { 1755*5fe58019SAttilio Rao struct vnode *a_vp; 1756*5fe58019SAttilio Rao vm_page_t *a_m; 1757*5fe58019SAttilio Rao int a_count; 1758*5fe58019SAttilio Rao int a_reqpage; 1759*5fe58019SAttilio Rao vm_ooffset_t a_offset; 1760*5fe58019SAttilio Rao }; 1761*5fe58019SAttilio Rao */ 1762*5fe58019SAttilio Rao static int 1763*5fe58019SAttilio Rao fuse_vnop_getpages(struct vop_getpages_args *ap) 1764*5fe58019SAttilio Rao { 1765*5fe58019SAttilio Rao int i, error, nextoff, size, toff, count, npages; 1766*5fe58019SAttilio Rao struct uio uio; 1767*5fe58019SAttilio Rao struct iovec iov; 1768*5fe58019SAttilio Rao vm_offset_t kva; 1769*5fe58019SAttilio Rao struct buf *bp; 1770*5fe58019SAttilio Rao struct vnode *vp; 1771*5fe58019SAttilio Rao struct thread *td; 1772*5fe58019SAttilio Rao struct ucred *cred; 1773*5fe58019SAttilio Rao vm_page_t *pages; 1774*5fe58019SAttilio Rao 1775*5fe58019SAttilio Rao DEBUG2G("heh\n"); 1776*5fe58019SAttilio Rao 1777*5fe58019SAttilio Rao vp = ap->a_vp; 1778*5fe58019SAttilio Rao KASSERT(vp->v_object, ("objectless vp passed to getpages")); 1779*5fe58019SAttilio Rao td = curthread; /* XXX */ 1780*5fe58019SAttilio Rao cred = curthread->td_ucred; /* XXX */ 1781*5fe58019SAttilio Rao pages = ap->a_m; 1782*5fe58019SAttilio Rao count = ap->a_count; 1783*5fe58019SAttilio Rao 1784*5fe58019SAttilio Rao if (!fsess_opt_mmap(vnode_mount(vp))) { 1785*5fe58019SAttilio Rao DEBUG("called on non-cacheable vnode??\n"); 1786*5fe58019SAttilio Rao return (VM_PAGER_ERROR); 1787*5fe58019SAttilio Rao } 1788*5fe58019SAttilio Rao npages = btoc(count); 1789*5fe58019SAttilio Rao 1790*5fe58019SAttilio Rao /* 1791*5fe58019SAttilio Rao * If the requested page is partially valid, just return it and 1792*5fe58019SAttilio Rao * allow the pager to zero-out the blanks. Partially valid pages 1793*5fe58019SAttilio Rao * can only occur at the file EOF. 1794*5fe58019SAttilio Rao */ 1795*5fe58019SAttilio Rao 1796*5fe58019SAttilio Rao VM_OBJECT_LOCK(vp->v_object); 1797*5fe58019SAttilio Rao fuse_vm_page_lock_queues(); 1798*5fe58019SAttilio Rao if (pages[ap->a_reqpage]->valid != 0) { 1799*5fe58019SAttilio Rao for (i = 0; i < npages; ++i) { 1800*5fe58019SAttilio Rao if (i != ap->a_reqpage) { 1801*5fe58019SAttilio Rao fuse_vm_page_lock(pages[i]); 1802*5fe58019SAttilio Rao vm_page_free(pages[i]); 1803*5fe58019SAttilio Rao fuse_vm_page_unlock(pages[i]); 1804*5fe58019SAttilio Rao } 1805*5fe58019SAttilio Rao } 1806*5fe58019SAttilio Rao fuse_vm_page_unlock_queues(); 1807*5fe58019SAttilio Rao VM_OBJECT_UNLOCK(vp->v_object); 1808*5fe58019SAttilio Rao return 0; 1809*5fe58019SAttilio Rao } 1810*5fe58019SAttilio Rao fuse_vm_page_unlock_queues(); 1811*5fe58019SAttilio Rao VM_OBJECT_UNLOCK(vp->v_object); 1812*5fe58019SAttilio Rao 1813*5fe58019SAttilio Rao /* 1814*5fe58019SAttilio Rao * We use only the kva address for the buffer, but this is extremely 1815*5fe58019SAttilio Rao * convienient and fast. 1816*5fe58019SAttilio Rao */ 1817*5fe58019SAttilio Rao bp = getpbuf(&fuse_pbuf_freecnt); 1818*5fe58019SAttilio Rao 1819*5fe58019SAttilio Rao kva = (vm_offset_t)bp->b_data; 1820*5fe58019SAttilio Rao pmap_qenter(kva, pages, npages); 1821*5fe58019SAttilio Rao PCPU_INC(cnt.v_vnodein); 1822*5fe58019SAttilio Rao PCPU_ADD(cnt.v_vnodepgsin, npages); 1823*5fe58019SAttilio Rao 1824*5fe58019SAttilio Rao iov.iov_base = (caddr_t)kva; 1825*5fe58019SAttilio Rao iov.iov_len = count; 1826*5fe58019SAttilio Rao uio.uio_iov = &iov; 1827*5fe58019SAttilio Rao uio.uio_iovcnt = 1; 1828*5fe58019SAttilio Rao uio.uio_offset = IDX_TO_OFF(pages[0]->pindex); 1829*5fe58019SAttilio Rao uio.uio_resid = count; 1830*5fe58019SAttilio Rao uio.uio_segflg = UIO_SYSSPACE; 1831*5fe58019SAttilio Rao uio.uio_rw = UIO_READ; 1832*5fe58019SAttilio Rao uio.uio_td = td; 1833*5fe58019SAttilio Rao 1834*5fe58019SAttilio Rao error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred); 1835*5fe58019SAttilio Rao pmap_qremove(kva, npages); 1836*5fe58019SAttilio Rao 1837*5fe58019SAttilio Rao relpbuf(bp, &fuse_pbuf_freecnt); 1838*5fe58019SAttilio Rao 1839*5fe58019SAttilio Rao if (error && (uio.uio_resid == count)) { 1840*5fe58019SAttilio Rao DEBUG("error %d\n", error); 1841*5fe58019SAttilio Rao VM_OBJECT_LOCK(vp->v_object); 1842*5fe58019SAttilio Rao fuse_vm_page_lock_queues(); 1843*5fe58019SAttilio Rao for (i = 0; i < npages; ++i) { 1844*5fe58019SAttilio Rao if (i != ap->a_reqpage) { 1845*5fe58019SAttilio Rao fuse_vm_page_lock(pages[i]); 1846*5fe58019SAttilio Rao vm_page_free(pages[i]); 1847*5fe58019SAttilio Rao fuse_vm_page_unlock(pages[i]); 1848*5fe58019SAttilio Rao } 1849*5fe58019SAttilio Rao } 1850*5fe58019SAttilio Rao fuse_vm_page_unlock_queues(); 1851*5fe58019SAttilio Rao VM_OBJECT_UNLOCK(vp->v_object); 1852*5fe58019SAttilio Rao return VM_PAGER_ERROR; 1853*5fe58019SAttilio Rao } 1854*5fe58019SAttilio Rao /* 1855*5fe58019SAttilio Rao * Calculate the number of bytes read and validate only that number 1856*5fe58019SAttilio Rao * of bytes. Note that due to pending writes, size may be 0. This 1857*5fe58019SAttilio Rao * does not mean that the remaining data is invalid! 1858*5fe58019SAttilio Rao */ 1859*5fe58019SAttilio Rao 1860*5fe58019SAttilio Rao size = count - uio.uio_resid; 1861*5fe58019SAttilio Rao VM_OBJECT_LOCK(vp->v_object); 1862*5fe58019SAttilio Rao fuse_vm_page_lock_queues(); 1863*5fe58019SAttilio Rao for (i = 0, toff = 0; i < npages; i++, toff = nextoff) { 1864*5fe58019SAttilio Rao vm_page_t m; 1865*5fe58019SAttilio Rao 1866*5fe58019SAttilio Rao nextoff = toff + PAGE_SIZE; 1867*5fe58019SAttilio Rao m = pages[i]; 1868*5fe58019SAttilio Rao 1869*5fe58019SAttilio Rao if (nextoff <= size) { 1870*5fe58019SAttilio Rao /* 1871*5fe58019SAttilio Rao * Read operation filled an entire page 1872*5fe58019SAttilio Rao */ 1873*5fe58019SAttilio Rao m->valid = VM_PAGE_BITS_ALL; 1874*5fe58019SAttilio Rao KASSERT(m->dirty == 0, 1875*5fe58019SAttilio Rao ("fuse_getpages: page %p is dirty", m)); 1876*5fe58019SAttilio Rao } else if (size > toff) { 1877*5fe58019SAttilio Rao /* 1878*5fe58019SAttilio Rao * Read operation filled a partial page. 1879*5fe58019SAttilio Rao */ 1880*5fe58019SAttilio Rao m->valid = 0; 1881*5fe58019SAttilio Rao vm_page_set_valid_range(m, 0, size - toff); 1882*5fe58019SAttilio Rao KASSERT(m->dirty == 0, 1883*5fe58019SAttilio Rao ("fuse_getpages: page %p is dirty", m)); 1884*5fe58019SAttilio Rao } else { 1885*5fe58019SAttilio Rao /* 1886*5fe58019SAttilio Rao * Read operation was short. If no error occured 1887*5fe58019SAttilio Rao * we may have hit a zero-fill section. We simply 1888*5fe58019SAttilio Rao * leave valid set to 0. 1889*5fe58019SAttilio Rao */ 1890*5fe58019SAttilio Rao ; 1891*5fe58019SAttilio Rao } 1892*5fe58019SAttilio Rao if (i != ap->a_reqpage) { 1893*5fe58019SAttilio Rao /* 1894*5fe58019SAttilio Rao * Whether or not to leave the page activated is up in 1895*5fe58019SAttilio Rao * the air, but we should put the page on a page queue 1896*5fe58019SAttilio Rao * somewhere (it already is in the object). Result: 1897*5fe58019SAttilio Rao * It appears that emperical results show that 1898*5fe58019SAttilio Rao * deactivating pages is best. 1899*5fe58019SAttilio Rao */ 1900*5fe58019SAttilio Rao 1901*5fe58019SAttilio Rao /* 1902*5fe58019SAttilio Rao * Just in case someone was asking for this page we 1903*5fe58019SAttilio Rao * now tell them that it is ok to use. 1904*5fe58019SAttilio Rao */ 1905*5fe58019SAttilio Rao if (!error) { 1906*5fe58019SAttilio Rao if (m->oflags & VPO_WANTED) { 1907*5fe58019SAttilio Rao fuse_vm_page_lock(m); 1908*5fe58019SAttilio Rao vm_page_activate(m); 1909*5fe58019SAttilio Rao fuse_vm_page_unlock(m); 1910*5fe58019SAttilio Rao } else { 1911*5fe58019SAttilio Rao fuse_vm_page_lock(m); 1912*5fe58019SAttilio Rao vm_page_deactivate(m); 1913*5fe58019SAttilio Rao fuse_vm_page_unlock(m); 1914*5fe58019SAttilio Rao } 1915*5fe58019SAttilio Rao vm_page_wakeup(m); 1916*5fe58019SAttilio Rao } else { 1917*5fe58019SAttilio Rao fuse_vm_page_lock(m); 1918*5fe58019SAttilio Rao vm_page_free(m); 1919*5fe58019SAttilio Rao fuse_vm_page_unlock(m); 1920*5fe58019SAttilio Rao } 1921*5fe58019SAttilio Rao } 1922*5fe58019SAttilio Rao } 1923*5fe58019SAttilio Rao fuse_vm_page_unlock_queues(); 1924*5fe58019SAttilio Rao VM_OBJECT_UNLOCK(vp->v_object); 1925*5fe58019SAttilio Rao return 0; 1926*5fe58019SAttilio Rao } 1927*5fe58019SAttilio Rao 1928*5fe58019SAttilio Rao /* 1929*5fe58019SAttilio Rao struct vnop_putpages_args { 1930*5fe58019SAttilio Rao struct vnode *a_vp; 1931*5fe58019SAttilio Rao vm_page_t *a_m; 1932*5fe58019SAttilio Rao int a_count; 1933*5fe58019SAttilio Rao int a_sync; 1934*5fe58019SAttilio Rao int *a_rtvals; 1935*5fe58019SAttilio Rao vm_ooffset_t a_offset; 1936*5fe58019SAttilio Rao }; 1937*5fe58019SAttilio Rao */ 1938*5fe58019SAttilio Rao static int 1939*5fe58019SAttilio Rao fuse_vnop_putpages(struct vop_putpages_args *ap) 1940*5fe58019SAttilio Rao { 1941*5fe58019SAttilio Rao struct uio uio; 1942*5fe58019SAttilio Rao struct iovec iov; 1943*5fe58019SAttilio Rao vm_offset_t kva; 1944*5fe58019SAttilio Rao struct buf *bp; 1945*5fe58019SAttilio Rao int i, error, npages, count; 1946*5fe58019SAttilio Rao off_t offset; 1947*5fe58019SAttilio Rao int *rtvals; 1948*5fe58019SAttilio Rao struct vnode *vp; 1949*5fe58019SAttilio Rao struct thread *td; 1950*5fe58019SAttilio Rao struct ucred *cred; 1951*5fe58019SAttilio Rao vm_page_t *pages; 1952*5fe58019SAttilio Rao vm_ooffset_t fsize; 1953*5fe58019SAttilio Rao 1954*5fe58019SAttilio Rao DEBUG2G("heh\n"); 1955*5fe58019SAttilio Rao 1956*5fe58019SAttilio Rao vp = ap->a_vp; 1957*5fe58019SAttilio Rao KASSERT(vp->v_object, ("objectless vp passed to putpages")); 1958*5fe58019SAttilio Rao fsize = vp->v_object->un_pager.vnp.vnp_size; 1959*5fe58019SAttilio Rao td = curthread; /* XXX */ 1960*5fe58019SAttilio Rao cred = curthread->td_ucred; /* XXX */ 1961*5fe58019SAttilio Rao pages = ap->a_m; 1962*5fe58019SAttilio Rao count = ap->a_count; 1963*5fe58019SAttilio Rao rtvals = ap->a_rtvals; 1964*5fe58019SAttilio Rao npages = btoc(count); 1965*5fe58019SAttilio Rao offset = IDX_TO_OFF(pages[0]->pindex); 1966*5fe58019SAttilio Rao 1967*5fe58019SAttilio Rao if (!fsess_opt_mmap(vnode_mount(vp))) { 1968*5fe58019SAttilio Rao DEBUG("called on non-cacheable vnode??\n"); 1969*5fe58019SAttilio Rao } 1970*5fe58019SAttilio Rao for (i = 0; i < npages; i++) 1971*5fe58019SAttilio Rao rtvals[i] = VM_PAGER_AGAIN; 1972*5fe58019SAttilio Rao 1973*5fe58019SAttilio Rao /* 1974*5fe58019SAttilio Rao * When putting pages, do not extend file past EOF. 1975*5fe58019SAttilio Rao */ 1976*5fe58019SAttilio Rao 1977*5fe58019SAttilio Rao if (offset + count > fsize) { 1978*5fe58019SAttilio Rao count = fsize - offset; 1979*5fe58019SAttilio Rao if (count < 0) 1980*5fe58019SAttilio Rao count = 0; 1981*5fe58019SAttilio Rao } 1982*5fe58019SAttilio Rao /* 1983*5fe58019SAttilio Rao * We use only the kva address for the buffer, but this is extremely 1984*5fe58019SAttilio Rao * convienient and fast. 1985*5fe58019SAttilio Rao */ 1986*5fe58019SAttilio Rao bp = getpbuf(&fuse_pbuf_freecnt); 1987*5fe58019SAttilio Rao 1988*5fe58019SAttilio Rao kva = (vm_offset_t)bp->b_data; 1989*5fe58019SAttilio Rao pmap_qenter(kva, pages, npages); 1990*5fe58019SAttilio Rao PCPU_INC(cnt.v_vnodeout); 1991*5fe58019SAttilio Rao PCPU_ADD(cnt.v_vnodepgsout, count); 1992*5fe58019SAttilio Rao 1993*5fe58019SAttilio Rao iov.iov_base = (caddr_t)kva; 1994*5fe58019SAttilio Rao iov.iov_len = count; 1995*5fe58019SAttilio Rao uio.uio_iov = &iov; 1996*5fe58019SAttilio Rao uio.uio_iovcnt = 1; 1997*5fe58019SAttilio Rao uio.uio_offset = offset; 1998*5fe58019SAttilio Rao uio.uio_resid = count; 1999*5fe58019SAttilio Rao uio.uio_segflg = UIO_SYSSPACE; 2000*5fe58019SAttilio Rao uio.uio_rw = UIO_WRITE; 2001*5fe58019SAttilio Rao uio.uio_td = td; 2002*5fe58019SAttilio Rao 2003*5fe58019SAttilio Rao error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred); 2004*5fe58019SAttilio Rao 2005*5fe58019SAttilio Rao pmap_qremove(kva, npages); 2006*5fe58019SAttilio Rao relpbuf(bp, &fuse_pbuf_freecnt); 2007*5fe58019SAttilio Rao 2008*5fe58019SAttilio Rao if (!error) { 2009*5fe58019SAttilio Rao int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE; 2010*5fe58019SAttilio Rao 2011*5fe58019SAttilio Rao for (i = 0; i < nwritten; i++) { 2012*5fe58019SAttilio Rao rtvals[i] = VM_PAGER_OK; 2013*5fe58019SAttilio Rao VM_OBJECT_LOCK(pages[i]->object); 2014*5fe58019SAttilio Rao vm_page_undirty(pages[i]); 2015*5fe58019SAttilio Rao VM_OBJECT_UNLOCK(pages[i]->object); 2016*5fe58019SAttilio Rao } 2017*5fe58019SAttilio Rao } 2018*5fe58019SAttilio Rao return rtvals[0]; 2019*5fe58019SAttilio Rao } 2020*5fe58019SAttilio Rao 2021*5fe58019SAttilio Rao /* 2022*5fe58019SAttilio Rao struct vnop_print_args { 2023*5fe58019SAttilio Rao struct vnode *a_vp; 2024*5fe58019SAttilio Rao }; 2025*5fe58019SAttilio Rao */ 2026*5fe58019SAttilio Rao static int 2027*5fe58019SAttilio Rao fuse_vnop_print(struct vop_print_args *ap) 2028*5fe58019SAttilio Rao { 2029*5fe58019SAttilio Rao struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp); 2030*5fe58019SAttilio Rao 2031*5fe58019SAttilio Rao printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n", 2032*5fe58019SAttilio Rao (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid, 2033*5fe58019SAttilio Rao (uintmax_t)fvdat->nlookup, 2034*5fe58019SAttilio Rao fvdat->flag); 2035*5fe58019SAttilio Rao 2036*5fe58019SAttilio Rao return 0; 2037*5fe58019SAttilio Rao } 2038