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