xref: /openbsd-src/sys/miscfs/fuse/fuse_vfsops.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /* $OpenBSD: fuse_vfsops.c,v 1.11 2014/07/12 18:43:52 tedu 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/file.h>
20 #include <sys/filedesc.h>
21 #include <sys/malloc.h>
22 #include <sys/mount.h>
23 #include <sys/pool.h>
24 #include <sys/proc.h>
25 #include <sys/specdev.h>
26 #include <sys/statvfs.h>
27 #include <sys/sysctl.h>
28 #include <sys/vnode.h>
29 #include <sys/fusebuf.h>
30 
31 #include "fusefs_node.h"
32 #include "fusefs.h"
33 
34 int	fusefs_mount(struct mount *, const char *, void *, struct nameidata *,
35 	    struct proc *);
36 int	fusefs_start(struct mount *, int, struct proc *);
37 int	fusefs_unmount(struct mount *, int, struct proc *);
38 int	fusefs_root(struct mount *, struct vnode **);
39 int	fusefs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *);
40 int	fusefs_statfs(struct mount *, struct statfs *, struct proc *);
41 int	fusefs_sync(struct mount *, int, struct ucred *, struct proc *);
42 int	fusefs_vget(struct mount *, ino_t, struct vnode **);
43 int	fusefs_fhtovp(struct mount *, struct fid *, struct vnode **);
44 int	fusefs_vptofh(struct vnode *, struct fid *);
45 int	fusefs_init(struct vfsconf *);
46 int	fusefs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
47 	    struct proc *);
48 int	fusefs_checkexp(struct mount *, struct mbuf *, int *,
49 	    struct ucred **);
50 
51 const struct vfsops fusefs_vfsops = {
52 	fusefs_mount,
53 	fusefs_start,
54 	fusefs_unmount,
55 	fusefs_root,
56 	fusefs_quotactl,
57 	fusefs_statfs,
58 	fusefs_sync,
59 	fusefs_vget,
60 	fusefs_fhtovp,
61 	fusefs_vptofh,
62 	fusefs_init,
63 	fusefs_sysctl,
64 	fusefs_checkexp
65 };
66 
67 struct pool fusefs_fbuf_pool;
68 
69 int
70 fusefs_mount(struct mount *mp, const char *path, void *data,
71     struct nameidata *ndp, struct proc *p)
72 {
73 	struct fusefs_mnt *fmp;
74 	struct fusebuf *fbuf;
75 	struct fusefs_args args;
76 	struct vnode *vp;
77 	struct file *fp;
78 	int error;
79 
80 	if (mp->mnt_flag & MNT_UPDATE)
81 		return (EOPNOTSUPP);
82 
83 	error = copyin(data, &args, sizeof(struct fusefs_args));
84 	if (error)
85 		return (error);
86 
87 	if ((fp = fd_getfile(p->p_fd, args.fd)) == NULL)
88 		return (EBADF);
89 
90 	if (fp->f_type != DTYPE_VNODE)
91 		return (EINVAL);
92 
93 	vp = fp->f_data;
94 	if (vp->v_type != VCHR)
95 		return (EBADF);
96 
97 	fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO);
98 	fmp->mp = mp;
99 	fmp->sess_init = 0;
100 	fmp->dev = vp->v_rdev;
101 	if (args.max_read > 0)
102 		fmp->max_read = MIN(args.max_read, FUSEBUFMAXSIZE);
103 	else
104 		fmp->max_read = FUSEBUFMAXSIZE;
105 
106 	mp->mnt_data = fmp;
107 	mp->mnt_flag |= MNT_LOCAL;
108 	vfs_getnewfsid(mp);
109 
110 	bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
111 	strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
112 	bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
113 	bcopy("fusefs", mp->mnt_stat.f_mntfromname, sizeof("fusefs"));
114 
115 	fuse_device_set_fmp(fmp, 1);
116 	fbuf = fb_setup(0, 0, FBT_INIT, p);
117 
118 	/* cannot tsleep on mount */
119 	fuse_device_queue_fbuf(fmp->dev, fbuf);
120 
121 	return (0);
122 }
123 
124 int
125 fusefs_start(struct mount *mp, int flags, struct proc *p)
126 {
127 	return (0);
128 }
129 
130 int
131 fusefs_unmount(struct mount *mp, int mntflags, struct proc *p)
132 {
133 	struct fusefs_mnt *fmp;
134 	struct fusebuf *fbuf;
135 	extern int doforce;
136 	int flags = 0;
137 	int error;
138 
139 	fmp = VFSTOFUSEFS(mp);
140 
141 	if (mntflags & MNT_FORCE) {
142 		/* fusefs can never be rootfs so don't check for it */
143 		if (!doforce)
144 			return (EINVAL);
145 
146 		flags |= FORCECLOSE;
147 	}
148 
149 	if ((error = vflush(mp, NULLVP, flags)))
150 		return (error);
151 
152 	if (fmp->sess_init) {
153 		fmp->sess_init = 0;
154 		fbuf = fb_setup(0, 0, FBT_DESTROY, p);
155 
156 		error = fb_queue(fmp->dev, fbuf);
157 
158 		if (error)
159 			printf("fusefs: error %d on destroy\n", error);
160 
161 		fb_delete(fbuf);
162 	}
163 
164 	fuse_device_cleanup(fmp->dev, NULL);
165 	fuse_device_set_fmp(fmp, 0);
166 	free(fmp, M_FUSEFS, 0);
167 
168 	return (error);
169 }
170 
171 int
172 fusefs_root(struct mount *mp, struct vnode **vpp)
173 {
174 	struct vnode *nvp;
175 	struct fusefs_node *ip;
176 	int error;
177 
178 	if ((error = VFS_VGET(mp, (ino_t)FUSE_ROOTINO, &nvp)) != 0)
179 		return (error);
180 
181 	ip = VTOI(nvp);
182 	nvp->v_type = VDIR;
183 	ip->vtype = VDIR;
184 
185 	*vpp = nvp;
186 	return (0);
187 }
188 
189 int fusefs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
190     struct proc *p)
191 {
192 	return (0);
193 }
194 
195 int fusefs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
196 {
197 	struct fusefs_mnt *fmp;
198 	struct fusebuf *fbuf;
199 	int error;
200 
201 	fmp = VFSTOFUSEFS(mp);
202 
203 	if (fmp->sess_init) {
204 		fbuf = fb_setup(0, FUSE_ROOT_ID, 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_bsize = fbuf->fb_stat.f_frsize;
219 		sbp->f_namemax = fbuf->fb_stat.f_namemax;
220 		fb_delete(fbuf);
221 	} else {
222 		sbp->f_bavail = 0;
223 		sbp->f_bfree = 0;
224 		sbp->f_blocks = 0;
225 		sbp->f_ffree = 0;
226 		sbp->f_files = 0;
227 		sbp->f_bsize = 0;
228 		sbp->f_namemax = 0;
229 	}
230 
231 	return (0);
232 }
233 
234 int fusefs_sync(struct mount *mp, int waitfor, struct ucred *cred,
235     struct proc *p)
236 {
237 	return (0);
238 }
239 
240 int fusefs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
241 {
242 	struct fusefs_mnt *fmp;
243 	struct fusefs_node *ip;
244 	struct vnode *nvp;
245 	int i;
246 	int error;
247 retry:
248 	fmp = VFSTOFUSEFS(mp);
249 	/*
250 	 * check if vnode is in hash.
251 	 */
252 	if ((*vpp = ufs_ihashget(fmp->dev, ino)) != NULLVP)
253 		return (0);
254 
255 	/*
256 	 * if not create it
257 	 */
258 	if ((error = getnewvnode(VT_FUSEFS, mp, &fusefs_vops, &nvp)) != 0) {
259 		printf("fusefs: getnewvnode error\n");
260 		*vpp = NULLVP;
261 		return (error);
262 	}
263 
264 	ip = malloc(sizeof(*ip), M_FUSEFS, M_WAITOK | M_ZERO);
265 	lockinit(&ip->ufs_ino.i_lock, PINOD, "fuseinode", 0, 0);
266 	nvp->v_data = ip;
267 	ip->ufs_ino.i_vnode = nvp;
268 	ip->ufs_ino.i_dev = fmp->dev;
269 	ip->ufs_ino.i_number = ino;
270 	ip->parent = 0;
271 
272 	for (i = 0; i < FUFH_MAXTYPE; i++)
273 		ip->fufh[i].fh_type = FUFH_INVALID;
274 
275 	error = ufs_ihashins(&ip->ufs_ino);
276 	if (error) {
277 		vrele(nvp);
278 
279 		if (error == EEXIST)
280 			goto retry;
281 
282 		return (error);
283 	}
284 
285 	ip->ufs_ino.i_ump = (struct ufsmount *)fmp;
286 
287 	if (ino == FUSE_ROOTINO)
288 		nvp->v_flag |= VROOT;
289 
290 	*vpp = nvp;
291 
292 	return (0);
293 }
294 
295 int fusefs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
296 {
297 	return (0);
298 }
299 
300 int fusefs_vptofh(struct vnode *vp, struct fid *fhp)
301 {
302 	return (0);
303 }
304 
305 int fusefs_init(struct vfsconf *vfc)
306 {
307 	pool_init(&fusefs_fbuf_pool, sizeof(struct fusebuf), 0, 0, 0,
308 	    "fmsg", &pool_allocator_nointr);
309 
310 	return (0);
311 }
312 
313 int fusefs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
314     void *newp, size_t newlen, struct proc *p)
315 {
316 	extern int stat_fbufs_in, stat_fbufs_wait, stat_opened_fusedev;
317 
318 	/* all sysctl names at this level are terminal */
319 	if (namelen != 1)
320 		return (ENOTDIR);		/* overloaded */
321 
322 	switch (name[0]) {
323 	case FUSEFS_OPENDEVS:
324 		return (sysctl_rdint(oldp, oldlenp, newp,
325 		    stat_opened_fusedev));
326 	case FUSEFS_INFBUFS:
327 		return (sysctl_rdint(oldp, oldlenp, newp, stat_fbufs_in));
328 	case FUSEFS_WAITFBUFS:
329 		return (sysctl_rdint(oldp, oldlenp, newp, stat_fbufs_wait));
330 	case FUSEFS_POOL_NBPAGES:
331 		return (sysctl_rdint(oldp, oldlenp, newp,
332 		    fusefs_fbuf_pool.pr_npages));
333 	default:
334 		return (EOPNOTSUPP);
335 	}
336 }
337 
338 int fusefs_checkexp(struct mount *mp, struct mbuf *nam, int *extflagsp,
339     struct ucred **credanonp)
340 {
341 	return (0);
342 }
343