1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2007-2009 Google Inc. and Amit Singh 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following disclaimer 15 * in the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Google Inc. nor the names of its 18 * contributors may be used to endorse or promote products derived from 19 * this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Copyright (C) 2005 Csaba Henk. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58 #include <sys/cdefs.h> 59 __FBSDID("$FreeBSD$"); 60 61 #include <sys/types.h> 62 #include <sys/module.h> 63 #include <sys/systm.h> 64 #include <sys/errno.h> 65 #include <sys/param.h> 66 #include <sys/kernel.h> 67 #include <sys/conf.h> 68 #include <sys/uio.h> 69 #include <sys/malloc.h> 70 #include <sys/queue.h> 71 #include <sys/lock.h> 72 #include <sys/sx.h> 73 #include <sys/mutex.h> 74 #include <sys/proc.h> 75 #include <sys/vnode.h> 76 #include <sys/namei.h> 77 #include <sys/mount.h> 78 #include <sys/sysctl.h> 79 #include <sys/fcntl.h> 80 #include <sys/fnv_hash.h> 81 #include <sys/priv.h> 82 #include <security/mac/mac_framework.h> 83 #include <vm/vm.h> 84 #include <vm/vm_extern.h> 85 86 #include "fuse.h" 87 #include "fuse_node.h" 88 #include "fuse_internal.h" 89 #include "fuse_io.h" 90 #include "fuse_ipc.h" 91 92 #define FUSE_DEBUG_MODULE VNOPS 93 #include "fuse_debug.h" 94 95 MALLOC_DEFINE(M_FUSEVN, "fuse_vnode", "fuse vnode private data"); 96 97 static int fuse_node_count = 0; 98 99 SYSCTL_INT(_vfs_fuse, OID_AUTO, node_count, CTLFLAG_RD, 100 &fuse_node_count, 0, ""); 101 102 int fuse_data_cache_enable = 1; 103 104 SYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_enable, CTLFLAG_RW, 105 &fuse_data_cache_enable, 0, ""); 106 107 int fuse_data_cache_invalidate = 0; 108 109 SYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_invalidate, CTLFLAG_RW, 110 &fuse_data_cache_invalidate, 0, ""); 111 112 int fuse_mmap_enable = 1; 113 114 SYSCTL_INT(_vfs_fuse, OID_AUTO, mmap_enable, CTLFLAG_RW, 115 &fuse_mmap_enable, 0, ""); 116 117 int fuse_refresh_size = 0; 118 119 SYSCTL_INT(_vfs_fuse, OID_AUTO, refresh_size, CTLFLAG_RW, 120 &fuse_refresh_size, 0, ""); 121 122 int fuse_sync_resize = 1; 123 124 SYSCTL_INT(_vfs_fuse, OID_AUTO, sync_resize, CTLFLAG_RW, 125 &fuse_sync_resize, 0, ""); 126 127 int fuse_fix_broken_io = 0; 128 129 SYSCTL_INT(_vfs_fuse, OID_AUTO, fix_broken_io, CTLFLAG_RW, 130 &fuse_fix_broken_io, 0, ""); 131 132 static void 133 fuse_vnode_init(struct vnode *vp, struct fuse_vnode_data *fvdat, 134 uint64_t nodeid, enum vtype vtyp) 135 { 136 int i; 137 138 fvdat->nid = nodeid; 139 if (nodeid == FUSE_ROOT_ID) { 140 vp->v_vflag |= VV_ROOT; 141 } 142 vp->v_type = vtyp; 143 vp->v_data = fvdat; 144 145 for (i = 0; i < FUFH_MAXTYPE; i++) 146 fvdat->fufh[i].fh_type = FUFH_INVALID; 147 148 atomic_add_acq_int(&fuse_node_count, 1); 149 } 150 151 void 152 fuse_vnode_destroy(struct vnode *vp) 153 { 154 struct fuse_vnode_data *fvdat = vp->v_data; 155 156 vp->v_data = NULL; 157 free(fvdat, M_FUSEVN); 158 159 atomic_subtract_acq_int(&fuse_node_count, 1); 160 } 161 162 static int 163 fuse_vnode_cmp(struct vnode *vp, void *nidp) 164 { 165 return (VTOI(vp) != *((uint64_t *)nidp)); 166 } 167 168 static uint32_t __inline 169 fuse_vnode_hash(uint64_t id) 170 { 171 return (fnv_32_buf(&id, sizeof(id), FNV1_32_INIT)); 172 } 173 174 static int 175 fuse_vnode_alloc(struct mount *mp, 176 struct thread *td, 177 uint64_t nodeid, 178 enum vtype vtyp, 179 struct vnode **vpp) 180 { 181 struct fuse_vnode_data *fvdat; 182 struct vnode *vp2; 183 int err = 0; 184 185 FS_DEBUG("been asked for vno #%ju\n", (uintmax_t)nodeid); 186 187 if (vtyp == VNON) { 188 return EINVAL; 189 } 190 *vpp = NULL; 191 err = vfs_hash_get(mp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE, td, vpp, 192 fuse_vnode_cmp, &nodeid); 193 if (err) 194 return (err); 195 196 if (*vpp) { 197 MPASS((*vpp)->v_type == vtyp && (*vpp)->v_data != NULL); 198 FS_DEBUG("vnode taken from hash\n"); 199 return (0); 200 } 201 fvdat = malloc(sizeof(*fvdat), M_FUSEVN, M_WAITOK | M_ZERO); 202 err = getnewvnode("fuse", mp, &fuse_vnops, vpp); 203 if (err) { 204 free(fvdat, M_FUSEVN); 205 return (err); 206 } 207 lockmgr((*vpp)->v_vnlock, LK_EXCLUSIVE, NULL); 208 fuse_vnode_init(*vpp, fvdat, nodeid, vtyp); 209 err = insmntque(*vpp, mp); 210 ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc"); 211 if (err) { 212 free(fvdat, M_FUSEVN); 213 *vpp = NULL; 214 return (err); 215 } 216 err = vfs_hash_insert(*vpp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE, 217 td, &vp2, fuse_vnode_cmp, &nodeid); 218 if (err) 219 return (err); 220 if (vp2 != NULL) { 221 *vpp = vp2; 222 return (0); 223 } 224 225 ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc"); 226 227 return (0); 228 } 229 230 int 231 fuse_vnode_get(struct mount *mp, 232 uint64_t nodeid, 233 struct vnode *dvp, 234 struct vnode **vpp, 235 struct componentname *cnp, 236 enum vtype vtyp) 237 { 238 struct thread *td = (cnp != NULL ? cnp->cn_thread : curthread); 239 int err = 0; 240 241 debug_printf("dvp=%p\n", dvp); 242 243 err = fuse_vnode_alloc(mp, td, nodeid, vtyp, vpp); 244 if (err) { 245 return err; 246 } 247 if (dvp != NULL) { 248 MPASS((cnp->cn_flags & ISDOTDOT) == 0); 249 MPASS(!(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')); 250 fuse_vnode_setparent(*vpp, dvp); 251 } 252 if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0) { 253 ASSERT_VOP_LOCKED(*vpp, "fuse_vnode_get"); 254 ASSERT_VOP_LOCKED(dvp, "fuse_vnode_get"); 255 cache_enter(dvp, *vpp, cnp); 256 } 257 258 /* 259 * In userland, libfuse uses cached lookups for dot and dotdot entries, 260 * thus it does not really bump the nlookup counter for forget. 261 * Follow the same semantic and avoid tu bump it in order to keep 262 * nlookup counters consistent. 263 */ 264 if (cnp == NULL || ((cnp->cn_flags & ISDOTDOT) == 0 && 265 (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.'))) 266 VTOFUD(*vpp)->nlookup++; 267 268 return 0; 269 } 270 271 void 272 fuse_vnode_open(struct vnode *vp, int32_t fuse_open_flags, struct thread *td) 273 { 274 /* 275 * Funcation is called for every vnode open. 276 * Merge fuse_open_flags it may be 0 277 */ 278 /* 279 * Ideally speaking, direct io should be enabled on 280 * fd's but do not see of any way of providing that 281 * this implementation. 282 * 283 * Also cannot think of a reason why would two 284 * different fd's on same vnode would like 285 * have DIRECT_IO turned on and off. But linux 286 * based implementation works on an fd not an 287 * inode and provides such a feature. 288 * 289 * XXXIP: Handle fd based DIRECT_IO 290 */ 291 if (fuse_open_flags & FOPEN_DIRECT_IO) { 292 ASSERT_VOP_ELOCKED(vp, __func__); 293 VTOFUD(vp)->flag |= FN_DIRECTIO; 294 fuse_io_invalbuf(vp, td); 295 } else { 296 if ((fuse_open_flags & FOPEN_KEEP_CACHE) == 0) 297 fuse_io_invalbuf(vp, td); 298 VTOFUD(vp)->flag &= ~FN_DIRECTIO; 299 } 300 301 if (vnode_vtype(vp) == VREG) { 302 /* XXXIP prevent getattr, by using cached node size */ 303 vnode_create_vobject(vp, 0, td); 304 } 305 } 306 307 int 308 fuse_vnode_savesize(struct vnode *vp, struct ucred *cred) 309 { 310 struct fuse_vnode_data *fvdat = VTOFUD(vp); 311 struct thread *td = curthread; 312 struct fuse_filehandle *fufh = NULL; 313 struct fuse_dispatcher fdi; 314 struct fuse_setattr_in *fsai; 315 int err = 0; 316 317 FS_DEBUG("inode=%ju size=%ju\n", (uintmax_t)VTOI(vp), 318 (uintmax_t)fvdat->filesize); 319 ASSERT_VOP_ELOCKED(vp, "fuse_io_extend"); 320 321 if (fuse_isdeadfs(vp)) { 322 return EBADF; 323 } 324 if (vnode_vtype(vp) == VDIR) { 325 return EISDIR; 326 } 327 if (vfs_isrdonly(vnode_mount(vp))) { 328 return EROFS; 329 } 330 if (cred == NULL) { 331 cred = td->td_ucred; 332 } 333 fdisp_init(&fdi, sizeof(*fsai)); 334 fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred); 335 fsai = fdi.indata; 336 fsai->valid = 0; 337 338 /* Truncate to a new value. */ 339 fsai->size = fvdat->filesize; 340 fsai->valid |= FATTR_SIZE; 341 342 fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh); 343 if (fufh) { 344 fsai->fh = fufh->fh_id; 345 fsai->valid |= FATTR_FH; 346 } 347 err = fdisp_wait_answ(&fdi); 348 fdisp_destroy(&fdi); 349 if (err == 0) 350 fvdat->flag &= ~FN_SIZECHANGE; 351 352 return err; 353 } 354 355 void 356 fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred) 357 { 358 359 struct fuse_vnode_data *fvdat = VTOFUD(vp); 360 struct vattr va; 361 362 if ((fvdat->flag & FN_SIZECHANGE) != 0 || 363 (fuse_refresh_size == 0 && fvdat->filesize != 0)) 364 return; 365 366 VOP_GETATTR(vp, &va, cred); 367 FS_DEBUG("refreshed file size: %jd\n", (intmax_t)VTOFUD(vp)->filesize); 368 } 369 370 int 371 fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize) 372 { 373 struct fuse_vnode_data *fvdat = VTOFUD(vp); 374 off_t oldsize; 375 int err = 0; 376 377 FS_DEBUG("inode=%ju oldsize=%ju newsize=%ju\n", 378 (uintmax_t)VTOI(vp), (uintmax_t)fvdat->filesize, 379 (uintmax_t)newsize); 380 ASSERT_VOP_ELOCKED(vp, "fuse_vnode_setsize"); 381 382 oldsize = fvdat->filesize; 383 fvdat->filesize = newsize; 384 fvdat->flag |= FN_SIZECHANGE; 385 386 if (newsize < oldsize) { 387 err = vtruncbuf(vp, cred, newsize, fuse_iosize(vp)); 388 } 389 vnode_pager_setsize(vp, newsize); 390 return err; 391 } 392