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