xref: /openbsd-src/sys/miscfs/fuse/fuse_vfsops.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: fuse_vfsops.c,v 1.28 2016/09/07 17:53:35 natano Exp $ */
2 /*
3  * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/file.h>
21 #include <sys/filedesc.h>
22 #include <sys/malloc.h>
23 #include <sys/mount.h>
24 #include <sys/pool.h>
25 #include <sys/proc.h>
26 #include <sys/specdev.h>
27 #include <sys/stat.h>
28 #include <sys/statvfs.h>
29 #include <sys/sysctl.h>
30 #include <sys/vnode.h>
31 #include <sys/fusebuf.h>
32 
33 #include "fusefs_node.h"
34 #include "fusefs.h"
35 
36 int	fusefs_mount(struct mount *, const char *, void *, struct nameidata *,
37 	    struct proc *);
38 int	fusefs_start(struct mount *, int, struct proc *);
39 int	fusefs_unmount(struct mount *, int, struct proc *);
40 int	fusefs_root(struct mount *, struct vnode **);
41 int	fusefs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *);
42 int	fusefs_statfs(struct mount *, struct statfs *, struct proc *);
43 int	fusefs_sync(struct mount *, int, struct ucred *, struct proc *);
44 int	fusefs_vget(struct mount *, ino_t, struct vnode **);
45 int	fusefs_fhtovp(struct mount *, struct fid *, struct vnode **);
46 int	fusefs_vptofh(struct vnode *, struct fid *);
47 int	fusefs_init(struct vfsconf *);
48 int	fusefs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
49 	    struct proc *);
50 int	fusefs_checkexp(struct mount *, struct mbuf *, int *,
51 	    struct ucred **);
52 
53 const struct vfsops fusefs_vfsops = {
54 	fusefs_mount,
55 	fusefs_start,
56 	fusefs_unmount,
57 	fusefs_root,
58 	fusefs_quotactl,
59 	fusefs_statfs,
60 	fusefs_sync,
61 	fusefs_vget,
62 	fusefs_fhtovp,
63 	fusefs_vptofh,
64 	fusefs_init,
65 	fusefs_sysctl,
66 	fusefs_checkexp
67 };
68 
69 struct pool fusefs_fbuf_pool;
70 
71 int
72 fusefs_mount(struct mount *mp, const char *path, void *data,
73     struct nameidata *ndp, struct proc *p)
74 {
75 	struct fusefs_mnt *fmp;
76 	struct fusebuf *fbuf;
77 	struct fusefs_args args;
78 	struct vnode *vp;
79 	struct file *fp;
80 	int error;
81 
82 	if (mp->mnt_flag & MNT_UPDATE)
83 		return (EOPNOTSUPP);
84 
85 	error = copyin(data, &args, sizeof(struct fusefs_args));
86 	if (error)
87 		return (error);
88 
89 	if ((fp = fd_getfile(p->p_fd, args.fd)) == NULL)
90 		return (EBADF);
91 
92 	if (fp->f_type != DTYPE_VNODE)
93 		return (EINVAL);
94 
95 	vp = fp->f_data;
96 	if (vp->v_type != VCHR)
97 		return (EBADF);
98 
99 	fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO);
100 	fmp->mp = mp;
101 	fmp->sess_init = 0;
102 	fmp->dev = vp->v_rdev;
103 	if (args.max_read > 0)
104 		fmp->max_read = MIN(args.max_read, FUSEBUFMAXSIZE);
105 	else
106 		fmp->max_read = FUSEBUFMAXSIZE;
107 
108 	mp->mnt_data = fmp;
109 	mp->mnt_flag |= MNT_LOCAL;
110 	vfs_getnewfsid(mp);
111 
112 	bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
113 	strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
114 	bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
115 	strlcpy(mp->mnt_stat.f_mntfromname, "fusefs", MNAMELEN);
116 	bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
117 	strlcpy(mp->mnt_stat.f_mntfromspec, "fusefs", MNAMELEN);
118 
119 	fuse_device_set_fmp(fmp, 1);
120 	fbuf = fb_setup(0, 0, FBT_INIT, p);
121 
122 	/* cannot tsleep on mount */
123 	fuse_device_queue_fbuf(fmp->dev, fbuf);
124 
125 	return (0);
126 }
127 
128 int
129 fusefs_start(struct mount *mp, int flags, struct proc *p)
130 {
131 	return (0);
132 }
133 
134 int
135 fusefs_unmount(struct mount *mp, int mntflags, struct proc *p)
136 {
137 	struct fusefs_mnt *fmp;
138 	struct fusebuf *fbuf;
139 	int flags = 0;
140 	int error;
141 
142 	fmp = VFSTOFUSEFS(mp);
143 
144 	if (mntflags & MNT_FORCE)
145 		flags |= FORCECLOSE;
146 
147 	if ((error = vflush(mp, NULLVP, flags)))
148 		return (error);
149 
150 	if (fmp->sess_init) {
151 		fmp->sess_init = 0;
152 		fbuf = fb_setup(0, 0, FBT_DESTROY, p);
153 
154 		error = fb_queue(fmp->dev, fbuf);
155 
156 		if (error)
157 			printf("fusefs: error %d on destroy\n", error);
158 
159 		fb_delete(fbuf);
160 	}
161 
162 	fuse_device_cleanup(fmp->dev, NULL);
163 	fuse_device_set_fmp(fmp, 0);
164 	free(fmp, M_FUSEFS, 0);
165 	mp->mnt_data = NULL;
166 
167 	return (0);
168 }
169 
170 int
171 fusefs_root(struct mount *mp, struct vnode **vpp)
172 {
173 	struct vnode *nvp;
174 	int error;
175 
176 	if ((error = VFS_VGET(mp, FUSE_ROOTINO, &nvp)) != 0)
177 		return (error);
178 
179 	nvp->v_type = VDIR;
180 
181 	*vpp = nvp;
182 	return (0);
183 }
184 
185 int
186 fusefs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
187     struct proc *p)
188 {
189 	return (EOPNOTSUPP);
190 }
191 
192 int
193 fusefs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
194 {
195 	struct fusefs_mnt *fmp;
196 	struct fusebuf *fbuf;
197 	int error;
198 
199 	fmp = VFSTOFUSEFS(mp);
200 
201 	copy_statfs_info(sbp, mp);
202 
203 	if (fmp->sess_init) {
204 		fbuf = fb_setup(0, FUSE_ROOTINO, FBT_STATFS, p);
205 
206 		error = fb_queue(fmp->dev, fbuf);
207 
208 		if (error) {
209 			fb_delete(fbuf);
210 			return (error);
211 		}
212 
213 		sbp->f_bavail = fbuf->fb_stat.f_bavail;
214 		sbp->f_bfree = fbuf->fb_stat.f_bfree;
215 		sbp->f_blocks = fbuf->fb_stat.f_blocks;
216 		sbp->f_files = fbuf->fb_stat.f_files;
217 		sbp->f_ffree = fbuf->fb_stat.f_ffree;
218 		sbp->f_favail = fbuf->fb_stat.f_favail;
219 		sbp->f_bsize = fbuf->fb_stat.f_frsize;
220 		sbp->f_iosize = fbuf->fb_stat.f_bsize;
221 		sbp->f_namemax = fbuf->fb_stat.f_namemax;
222 		fb_delete(fbuf);
223 	} else {
224 		sbp->f_bavail = 0;
225 		sbp->f_bfree = 0;
226 		sbp->f_blocks = 0;
227 		sbp->f_ffree = 0;
228 		sbp->f_favail = 0;
229 		sbp->f_files = 0;
230 		sbp->f_bsize = 0;
231 		sbp->f_iosize = 0;
232 		sbp->f_namemax = 0;
233 	}
234 
235 	return (0);
236 }
237 
238 int
239 fusefs_sync(struct mount *mp, int waitfor, struct ucred *cred,
240     struct proc *p)
241 {
242 	return (0);
243 }
244 
245 int
246 fusefs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
247 {
248 	struct fusefs_mnt *fmp;
249 	struct fusefs_node *ip;
250 	struct vnode *nvp;
251 	int i;
252 	int error;
253 retry:
254 	fmp = VFSTOFUSEFS(mp);
255 	/*
256 	 * check if vnode is in hash.
257 	 */
258 	if ((*vpp = ufs_ihashget(fmp->dev, ino)) != NULLVP)
259 		return (0);
260 
261 	/*
262 	 * if not create it
263 	 */
264 	if ((error = getnewvnode(VT_FUSEFS, mp, &fusefs_vops, &nvp)) != 0) {
265 		printf("fusefs: getnewvnode error\n");
266 		*vpp = NULLVP;
267 		return (error);
268 	}
269 
270 	ip = malloc(sizeof(*ip), M_FUSEFS, M_WAITOK | M_ZERO);
271 	rrw_init(&ip->ufs_ino.i_lock, "fuseinode");
272 	nvp->v_data = ip;
273 	ip->ufs_ino.i_vnode = nvp;
274 	ip->ufs_ino.i_dev = fmp->dev;
275 	ip->ufs_ino.i_number = ino;
276 
277 	for (i = 0; i < FUFH_MAXTYPE; i++)
278 		ip->fufh[i].fh_type = FUFH_INVALID;
279 
280 	error = ufs_ihashins(&ip->ufs_ino);
281 	if (error) {
282 		vrele(nvp);
283 
284 		if (error == EEXIST)
285 			goto retry;
286 
287 		return (error);
288 	}
289 
290 	ip->ufs_ino.i_ump = (struct ufsmount *)fmp;
291 
292 	if (ino == FUSE_ROOTINO)
293 		nvp->v_flag |= VROOT;
294 
295 	*vpp = nvp;
296 
297 	return (0);
298 }
299 
300 int
301 fusefs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
302 {
303 	return (EINVAL);
304 }
305 
306 int
307 fusefs_vptofh(struct vnode *vp, struct fid *fhp)
308 {
309 	return (EINVAL);
310 }
311 
312 int
313 fusefs_init(struct vfsconf *vfc)
314 {
315 	pool_init(&fusefs_fbuf_pool, sizeof(struct fusebuf), 0, 0, PR_WAITOK,
316 	    "fmsg", NULL);
317 
318 	return (0);
319 }
320 
321 int
322 fusefs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
323     void *newp, size_t newlen, struct proc *p)
324 {
325 	extern int stat_fbufs_in, stat_fbufs_wait, stat_opened_fusedev;
326 
327 	/* all sysctl names at this level are terminal */
328 	if (namelen != 1)
329 		return (ENOTDIR);		/* overloaded */
330 
331 	switch (name[0]) {
332 	case FUSEFS_OPENDEVS:
333 		return (sysctl_rdint(oldp, oldlenp, newp,
334 		    stat_opened_fusedev));
335 	case FUSEFS_INFBUFS:
336 		return (sysctl_rdint(oldp, oldlenp, newp, stat_fbufs_in));
337 	case FUSEFS_WAITFBUFS:
338 		return (sysctl_rdint(oldp, oldlenp, newp, stat_fbufs_wait));
339 	case FUSEFS_POOL_NBPAGES:
340 		return (sysctl_rdint(oldp, oldlenp, newp,
341 		    fusefs_fbuf_pool.pr_npages));
342 	default:
343 		return (EOPNOTSUPP);
344 	}
345 }
346 
347 int
348 fusefs_checkexp(struct mount *mp, struct mbuf *nam, int *extflagsp,
349     struct ucred **credanonp)
350 {
351 	return (EOPNOTSUPP);
352 }
353