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,
37 static MALLOC_DEFINE(M_FUSE_DENT, "fuse_dent", "FUSE dent");
39 static struct objcache *fuse_dent_objcache = NULL;
40 static struct objcache_malloc_args fuse_dent_args = {
41 sizeof(struct fuse_dent), M_FUSE_DENT,
45 fuse_dent_cmp(struct fuse_dent *p1, struct fuse_dent *p2)
47 return strcmp(p1->name, p2->name);
50 RB_PROTOTYPE_STATIC(fuse_dent_tree, fuse_dent, entry, fuse_dent_cmp);
51 RB_GENERATE_STATIC(fuse_dent_tree, fuse_dent, dent_entry, fuse_dent_cmp);
54 fuse_node_new(struct fuse_mount *fmp, uint64_t ino, enum vtype vtyp,
55 struct fuse_node **fnpp)
57 struct fuse_node *fnp;
59 fnp = objcache_get(fuse_node_objcache, M_WAITOK);
62 memset(fnp, 0, sizeof(*fnp));
67 mtx_init(&fnp->node_lock, "fuse_node_lock");
68 RB_INIT(&fnp->dent_head);
83 fuse_node_free(struct fuse_node *fnp)
85 struct fuse_node *dfnp = fnp->pfnp;
86 struct fuse_dent *fep;
88 fuse_dbg("free ino=%ju\n", fnp->ino);
91 KKASSERT(dfnp->type == VDIR);
92 mtx_lock(&dfnp->node_lock);
93 RB_FOREACH(fep, fuse_dent_tree, &dfnp->dent_head) {
94 if (fep->fnp == fnp) {
95 fuse_dent_detach(dfnp, fep);
100 mtx_unlock(&dfnp->node_lock);
103 mtx_lock(&fnp->node_lock);
104 if (fnp->type == VDIR) {
105 while ((fep = RB_ROOT(&fnp->dent_head))) {
106 fuse_dent_detach(fnp, fep);
110 fnp->vp->v_data = NULL;
112 fnp->nlink = -123; /* debug */
113 mtx_unlock(&fnp->node_lock);
115 objcache_put(fuse_node_objcache, fnp);
119 fuse_dent_new(struct fuse_node *fnp, const char *name, int namelen,
120 struct fuse_dent **fepp)
122 struct fuse_dent *fep;
124 fep = objcache_get(fuse_dent_objcache, M_WAITOK);
128 fep->name = kstrndup(name, namelen, M_TEMP);
130 fep->name = kstrdup(name, M_TEMP);
134 KASSERT(fnp->nlink >= 0, ("new ino=%ju nlink=%d dent=\"%s\"",
135 fnp->ino, fnp->nlink, fep->name));
136 KKASSERT(fnp->nlink < LINK_MAX);
144 fuse_dent_free(struct fuse_dent *fep)
146 struct fuse_node *fnp = fep->fnp;
148 fuse_dbg("free dent=\"%s\"\n", fep->name);
150 KASSERT(fnp->nlink > 0, ("free ino=%ju nlink=%d dent=\"%s\"",
151 fnp->ino, fnp->nlink, fep->name));
154 kfree(fep->name, M_TEMP);
158 KKASSERT(fnp->nlink <= LINK_MAX);
162 objcache_put(fuse_dent_objcache, fep);
166 fuse_dent_attach(struct fuse_node *dfnp, struct fuse_dent *fep)
169 KKASSERT(dfnp->type == VDIR);
170 KKASSERT(mtx_islocked_ex(&dfnp->node_lock));
172 RB_INSERT(fuse_dent_tree, &dfnp->dent_head, fep);
176 fuse_dent_detach(struct fuse_node *dfnp, struct fuse_dent *fep)
179 KKASSERT(dfnp->type == VDIR);
180 KKASSERT(mtx_islocked_ex(&dfnp->node_lock));
182 RB_REMOVE(fuse_dent_tree, &dfnp->dent_head, fep);
186 fuse_dent_find(struct fuse_node *dfnp, const char *name, int namelen,
187 struct fuse_dent **fepp)
189 struct fuse_dent *fep, find;
193 find.name = kstrndup(name, namelen, M_TEMP);
195 find.name = kstrdup(name, M_TEMP);
198 fep = RB_FIND(fuse_dent_tree, &dfnp->dent_head, &find);
205 fuse_dbg("dent=\"%s\" not found\n", find.name);
208 kfree(find.name, M_TEMP);
214 fuse_alloc_node(struct fuse_node *dfnp, uint64_t ino, const char *name,
215 int namelen, enum vtype vtyp, struct vnode **vpp)
217 struct fuse_node *fnp = NULL;
218 struct fuse_dent *fep = NULL;
221 KKASSERT(dfnp->type == VDIR);
222 if (vtyp == VBLK || vtyp == VCHR || vtyp == VFIFO)
225 mtx_lock(&dfnp->node_lock);
226 error = fuse_dent_find(dfnp, name, namelen, &fep);
228 mtx_unlock(&dfnp->node_lock);
230 } else if (error == ENOENT) {
231 fuse_node_new(dfnp->fmp, ino, vtyp, &fnp);
232 mtx_lock(&fnp->node_lock);
234 fuse_dent_new(fnp, name, namelen, &fep);
235 fuse_dent_attach(dfnp, fep);
236 mtx_unlock(&fnp->node_lock);
239 mtx_unlock(&dfnp->node_lock);
241 error = fuse_node_vn(fnp, LK_EXCLUSIVE, vpp);
243 mtx_lock(&dfnp->node_lock);
244 fuse_dent_detach(dfnp, fep);
246 mtx_unlock(&dfnp->node_lock);
252 fuse_dbg("fnp=%p ino=%ju dent=\"%s\"\n", fnp, fnp->ino, fep->name);
258 fuse_node_vn(struct fuse_node *fnp, int flags, struct vnode **vpp)
260 struct mount *mp = fnp->fmp->mp;
264 mtx_lock(&fnp->node_lock);
268 mtx_unlock(&fnp->node_lock);
270 error = vget(vp, flags | LK_RETRY);
279 mtx_unlock(&fnp->node_lock);
281 error = getnewvnode(VT_FUSE, mp, &vp, VLKTIMEOUT, LK_CANRECURSE);
284 vp->v_type = fnp->type;
287 switch (vp->v_type) {
289 vinitvmio(vp, fnp->size, FUSE_BLKSIZE, -1);
296 vp->v_ops = &mp->mnt_vn_spec_ops;
297 addaliasu(vp, umajor(0), uminor(0)); /* XXX CUSE */
311 KKASSERT(vn_islocked(vp) == LK_EXCLUSIVE);
312 KASSERT(!fnp->vp, ("lost race"));
320 fuse_node_truncate(struct fuse_node *fnp, size_t oldsize, size_t newsize)
322 struct vnode *vp = fnp->vp;
325 fuse_dbg("ino=%ju update size %ju -> %ju\n",
326 fnp->ino, oldsize, newsize);
328 fnp->attr.va_size = fnp->size = newsize;
330 if (newsize < oldsize)
331 error = nvtruncbuf(vp, newsize, FUSE_BLKSIZE, -1, 0);
333 error = nvextendbuf(vp, oldsize, newsize, FUSE_BLKSIZE,
334 FUSE_BLKSIZE, -1, -1, 0);
341 fuse_node_objcache = objcache_create("fuse_node", 0, 0,
343 objcache_malloc_alloc_zero, objcache_malloc_free, &fuse_node_args);
345 fuse_dent_objcache = objcache_create("fuse_dent", 0, 0,
347 objcache_malloc_alloc_zero, objcache_malloc_free, &fuse_dent_args);
351 fuse_node_cleanup(void)
353 objcache_destroy(fuse_node_objcache);
354 objcache_destroy(fuse_dent_objcache);