xref: /dflybsd-src/sys/vfs/fuse/fuse_node.c (revision 1a8e5e4cf0cfbe16676810f7edca73f98bb9b8f5)
15812c3ccSTomohiro Kusumi /*-
25812c3ccSTomohiro Kusumi  * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
35812c3ccSTomohiro Kusumi  * Copyright (c) 2019 The DragonFly Project
45812c3ccSTomohiro Kusumi  * All rights reserved.
55812c3ccSTomohiro Kusumi  *
65812c3ccSTomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
75812c3ccSTomohiro Kusumi  * modification, are permitted provided that the following conditions
85812c3ccSTomohiro Kusumi  * are met:
95812c3ccSTomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
105812c3ccSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
115812c3ccSTomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
125812c3ccSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in the
135812c3ccSTomohiro Kusumi  *    documentation and/or other materials provided with the distribution.
145812c3ccSTomohiro Kusumi  *
155812c3ccSTomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165812c3ccSTomohiro Kusumi  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175812c3ccSTomohiro Kusumi  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185812c3ccSTomohiro Kusumi  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195812c3ccSTomohiro Kusumi  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205812c3ccSTomohiro Kusumi  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215812c3ccSTomohiro Kusumi  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225812c3ccSTomohiro Kusumi  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235812c3ccSTomohiro Kusumi  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245812c3ccSTomohiro Kusumi  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255812c3ccSTomohiro Kusumi  * SUCH DAMAGE.
265812c3ccSTomohiro Kusumi  */
275812c3ccSTomohiro Kusumi 
285812c3ccSTomohiro Kusumi #include "fuse.h"
295812c3ccSTomohiro Kusumi 
305812c3ccSTomohiro Kusumi static MALLOC_DEFINE(M_FUSE_NODE, "fuse_node", "FUSE node");
315812c3ccSTomohiro Kusumi 
325812c3ccSTomohiro Kusumi static struct objcache *fuse_node_objcache = NULL;
335812c3ccSTomohiro Kusumi static struct objcache_malloc_args fuse_node_args = {
345812c3ccSTomohiro Kusumi 	sizeof(struct fuse_node), M_FUSE_NODE,
355812c3ccSTomohiro Kusumi };
365812c3ccSTomohiro Kusumi 
375812c3ccSTomohiro Kusumi static int
fuse_node_cmp(struct fuse_node * p1,struct fuse_node * p2)38*1a8e5e4cSMatthew Dillon fuse_node_cmp(struct fuse_node *p1, struct fuse_node *p2)
395812c3ccSTomohiro Kusumi {
40*1a8e5e4cSMatthew Dillon 	if (p1->ino < p2->ino)
41*1a8e5e4cSMatthew Dillon 		return -1;
42*1a8e5e4cSMatthew Dillon 	if (p1->ino > p2->ino)
43*1a8e5e4cSMatthew Dillon 		return 1;
44*1a8e5e4cSMatthew Dillon 	return 0;
455812c3ccSTomohiro Kusumi }
465812c3ccSTomohiro Kusumi 
47*1a8e5e4cSMatthew Dillon RB_PROTOTYPE2(fuse_node_tree, fuse_node, entry, fuse_node_cmp, uint64_t);
48*1a8e5e4cSMatthew Dillon RB_GENERATE2(fuse_node_tree, fuse_node, node_entry, fuse_node_cmp,
49*1a8e5e4cSMatthew Dillon 		uint64_t, ino);
505812c3ccSTomohiro Kusumi 
515812c3ccSTomohiro Kusumi void
fuse_node_new(struct fuse_mount * fmp,uint64_t ino,enum vtype vtyp,struct fuse_node ** fnpp)525812c3ccSTomohiro Kusumi fuse_node_new(struct fuse_mount *fmp, uint64_t ino, enum vtype vtyp,
535812c3ccSTomohiro Kusumi 	      struct fuse_node **fnpp)
545812c3ccSTomohiro Kusumi {
555812c3ccSTomohiro Kusumi 	struct fuse_node *fnp;
565812c3ccSTomohiro Kusumi 
575812c3ccSTomohiro Kusumi 	fnp = objcache_get(fuse_node_objcache, M_WAITOK);
585d0d0bafSMatthew Dillon 	bzero(fnp, sizeof(*fnp));
595812c3ccSTomohiro Kusumi 
605812c3ccSTomohiro Kusumi 	fnp->fmp = fmp;
615812c3ccSTomohiro Kusumi 
625812c3ccSTomohiro Kusumi 	mtx_init(&fnp->node_lock, "fuse_node_lock");
635812c3ccSTomohiro Kusumi 
645812c3ccSTomohiro Kusumi 	fnp->ino = ino;
655812c3ccSTomohiro Kusumi 	fnp->type = vtyp;
665812c3ccSTomohiro Kusumi 	fnp->size = 0;
675812c3ccSTomohiro Kusumi 	fnp->nlookup = 0;
685812c3ccSTomohiro Kusumi 	fnp->fh = 0;
695812c3ccSTomohiro Kusumi 	fnp->closed = false;
705812c3ccSTomohiro Kusumi 
71*1a8e5e4cSMatthew Dillon 	if (RB_INSERT(fuse_node_tree, &fmp->node_head, fnp)) {
72*1a8e5e4cSMatthew Dillon 		panic("fuse_node_new: cannot insert %p\n", fnp);
73*1a8e5e4cSMatthew Dillon 	}
74*1a8e5e4cSMatthew Dillon 
755812c3ccSTomohiro Kusumi 	*fnpp = fnp;
765812c3ccSTomohiro Kusumi }
775812c3ccSTomohiro Kusumi 
785812c3ccSTomohiro Kusumi void
fuse_node_free(struct fuse_mount * fmp,struct fuse_node * fnp)79*1a8e5e4cSMatthew Dillon fuse_node_free(struct fuse_mount *fmp, struct fuse_node *fnp)
805812c3ccSTomohiro Kusumi {
815812c3ccSTomohiro Kusumi 	fuse_dbg("free ino=%ju\n", fnp->ino);
825812c3ccSTomohiro Kusumi 
83*1a8e5e4cSMatthew Dillon 	mtx_lock(&fmp->ino_lock);
84*1a8e5e4cSMatthew Dillon 	RB_REMOVE(fuse_node_tree, &fmp->node_head, fnp);
85*1a8e5e4cSMatthew Dillon 	mtx_unlock(&fmp->ino_lock);
865812c3ccSTomohiro Kusumi 
875812c3ccSTomohiro Kusumi 	objcache_put(fuse_node_objcache, fnp);
885812c3ccSTomohiro Kusumi }
895812c3ccSTomohiro Kusumi 
90*1a8e5e4cSMatthew Dillon /*
91*1a8e5e4cSMatthew Dillon  * Allocate or find the fuse node for the specified inode number and assign
92*1a8e5e4cSMatthew Dillon  * its vnode.
93*1a8e5e4cSMatthew Dillon  */
945812c3ccSTomohiro Kusumi int
fuse_alloc_node(struct fuse_mount * fmp,struct fuse_node * dfnp,uint64_t ino,enum vtype vtyp,struct vnode ** vpp)95*1a8e5e4cSMatthew Dillon fuse_alloc_node(struct fuse_mount *fmp, struct fuse_node *dfnp,
96*1a8e5e4cSMatthew Dillon 	        uint64_t ino, enum vtype vtyp, struct vnode **vpp)
975812c3ccSTomohiro Kusumi {
98*1a8e5e4cSMatthew Dillon 	struct fuse_node *fnp;
995812c3ccSTomohiro Kusumi 	int error;
100*1a8e5e4cSMatthew Dillon 	int allocated = 0;
1015812c3ccSTomohiro Kusumi 
1021243142aSTomohiro Kusumi 	KKASSERT(dfnp->type == VDIR);
1035812c3ccSTomohiro Kusumi 	if (vtyp == VBLK || vtyp == VCHR || vtyp == VFIFO)
1045812c3ccSTomohiro Kusumi 		return EINVAL;
1055812c3ccSTomohiro Kusumi 
106*1a8e5e4cSMatthew Dillon 	mtx_lock(&fmp->ino_lock);
107*1a8e5e4cSMatthew Dillon 	fnp = RB_LOOKUP(fuse_node_tree, &fmp->node_head, ino);
108*1a8e5e4cSMatthew Dillon 	if (fnp == NULL) {
109*1a8e5e4cSMatthew Dillon 		fuse_node_new(fmp, ino, vtyp, &fnp);
110*1a8e5e4cSMatthew Dillon 		allocated = 1;
1115d0d0bafSMatthew Dillon 	}
112*1a8e5e4cSMatthew Dillon 	mtx_unlock(&fmp->ino_lock);
1135812c3ccSTomohiro Kusumi 
1145d0d0bafSMatthew Dillon 	error = fuse_node_vn(fnp, vpp);
1155812c3ccSTomohiro Kusumi 	if (error) {
116*1a8e5e4cSMatthew Dillon 		if (allocated)
117*1a8e5e4cSMatthew Dillon 			fuse_node_free(fmp, fnp);
1185d0d0bafSMatthew Dillon 	}
1195812c3ccSTomohiro Kusumi 	return error;
1205812c3ccSTomohiro Kusumi }
1215812c3ccSTomohiro Kusumi 
1225d0d0bafSMatthew Dillon /*
1235d0d0bafSMatthew Dillon  * Returns exclusively locked vp
1245d0d0bafSMatthew Dillon  */
1255812c3ccSTomohiro Kusumi int
fuse_node_vn(struct fuse_node * fnp,struct vnode ** vpp)1265d0d0bafSMatthew Dillon fuse_node_vn(struct fuse_node *fnp, struct vnode **vpp)
1275812c3ccSTomohiro Kusumi {
1285812c3ccSTomohiro Kusumi 	struct mount *mp = fnp->fmp->mp;
1295812c3ccSTomohiro Kusumi 	struct vnode *vp;
1305d0d0bafSMatthew Dillon 	struct vnode *newvp;
1315812c3ccSTomohiro Kusumi 	int error;
1325d0d0bafSMatthew Dillon 
1335d0d0bafSMatthew Dillon 	newvp = NULL;
1345812c3ccSTomohiro Kusumi retry:
1355d0d0bafSMatthew Dillon 	error = 0;
1365d0d0bafSMatthew Dillon 	if (fnp->vp == NULL && newvp == NULL) {
1375d0d0bafSMatthew Dillon 		error = getnewvnode(VT_FUSE, mp, &newvp,
1385d0d0bafSMatthew Dillon 				    VLKTIMEOUT, LK_CANRECURSE);
1395d0d0bafSMatthew Dillon 		if (error)
1405d0d0bafSMatthew Dillon 			return error;
1415d0d0bafSMatthew Dillon 	}
1425d0d0bafSMatthew Dillon 
1435812c3ccSTomohiro Kusumi 	mtx_lock(&fnp->node_lock);
1445d0d0bafSMatthew Dillon 
1455d0d0bafSMatthew Dillon 	/*
1465d0d0bafSMatthew Dillon 	 * Check case where vp is already assigned
1475d0d0bafSMatthew Dillon 	 */
1485812c3ccSTomohiro Kusumi 	vp = fnp->vp;
1495812c3ccSTomohiro Kusumi 	if (vp) {
1505812c3ccSTomohiro Kusumi 		vhold(vp);
1515812c3ccSTomohiro Kusumi 		mtx_unlock(&fnp->node_lock);
1525d0d0bafSMatthew Dillon 		error = vget(vp, LK_EXCLUSIVE | LK_RETRY);
1535812c3ccSTomohiro Kusumi 		vdrop(vp);
1545d0d0bafSMatthew Dillon 
1555d0d0bafSMatthew Dillon 		if (error)
1565d0d0bafSMatthew Dillon 			goto retry;
1575d0d0bafSMatthew Dillon 		if (fnp->vp != vp) {
1585d0d0bafSMatthew Dillon 			vput(vp);
1595812c3ccSTomohiro Kusumi 			goto retry;
1605812c3ccSTomohiro Kusumi 		}
1615d0d0bafSMatthew Dillon 
1625812c3ccSTomohiro Kusumi 		*vpp = vp;
1635d0d0bafSMatthew Dillon 
1645d0d0bafSMatthew Dillon 		if (newvp) {
1655d0d0bafSMatthew Dillon 			newvp->v_type = VBAD;
1665d0d0bafSMatthew Dillon 			vx_put(newvp);
1675d0d0bafSMatthew Dillon 		}
1685d0d0bafSMatthew Dillon 
1695812c3ccSTomohiro Kusumi 		return 0;
1705812c3ccSTomohiro Kusumi 	}
1715812c3ccSTomohiro Kusumi 
1725d0d0bafSMatthew Dillon 	/*
1735d0d0bafSMatthew Dillon 	 * Assign new vp, release the node lock
1745d0d0bafSMatthew Dillon 	 */
1755d0d0bafSMatthew Dillon 	if (newvp == NULL) {
1765d0d0bafSMatthew Dillon 		mtx_unlock(&fnp->node_lock);
1775d0d0bafSMatthew Dillon 		goto retry;
1785d0d0bafSMatthew Dillon 	}
1795d0d0bafSMatthew Dillon 
1805d0d0bafSMatthew Dillon 	fnp->vp = newvp;
1815d0d0bafSMatthew Dillon 	mtx_unlock(&fnp->node_lock);
1825d0d0bafSMatthew Dillon 	vp = newvp;
1835d0d0bafSMatthew Dillon 
1845d0d0bafSMatthew Dillon 	/*
1855d0d0bafSMatthew Dillon 	 * Finish setting up vp (vp is held exclusively + vx)
1865d0d0bafSMatthew Dillon 	 */
1875812c3ccSTomohiro Kusumi 	vp->v_type = fnp->type;
1885812c3ccSTomohiro Kusumi 	vp->v_data = fnp;
1895812c3ccSTomohiro Kusumi 
1905812c3ccSTomohiro Kusumi 	switch (vp->v_type) {
1915812c3ccSTomohiro Kusumi 	case VREG:
1925812c3ccSTomohiro Kusumi 		vinitvmio(vp, fnp->size, FUSE_BLKSIZE, -1);
1935812c3ccSTomohiro Kusumi 		break;
1945812c3ccSTomohiro Kusumi 	case VDIR:
1955812c3ccSTomohiro Kusumi 		break;
1965812c3ccSTomohiro Kusumi 	case VBLK:
1975812c3ccSTomohiro Kusumi 	case VCHR:
1985812c3ccSTomohiro Kusumi 		KKASSERT(0);
1995812c3ccSTomohiro Kusumi 		vp->v_ops = &mp->mnt_vn_spec_ops;
2005812c3ccSTomohiro Kusumi 		addaliasu(vp, umajor(0), uminor(0)); /* XXX CUSE */
2015812c3ccSTomohiro Kusumi 		break;
2025812c3ccSTomohiro Kusumi 	case VLNK:
2035812c3ccSTomohiro Kusumi 		break;
2045812c3ccSTomohiro Kusumi 	case VSOCK:
2055812c3ccSTomohiro Kusumi 		break;
2065812c3ccSTomohiro Kusumi 	case VFIFO:
2075812c3ccSTomohiro Kusumi 		KKASSERT(0);
2085812c3ccSTomohiro Kusumi 	case VDATABASE:
2095812c3ccSTomohiro Kusumi 		break;
2105812c3ccSTomohiro Kusumi 	default:
2115812c3ccSTomohiro Kusumi 		KKASSERT(0);
2125812c3ccSTomohiro Kusumi 	}
2135812c3ccSTomohiro Kusumi 
2145d0d0bafSMatthew Dillon 	vx_downgrade(vp);	/* VX to normal, is still exclusive */
2155d0d0bafSMatthew Dillon 
2165812c3ccSTomohiro Kusumi 	*vpp = vp;
2175812c3ccSTomohiro Kusumi 
2185d0d0bafSMatthew Dillon 	return error;
2195812c3ccSTomohiro Kusumi }
2205812c3ccSTomohiro Kusumi 
2215812c3ccSTomohiro Kusumi int
fuse_node_truncate(struct fuse_node * fnp,size_t oldsize,size_t newsize)2225812c3ccSTomohiro Kusumi fuse_node_truncate(struct fuse_node *fnp, size_t oldsize, size_t newsize)
2235812c3ccSTomohiro Kusumi {
2245812c3ccSTomohiro Kusumi 	struct vnode *vp = fnp->vp;
2255812c3ccSTomohiro Kusumi 	int error;
2265812c3ccSTomohiro Kusumi 
2275812c3ccSTomohiro Kusumi 	fuse_dbg("ino=%ju update size %ju -> %ju\n",
2285812c3ccSTomohiro Kusumi 	    fnp->ino, oldsize, newsize);
2295812c3ccSTomohiro Kusumi 
2305812c3ccSTomohiro Kusumi 	fnp->attr.va_size = fnp->size = newsize;
2315812c3ccSTomohiro Kusumi 
2325812c3ccSTomohiro Kusumi 	if (newsize < oldsize)
2335812c3ccSTomohiro Kusumi 		error = nvtruncbuf(vp, newsize, FUSE_BLKSIZE, -1, 0);
2345812c3ccSTomohiro Kusumi 	else
2355812c3ccSTomohiro Kusumi 		error = nvextendbuf(vp, oldsize, newsize, FUSE_BLKSIZE,
2365812c3ccSTomohiro Kusumi 		    FUSE_BLKSIZE, -1, -1, 0);
2375812c3ccSTomohiro Kusumi 	return error;
2385812c3ccSTomohiro Kusumi }
2395812c3ccSTomohiro Kusumi 
2405812c3ccSTomohiro Kusumi void
fuse_node_init(void)2415812c3ccSTomohiro Kusumi fuse_node_init(void)
2425812c3ccSTomohiro Kusumi {
2435812c3ccSTomohiro Kusumi 	fuse_node_objcache = objcache_create("fuse_node", 0, 0,
2445812c3ccSTomohiro Kusumi 	    NULL, NULL, NULL,
2455812c3ccSTomohiro Kusumi 	    objcache_malloc_alloc_zero, objcache_malloc_free, &fuse_node_args);
2465812c3ccSTomohiro Kusumi }
2475812c3ccSTomohiro Kusumi 
2485812c3ccSTomohiro Kusumi void
fuse_node_cleanup(void)2495812c3ccSTomohiro Kusumi fuse_node_cleanup(void)
2505812c3ccSTomohiro Kusumi {
2515812c3ccSTomohiro Kusumi 	objcache_destroy(fuse_node_objcache);
2525812c3ccSTomohiro Kusumi }
253