xref: /dragonfly/sys/vfs/fuse/fuse_node.c (revision a1626531)
1 /*-
2  * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3  * Copyright (c) 2019 The DragonFly Project
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  */
27 
28 #include "fuse.h"
29 
30 static MALLOC_DEFINE(M_FUSE_NODE, "fuse_node", "FUSE node");
31 
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,
35 };
36 
37 static MALLOC_DEFINE(M_FUSE_DENT, "fuse_dent", "FUSE dent");
38 
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,
42 };
43 
44 static int
45 fuse_dent_cmp(struct fuse_dent *p1, struct fuse_dent *p2)
46 {
47 	return strcmp(p1->name, p2->name);
48 }
49 
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);
52 
53 void
54 fuse_node_new(struct fuse_mount *fmp, uint64_t ino, enum vtype vtyp,
55     struct fuse_node **fnpp)
56 {
57 	struct fuse_node *fnp;
58 
59 	fnp = objcache_get(fuse_node_objcache, M_WAITOK);
60 	KKASSERT(fnp);
61 
62 	memset(fnp, 0, sizeof(*fnp));
63 	fnp->vp = NULL;
64 	fnp->fmp = fmp;
65 	fnp->pfnp = NULL;
66 
67 	mtx_init(&fnp->node_lock, "fuse_node_lock");
68 	RB_INIT(&fnp->dent_head);
69 
70 	fnp->ino = ino;
71 	fnp->type = vtyp;
72 	fnp->nlink = 0;
73 	fnp->size = 0;
74 	fnp->nlookup = 0;
75 	fnp->fh = 0;
76 	fnp->closed = false;
77 
78 	*fnpp = fnp;
79 	KKASSERT(*fnpp);
80 }
81 
82 void
83 fuse_node_free(struct fuse_node *fnp)
84 {
85 	struct fuse_node *dfnp = fnp->pfnp;
86 	struct fuse_dent *fep;
87 
88 	fuse_dbg("free ino=%ju\n", fnp->ino);
89 
90 	if (dfnp) {
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);
96 				fuse_dent_free(fep);
97 				break;
98 			}
99 		}
100 		mtx_unlock(&dfnp->node_lock);
101 	}
102 
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);
107 			fuse_dent_free(fep);
108 		}
109 	}
110 	fnp->vp->v_data = NULL;
111 	fnp->vp = NULL;
112 	fnp->nlink = -123; /* debug */
113 	mtx_unlock(&fnp->node_lock);
114 
115 	objcache_put(fuse_node_objcache, fnp);
116 }
117 
118 void
119 fuse_dent_new(struct fuse_node *fnp, const char *name, int namelen,
120     struct fuse_dent **fepp)
121 {
122 	struct fuse_dent *fep;
123 
124 	fep = objcache_get(fuse_dent_objcache, M_WAITOK);
125 	KKASSERT(fep);
126 
127 	if (namelen >= 0)
128 		fep->name = kstrndup(name, namelen, M_TEMP);
129 	else
130 		fep->name = kstrdup(name, M_TEMP);
131 	KKASSERT(fep->name);
132 	fep->fnp = fnp;
133 
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);
137 	fnp->nlink++;
138 
139 	*fepp = fep;
140 	KKASSERT(*fepp);
141 }
142 
143 void
144 fuse_dent_free(struct fuse_dent *fep)
145 {
146 	struct fuse_node *fnp = fep->fnp;
147 
148 	fuse_dbg("free dent=\"%s\"\n", fep->name);
149 
150 	KASSERT(fnp->nlink > 0, ("free ino=%ju nlink=%d dent=\"%s\"",
151 	    fnp->ino, fnp->nlink, fep->name));
152 
153 	if (fep->name) {
154 		kfree(fep->name, M_TEMP);
155 		fep->name = NULL;
156 	}
157 
158 	KKASSERT(fnp->nlink <= LINK_MAX);
159 	fnp->nlink--;
160 
161 	fep->fnp = NULL;
162 	objcache_put(fuse_dent_objcache, fep);
163 }
164 
165 void
166 fuse_dent_attach(struct fuse_node *dfnp, struct fuse_dent *fep)
167 {
168 	KKASSERT(dfnp);
169 	KKASSERT(dfnp->type == VDIR);
170 	KKASSERT(mtx_islocked_ex(&dfnp->node_lock));
171 
172 	RB_INSERT(fuse_dent_tree, &dfnp->dent_head, fep);
173 }
174 
175 void
176 fuse_dent_detach(struct fuse_node *dfnp, struct fuse_dent *fep)
177 {
178 	KKASSERT(dfnp);
179 	KKASSERT(dfnp->type == VDIR);
180 	KKASSERT(mtx_islocked_ex(&dfnp->node_lock));
181 
182 	RB_REMOVE(fuse_dent_tree, &dfnp->dent_head, fep);
183 }
184 
185 int
186 fuse_dent_find(struct fuse_node *dfnp, const char *name, int namelen,
187     struct fuse_dent **fepp)
188 {
189 	struct fuse_dent *fep, find;
190 	int error;
191 
192 	if (namelen >= 0)
193 		find.name = kstrndup(name, namelen, M_TEMP);
194 	else
195 		find.name = kstrdup(name, M_TEMP);
196 	KKASSERT(find.name);
197 
198 	fep = RB_FIND(fuse_dent_tree, &dfnp->dent_head, &find);
199 	if (fep) {
200 		error = 0;
201 		if (fepp)
202 			*fepp = fep;
203 	} else {
204 		error = ENOENT;
205 		fuse_dbg("dent=\"%s\" not found\n", find.name);
206 	}
207 
208 	kfree(find.name, M_TEMP);
209 
210 	return error;
211 }
212 
213 int
214 fuse_alloc_node(struct fuse_node *dfnp, uint64_t ino, const char *name,
215     int namelen, enum vtype vtyp, struct vnode **vpp)
216 {
217 	struct fuse_node *fnp = NULL;
218 	struct fuse_dent *fep = NULL;
219 	int error;
220 
221 	KKASSERT(dfnp->type == VDIR);
222 	if (vtyp == VBLK || vtyp == VCHR || vtyp == VFIFO)
223 		return EINVAL;
224 
225 	mtx_lock(&dfnp->node_lock);
226 	error = fuse_dent_find(dfnp, name, namelen, &fep);
227 	if (!error) {
228 		mtx_unlock(&dfnp->node_lock);
229 		return EEXIST;
230 	} else if (error == ENOENT) {
231 		fuse_node_new(dfnp->fmp, ino, vtyp, &fnp);
232 		mtx_lock(&fnp->node_lock);
233 		fnp->pfnp = dfnp;
234 		fuse_dent_new(fnp, name, namelen, &fep);
235 		fuse_dent_attach(dfnp, fep);
236 		mtx_unlock(&fnp->node_lock);
237 	} else
238 		KKASSERT(0);
239 	mtx_unlock(&dfnp->node_lock);
240 
241 	error = fuse_node_vn(fnp, LK_EXCLUSIVE, vpp);
242 	if (error) {
243 		mtx_lock(&dfnp->node_lock);
244 		fuse_dent_detach(dfnp, fep);
245 		fuse_dent_free(fep);
246 		mtx_unlock(&dfnp->node_lock);
247 		fuse_node_free(fnp);
248 		return error;
249 	}
250 	KKASSERT(*vpp);
251 
252 	fuse_dbg("fnp=%p ino=%ju dent=\"%s\"\n", fnp, fnp->ino, fep->name);
253 
254 	return 0;
255 }
256 
257 int
258 fuse_node_vn(struct fuse_node *fnp, int flags, struct vnode **vpp)
259 {
260 	struct mount *mp = fnp->fmp->mp;
261 	struct vnode *vp;
262 	int error;
263 retry:
264 	mtx_lock(&fnp->node_lock);
265 	vp = fnp->vp;
266 	if (vp) {
267 		vhold(vp);
268 		mtx_unlock(&fnp->node_lock);
269 
270 		error = vget(vp, flags | LK_RETRY);
271 		if (error) {
272 			vdrop(vp);
273 			goto retry;
274 		}
275 		vdrop(vp);
276 		*vpp = vp;
277 		return 0;
278 	}
279 	mtx_unlock(&fnp->node_lock);
280 
281 	error = getnewvnode(VT_FUSE, mp, &vp, VLKTIMEOUT, LK_CANRECURSE);
282 	if (error)
283 		return error;
284 	vp->v_type = fnp->type;
285 	vp->v_data = fnp;
286 
287 	switch (vp->v_type) {
288 	case VREG:
289 		vinitvmio(vp, fnp->size, FUSE_BLKSIZE, -1);
290 		break;
291 	case VDIR:
292 		break;
293 	case VBLK:
294 	case VCHR:
295 		KKASSERT(0);
296 		vp->v_ops = &mp->mnt_vn_spec_ops;
297 		addaliasu(vp, umajor(0), uminor(0)); /* XXX CUSE */
298 		break;
299 	case VLNK:
300 		break;
301 	case VSOCK:
302 		break;
303 	case VFIFO:
304 		KKASSERT(0);
305 	case VDATABASE:
306 		break;
307 	default:
308 		KKASSERT(0);
309 	}
310 
311 	vx_downgrade(vp);
312 	KKASSERT(vn_islocked(vp) == LK_EXCLUSIVE);
313 	KASSERT(!fnp->vp, ("lost race"));
314 	fnp->vp = vp;
315 	*vpp = vp;
316 
317 	return 0;
318 }
319 
320 int
321 fuse_node_truncate(struct fuse_node *fnp, size_t oldsize, size_t newsize)
322 {
323 	struct vnode *vp = fnp->vp;
324 	int error;
325 
326 	fuse_dbg("ino=%ju update size %ju -> %ju\n",
327 	    fnp->ino, oldsize, newsize);
328 
329 	fnp->attr.va_size = fnp->size = newsize;
330 
331 	if (newsize < oldsize)
332 		error = nvtruncbuf(vp, newsize, FUSE_BLKSIZE, -1, 0);
333 	else
334 		error = nvextendbuf(vp, oldsize, newsize, FUSE_BLKSIZE,
335 		    FUSE_BLKSIZE, -1, -1, 0);
336 	return error;
337 }
338 
339 void
340 fuse_node_init(void)
341 {
342 	fuse_node_objcache = objcache_create("fuse_node", 0, 0,
343 	    NULL, NULL, NULL,
344 	    objcache_malloc_alloc_zero, objcache_malloc_free, &fuse_node_args);
345 
346 	fuse_dent_objcache = objcache_create("fuse_dent", 0, 0,
347 	    NULL, NULL, NULL,
348 	    objcache_malloc_alloc_zero, objcache_malloc_free, &fuse_dent_args);
349 }
350 
351 void
352 fuse_node_cleanup(void)
353 {
354 	objcache_destroy(fuse_node_objcache);
355 	objcache_destroy(fuse_dent_objcache);
356 }
357