2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 static MALLOC_DEFINE(M_FUSE_NODE
, "fuse_node", "FUSE node");
32 static struct objcache
*fuse_node_objcache
= NULL
;
33 static struct objcache_malloc_args fuse_node_args
= {
34 sizeof(struct fuse_node
), M_FUSE_NODE
,
38 fuse_node_cmp(struct fuse_node
*p1
, struct fuse_node
*p2
)
40 if (p1
->ino
< p2
->ino
)
42 if (p1
->ino
> p2
->ino
)
47 RB_PROTOTYPE2(fuse_node_tree
, fuse_node
, entry
, fuse_node_cmp
, uint64_t);
48 RB_GENERATE2(fuse_node_tree
, fuse_node
, node_entry
, fuse_node_cmp
,
52 fuse_node_new(struct fuse_mount
*fmp
, uint64_t ino
, enum vtype vtyp
,
53 struct fuse_node
**fnpp
)
55 struct fuse_node
*fnp
;
57 fnp
= objcache_get(fuse_node_objcache
, M_WAITOK
);
58 bzero(fnp
, sizeof(*fnp
));
62 mtx_init(&fnp
->node_lock
, "fuse_node_lock");
71 if (RB_INSERT(fuse_node_tree
, &fmp
->node_head
, fnp
)) {
72 panic("fuse_node_new: cannot insert %p\n", fnp
);
79 fuse_node_free(struct fuse_mount
*fmp
, struct fuse_node
*fnp
)
81 fuse_dbg("free ino=%ju\n", fnp
->ino
);
83 mtx_lock(&fmp
->ino_lock
);
84 RB_REMOVE(fuse_node_tree
, &fmp
->node_head
, fnp
);
85 mtx_unlock(&fmp
->ino_lock
);
87 objcache_put(fuse_node_objcache
, fnp
);
91 * Allocate or find the fuse node for the specified inode number and assign
95 fuse_alloc_node(struct fuse_mount
*fmp
, struct fuse_node
*dfnp
,
96 uint64_t ino
, enum vtype vtyp
, struct vnode
**vpp
)
98 struct fuse_node
*fnp
;
102 KKASSERT(dfnp
->type
== VDIR
);
103 if (vtyp
== VBLK
|| vtyp
== VCHR
|| vtyp
== VFIFO
)
106 mtx_lock(&fmp
->ino_lock
);
107 fnp
= RB_LOOKUP(fuse_node_tree
, &fmp
->node_head
, ino
);
109 fuse_node_new(fmp
, ino
, vtyp
, &fnp
);
112 mtx_unlock(&fmp
->ino_lock
);
114 error
= fuse_node_vn(fnp
, vpp
);
117 fuse_node_free(fmp
, fnp
);
123 * Returns exclusively locked vp
126 fuse_node_vn(struct fuse_node
*fnp
, struct vnode
**vpp
)
128 struct mount
*mp
= fnp
->fmp
->mp
;
136 if (fnp
->vp
== NULL
&& newvp
== NULL
) {
137 error
= getnewvnode(VT_FUSE
, mp
, &newvp
,
138 VLKTIMEOUT
, LK_CANRECURSE
);
143 mtx_lock(&fnp
->node_lock
);
146 * Check case where vp is already assigned
151 mtx_unlock(&fnp
->node_lock
);
152 error
= vget(vp
, LK_EXCLUSIVE
| LK_RETRY
);
165 newvp
->v_type
= VBAD
;
173 * Assign new vp, release the node lock
176 mtx_unlock(&fnp
->node_lock
);
181 mtx_unlock(&fnp
->node_lock
);
185 * Finish setting up vp (vp is held exclusively + vx)
187 vp
->v_type
= fnp
->type
;
190 switch (vp
->v_type
) {
192 vinitvmio(vp
, fnp
->size
, FUSE_BLKSIZE
, -1);
199 vp
->v_ops
= &mp
->mnt_vn_spec_ops
;
200 addaliasu(vp
, umajor(0), uminor(0)); /* XXX CUSE */
214 vx_downgrade(vp
); /* VX to normal, is still exclusive */
222 fuse_node_truncate(struct fuse_node
*fnp
, size_t oldsize
, size_t newsize
)
224 struct vnode
*vp
= fnp
->vp
;
227 fuse_dbg("ino=%ju update size %ju -> %ju\n",
228 fnp
->ino
, oldsize
, newsize
);
230 fnp
->attr
.va_size
= fnp
->size
= newsize
;
232 if (newsize
< oldsize
)
233 error
= nvtruncbuf(vp
, newsize
, FUSE_BLKSIZE
, -1, 0);
235 error
= nvextendbuf(vp
, oldsize
, newsize
, FUSE_BLKSIZE
,
236 FUSE_BLKSIZE
, -1, -1, 0);
243 fuse_node_objcache
= objcache_create("fuse_node", 0, 0,
245 objcache_malloc_alloc_zero
, objcache_malloc_free
, &fuse_node_args
);
249 fuse_node_cleanup(void)
251 objcache_destroy(fuse_node_objcache
);