1241519Sattilio/*
2241519Sattilio * Copyright (c) 2007-2009 Google Inc. and Amit Singh
3241519Sattilio * All rights reserved.
4241519Sattilio *
5241519Sattilio * Redistribution and use in source and binary forms, with or without
6241519Sattilio * modification, are permitted provided that the following conditions are
7241519Sattilio * met:
8241519Sattilio *
9241519Sattilio * * Redistributions of source code must retain the above copyright
10241519Sattilio *   notice, this list of conditions and the following disclaimer.
11241519Sattilio * * Redistributions in binary form must reproduce the above
12241519Sattilio *   copyright notice, this list of conditions and the following disclaimer
13241519Sattilio *   in the documentation and/or other materials provided with the
14241519Sattilio *   distribution.
15241519Sattilio * * Neither the name of Google Inc. nor the names of its
16241519Sattilio *   contributors may be used to endorse or promote products derived from
17241519Sattilio *   this software without specific prior written permission.
18241519Sattilio *
19241519Sattilio * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20241519Sattilio * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21241519Sattilio * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22241519Sattilio * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23241519Sattilio * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24241519Sattilio * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25241519Sattilio * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26241519Sattilio * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27241519Sattilio * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28241519Sattilio * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29241519Sattilio * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30241519Sattilio *
31241519Sattilio * Copyright (C) 2005 Csaba Henk.
32241519Sattilio * All rights reserved.
33241519Sattilio *
34241519Sattilio * Redistribution and use in source and binary forms, with or without
35241519Sattilio * modification, are permitted provided that the following conditions
36241519Sattilio * are met:
37241519Sattilio * 1. Redistributions of source code must retain the above copyright
38241519Sattilio *    notice, this list of conditions and the following disclaimer.
39241519Sattilio * 2. Redistributions in binary form must reproduce the above copyright
40241519Sattilio *    notice, this list of conditions and the following disclaimer in the
41241519Sattilio *    documentation and/or other materials provided with the distribution.
42241519Sattilio *
43241519Sattilio * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44241519Sattilio * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45241519Sattilio * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46241519Sattilio * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
47241519Sattilio * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48241519Sattilio * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49241519Sattilio * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50241519Sattilio * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51241519Sattilio * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52241519Sattilio * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53241519Sattilio * SUCH DAMAGE.
54241519Sattilio */
55241519Sattilio
56241519Sattilio#include <sys/cdefs.h>
57241519Sattilio__FBSDID("$FreeBSD$");
58241519Sattilio
59241519Sattilio#include <sys/types.h>
60241519Sattilio#include <sys/module.h>
61241519Sattilio#include <sys/systm.h>
62241519Sattilio#include <sys/errno.h>
63241519Sattilio#include <sys/param.h>
64241519Sattilio#include <sys/kernel.h>
65241519Sattilio#include <sys/conf.h>
66241519Sattilio#include <sys/uio.h>
67241519Sattilio#include <sys/malloc.h>
68241519Sattilio#include <sys/queue.h>
69241519Sattilio#include <sys/lock.h>
70241519Sattilio#include <sys/sx.h>
71241519Sattilio#include <sys/mutex.h>
72241519Sattilio#include <sys/proc.h>
73241519Sattilio#include <sys/vnode.h>
74241519Sattilio#include <sys/namei.h>
75241519Sattilio#include <sys/mount.h>
76241519Sattilio#include <sys/sysctl.h>
77241519Sattilio#include <sys/fcntl.h>
78241519Sattilio#include <sys/fnv_hash.h>
79241519Sattilio#include <sys/priv.h>
80241519Sattilio#include <security/mac/mac_framework.h>
81241519Sattilio#include <vm/vm.h>
82241519Sattilio#include <vm/vm_extern.h>
83241519Sattilio
84241519Sattilio#include "fuse.h"
85241519Sattilio#include "fuse_node.h"
86241519Sattilio#include "fuse_internal.h"
87241519Sattilio#include "fuse_io.h"
88241519Sattilio#include "fuse_ipc.h"
89241519Sattilio
90241519Sattilio#define FUSE_DEBUG_MODULE VNOPS
91241519Sattilio#include "fuse_debug.h"
92241519Sattilio
93241519SattilioMALLOC_DEFINE(M_FUSEVN, "fuse_vnode", "fuse vnode private data");
94241519Sattilio
95241519Sattiliostatic int fuse_node_count = 0;
96241519Sattilio
97241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, node_count, CTLFLAG_RD,
98241519Sattilio    &fuse_node_count, 0, "");
99241519Sattilio
100241519Sattilioint	fuse_data_cache_enable = 1;
101241519Sattilio
102241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_enable, CTLFLAG_RW,
103241519Sattilio    &fuse_data_cache_enable, 0, "");
104241519Sattilio
105241519Sattilioint	fuse_data_cache_invalidate = 0;
106241519Sattilio
107241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_invalidate, CTLFLAG_RW,
108241519Sattilio    &fuse_data_cache_invalidate, 0, "");
109241519Sattilio
110241519Sattilioint	fuse_mmap_enable = 1;
111241519Sattilio
112241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, mmap_enable, CTLFLAG_RW,
113241519Sattilio    &fuse_mmap_enable, 0, "");
114241519Sattilio
115241519Sattilioint	fuse_refresh_size = 0;
116241519Sattilio
117241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, refresh_size, CTLFLAG_RW,
118241519Sattilio    &fuse_refresh_size, 0, "");
119241519Sattilio
120241519Sattilioint	fuse_sync_resize = 1;
121241519Sattilio
122241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, sync_resize, CTLFLAG_RW,
123241519Sattilio    &fuse_sync_resize, 0, "");
124241519Sattilio
125241519Sattilioint	fuse_fix_broken_io = 0;
126241519Sattilio
127241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, fix_broken_io, CTLFLAG_RW,
128241519Sattilio    &fuse_fix_broken_io, 0, "");
129241519Sattilio
130241519Sattiliostatic void
131241519Sattiliofuse_vnode_init(struct vnode *vp, struct fuse_vnode_data *fvdat,
132241519Sattilio    uint64_t nodeid, enum vtype vtyp)
133241519Sattilio{
134241519Sattilio	int i;
135241519Sattilio
136241519Sattilio	fvdat->nid = nodeid;
137241519Sattilio	if (nodeid == FUSE_ROOT_ID) {
138241519Sattilio		vp->v_vflag |= VV_ROOT;
139241519Sattilio	}
140241519Sattilio	vp->v_type = vtyp;
141241519Sattilio	vp->v_data = fvdat;
142241519Sattilio
143241519Sattilio	for (i = 0; i < FUFH_MAXTYPE; i++)
144241519Sattilio		fvdat->fufh[i].fh_type = FUFH_INVALID;
145241519Sattilio
146241519Sattilio	atomic_add_acq_int(&fuse_node_count, 1);
147241519Sattilio}
148241519Sattilio
149241519Sattiliovoid
150241519Sattiliofuse_vnode_destroy(struct vnode *vp)
151241519Sattilio{
152241519Sattilio	struct fuse_vnode_data *fvdat = vp->v_data;
153241519Sattilio
154241519Sattilio	vp->v_data = NULL;
155241519Sattilio	free(fvdat, M_FUSEVN);
156241519Sattilio
157241519Sattilio	atomic_subtract_acq_int(&fuse_node_count, 1);
158241519Sattilio}
159241519Sattilio
160241519Sattiliostatic int
161241519Sattiliofuse_vnode_cmp(struct vnode *vp, void *nidp)
162241519Sattilio{
163241519Sattilio	return (VTOI(vp) != *((uint64_t *)nidp));
164241519Sattilio}
165241519Sattilio
166241519Sattiliostatic uint32_t __inline
167241519Sattiliofuse_vnode_hash(uint64_t id)
168241519Sattilio{
169241519Sattilio	return (fnv_32_buf(&id, sizeof(id), FNV1_32_INIT));
170241519Sattilio}
171241519Sattilio
172241519Sattiliostatic int
173241519Sattiliofuse_vnode_alloc(struct mount *mp,
174241519Sattilio    struct thread *td,
175241519Sattilio    uint64_t nodeid,
176241519Sattilio    enum vtype vtyp,
177241519Sattilio    struct vnode **vpp)
178241519Sattilio{
179241519Sattilio	struct fuse_vnode_data *fvdat;
180241519Sattilio	struct vnode *vp2;
181241519Sattilio	int err = 0;
182241519Sattilio
183241521Sattilio	FS_DEBUG("been asked for vno #%ju\n", (uintmax_t)nodeid);
184241519Sattilio
185241519Sattilio	if (vtyp == VNON) {
186241519Sattilio		return EINVAL;
187241519Sattilio	}
188241519Sattilio	*vpp = NULL;
189241519Sattilio	err = vfs_hash_get(mp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE, td, vpp,
190241519Sattilio	    fuse_vnode_cmp, &nodeid);
191241519Sattilio	if (err)
192241519Sattilio		return (err);
193241519Sattilio
194241519Sattilio	if (*vpp) {
195241519Sattilio		MPASS((*vpp)->v_type == vtyp && (*vpp)->v_data != NULL);
196241521Sattilio		FS_DEBUG("vnode taken from hash\n");
197241519Sattilio		return (0);
198241519Sattilio	}
199241519Sattilio	fvdat = malloc(sizeof(*fvdat), M_FUSEVN, M_WAITOK | M_ZERO);
200241519Sattilio	err = getnewvnode("fuse", mp, &fuse_vnops, vpp);
201241519Sattilio	if (err) {
202241519Sattilio		free(fvdat, M_FUSEVN);
203241519Sattilio		return (err);
204241519Sattilio	}
205241519Sattilio	lockmgr((*vpp)->v_vnlock, LK_EXCLUSIVE, NULL);
206241519Sattilio	fuse_vnode_init(*vpp, fvdat, nodeid, vtyp);
207241519Sattilio	err = insmntque(*vpp, mp);
208241519Sattilio	ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc");
209241519Sattilio	if (err) {
210241519Sattilio		free(fvdat, M_FUSEVN);
211241519Sattilio		*vpp = NULL;
212241519Sattilio		return (err);
213241519Sattilio	}
214241519Sattilio	err = vfs_hash_insert(*vpp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE,
215241519Sattilio	    td, &vp2, fuse_vnode_cmp, &nodeid);
216241519Sattilio	if (err)
217241519Sattilio		return (err);
218241519Sattilio	if (vp2 != NULL) {
219241519Sattilio		*vpp = vp2;
220241519Sattilio		return (0);
221241519Sattilio	}
222241519Sattilio
223241519Sattilio	ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc");
224241519Sattilio
225241519Sattilio	return (0);
226241519Sattilio}
227241519Sattilio
228241519Sattilioint
229241519Sattiliofuse_vnode_get(struct mount *mp,
230241519Sattilio    uint64_t nodeid,
231241519Sattilio    struct vnode *dvp,
232241519Sattilio    struct vnode **vpp,
233241519Sattilio    struct componentname *cnp,
234241519Sattilio    enum vtype vtyp)
235241519Sattilio{
236241519Sattilio	struct thread *td = (cnp != NULL ? cnp->cn_thread : curthread);
237241519Sattilio	int err = 0;
238241519Sattilio
239241519Sattilio	debug_printf("dvp=%p\n", dvp);
240241519Sattilio
241241519Sattilio	err = fuse_vnode_alloc(mp, td, nodeid, vtyp, vpp);
242241519Sattilio	if (err) {
243241519Sattilio		return err;
244241519Sattilio	}
245241519Sattilio	if (dvp != NULL) {
246241519Sattilio		MPASS((cnp->cn_flags & ISDOTDOT) == 0);
247241519Sattilio		MPASS(!(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.'));
248241519Sattilio		fuse_vnode_setparent(*vpp, dvp);
249241519Sattilio	}
250241519Sattilio	if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0) {
251241519Sattilio		ASSERT_VOP_LOCKED(*vpp, "fuse_vnode_get");
252241519Sattilio		ASSERT_VOP_LOCKED(dvp, "fuse_vnode_get");
253241519Sattilio		cache_enter(dvp, *vpp, cnp);
254241519Sattilio	}
255241519Sattilio
256241519Sattilio	/*
257241519Sattilio	 * In userland, libfuse uses cached lookups for dot and dotdot entries,
258241519Sattilio	 * thus it does not really bump the nlookup counter for forget.
259241519Sattilio	 * Follow the same semantic and avoid tu bump it in order to keep
260241519Sattilio	 * nlookup counters consistent.
261241519Sattilio	 */
262241519Sattilio	if (cnp == NULL || ((cnp->cn_flags & ISDOTDOT) == 0 &&
263241519Sattilio	    (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.')))
264241519Sattilio		VTOFUD(*vpp)->nlookup++;
265241519Sattilio
266241519Sattilio	return 0;
267241519Sattilio}
268241519Sattilio
269241519Sattiliovoid
270241519Sattiliofuse_vnode_open(struct vnode *vp, int32_t fuse_open_flags, struct thread *td)
271241519Sattilio{
272241519Sattilio	/*
273241519Sattilio         * Funcation is called for every vnode open.
274241519Sattilio         * Merge fuse_open_flags it may be 0
275241519Sattilio         *
276282960Strasz         * XXXIP: Handle FOPEN_KEEP_CACHE
277241519Sattilio         */
278282960Strasz        /*
279282960Strasz	  * Ideally speaking, direct io should be enabled on
280282960Strasz         * fd's but do not see of any way of providing that
281282960Strasz         * this implementation.
282241519Sattilio
283282960Strasz         * Also cannot think of a reason why would two
284282960Strasz         * different fd's on same vnode would like
285282960Strasz         * have DIRECT_IO turned on and off. But linux
286282960Strasz         * based implementation works on an fd not an
287282960Strasz         * inode and provides such a feature.
288282960Strasz         *
289282960Strasz         * XXXIP: Handle fd based DIRECT_IO
290282960Strasz         */
291282960Strasz	if (fuse_open_flags & FOPEN_DIRECT_IO) {
292300977Srmacklem		ASSERT_VOP_ELOCKED(vp, __func__);
293282960Strasz		VTOFUD(vp)->flag |= FN_DIRECTIO;
294300977Srmacklem		fuse_io_invalbuf(vp, td);
295282960Strasz	} else {
296282960Strasz	        VTOFUD(vp)->flag &= ~FN_DIRECTIO;
297282960Strasz	}
298282960Strasz
299241519Sattilio	if (vnode_vtype(vp) == VREG) {
300241519Sattilio		/* XXXIP prevent getattr, by using cached node size */
301241519Sattilio		vnode_create_vobject(vp, 0, td);
302241519Sattilio	}
303241519Sattilio}
304241519Sattilio
305241519Sattilioint
306241519Sattiliofuse_vnode_savesize(struct vnode *vp, struct ucred *cred)
307241519Sattilio{
308241519Sattilio	struct fuse_vnode_data *fvdat = VTOFUD(vp);
309241519Sattilio	struct thread *td = curthread;
310241519Sattilio	struct fuse_filehandle *fufh = NULL;
311241519Sattilio	struct fuse_dispatcher fdi;
312241519Sattilio	struct fuse_setattr_in *fsai;
313241519Sattilio	int err = 0;
314241519Sattilio
315241521Sattilio	FS_DEBUG("inode=%ju size=%ju\n", (uintmax_t)VTOI(vp),
316241519Sattilio	    (uintmax_t)fvdat->filesize);
317241519Sattilio	ASSERT_VOP_ELOCKED(vp, "fuse_io_extend");
318241519Sattilio
319241519Sattilio	if (fuse_isdeadfs(vp)) {
320241519Sattilio		return EBADF;
321241519Sattilio	}
322241519Sattilio	if (vnode_vtype(vp) == VDIR) {
323241519Sattilio		return EISDIR;
324241519Sattilio	}
325241519Sattilio	if (vfs_isrdonly(vnode_mount(vp))) {
326241519Sattilio		return EROFS;
327241519Sattilio	}
328241519Sattilio	if (cred == NULL) {
329241519Sattilio		cred = td->td_ucred;
330241519Sattilio	}
331241519Sattilio	fdisp_init(&fdi, sizeof(*fsai));
332241519Sattilio	fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred);
333241519Sattilio	fsai = fdi.indata;
334241519Sattilio	fsai->valid = 0;
335241519Sattilio
336241519Sattilio	/* Truncate to a new value. */
337241519Sattilio	    fsai->size = fvdat->filesize;
338241519Sattilio	fsai->valid |= FATTR_SIZE;
339241519Sattilio
340241519Sattilio	fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh);
341241519Sattilio	if (fufh) {
342241519Sattilio		fsai->fh = fufh->fh_id;
343241519Sattilio		fsai->valid |= FATTR_FH;
344241519Sattilio	}
345241519Sattilio	err = fdisp_wait_answ(&fdi);
346241519Sattilio	fdisp_destroy(&fdi);
347241519Sattilio	if (err == 0)
348241519Sattilio		fvdat->flag &= ~FN_SIZECHANGE;
349241519Sattilio
350241519Sattilio	return err;
351241519Sattilio}
352241519Sattilio
353241519Sattiliovoid
354241519Sattiliofuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred)
355241519Sattilio{
356241519Sattilio
357241519Sattilio	struct fuse_vnode_data *fvdat = VTOFUD(vp);
358241519Sattilio	struct vattr va;
359241519Sattilio
360241519Sattilio	if ((fvdat->flag & FN_SIZECHANGE) != 0 ||
361242727Sattilio	    (fuse_refresh_size == 0 && fvdat->filesize != 0))
362241519Sattilio		return;
363241519Sattilio
364241519Sattilio	VOP_GETATTR(vp, &va, cred);
365241521Sattilio	FS_DEBUG("refreshed file size: %jd\n", (intmax_t)VTOFUD(vp)->filesize);
366241519Sattilio}
367241519Sattilio
368241519Sattilioint
369241519Sattiliofuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize)
370241519Sattilio{
371241519Sattilio	struct fuse_vnode_data *fvdat = VTOFUD(vp);
372241519Sattilio	off_t oldsize;
373241519Sattilio	int err = 0;
374241519Sattilio
375241521Sattilio	FS_DEBUG("inode=%ju oldsize=%ju newsize=%ju\n",
376241519Sattilio	    (uintmax_t)VTOI(vp), (uintmax_t)fvdat->filesize,
377241519Sattilio	    (uintmax_t)newsize);
378241519Sattilio	ASSERT_VOP_ELOCKED(vp, "fuse_vnode_setsize");
379241519Sattilio
380241519Sattilio	oldsize = fvdat->filesize;
381241519Sattilio	fvdat->filesize = newsize;
382241519Sattilio	fvdat->flag |= FN_SIZECHANGE;
383241519Sattilio
384241519Sattilio	if (newsize < oldsize) {
385241519Sattilio		err = vtruncbuf(vp, cred, newsize, fuse_iosize(vp));
386241519Sattilio	}
387241519Sattilio	vnode_pager_setsize(vp, newsize);
388241519Sattilio	return err;
389241519Sattilio}
390