Line data Source code
1 : /* $OpenBSD: fuse_vfsops.c,v 1.42 2018/07/17 13:12:08 helg 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, 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 : #define PENDING 2 /* FBT_INIT reply not yet received */
72 :
73 : int
74 0 : fusefs_mount(struct mount *mp, const char *path, void *data,
75 : struct nameidata *ndp, struct proc *p)
76 : {
77 : struct fusefs_mnt *fmp;
78 : struct fusebuf *fbuf;
79 0 : struct fusefs_args *args = data;
80 : struct vnode *vp;
81 : struct file *fp;
82 : int error = 0;
83 :
84 0 : if (mp->mnt_flag & MNT_UPDATE)
85 0 : return (EOPNOTSUPP);
86 :
87 0 : if ((fp = fd_getfile(p->p_fd, args->fd)) == NULL)
88 0 : return (EBADF);
89 :
90 0 : if (fp->f_type != DTYPE_VNODE) {
91 : error = EINVAL;
92 0 : goto bad;
93 : }
94 :
95 0 : vp = fp->f_data;
96 0 : if (vp->v_type != VCHR) {
97 : error = EBADF;
98 0 : goto bad;
99 : }
100 :
101 : /* Only root may specify allow_other. */
102 0 : if (args->allow_other && (error = suser_ucred(p->p_ucred)))
103 : goto bad;
104 :
105 0 : fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO);
106 0 : fmp->mp = mp;
107 0 : fmp->sess_init = PENDING;
108 0 : fmp->dev = vp->v_rdev;
109 0 : if (args->max_read > 0)
110 0 : fmp->max_read = MIN(args->max_read, FUSEBUFMAXSIZE);
111 : else
112 0 : fmp->max_read = FUSEBUFMAXSIZE;
113 :
114 0 : fmp->allow_other = args->allow_other;
115 :
116 0 : mp->mnt_data = fmp;
117 0 : mp->mnt_flag |= MNT_LOCAL;
118 0 : vfs_getnewfsid(mp);
119 :
120 0 : memset(mp->mnt_stat.f_mntonname, 0, MNAMELEN);
121 0 : strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
122 0 : memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
123 0 : strlcpy(mp->mnt_stat.f_mntfromname, "fusefs", MNAMELEN);
124 0 : memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN);
125 0 : strlcpy(mp->mnt_stat.f_mntfromspec, "fusefs", MNAMELEN);
126 :
127 0 : fuse_device_set_fmp(fmp, 1);
128 0 : fbuf = fb_setup(0, 0, FBT_INIT, p);
129 :
130 : /* cannot tsleep on mount */
131 0 : fuse_device_queue_fbuf(fmp->dev, fbuf);
132 :
133 : bad:
134 0 : FRELE(fp, p);
135 0 : return (error);
136 0 : }
137 :
138 : int
139 0 : fusefs_start(struct mount *mp, int flags, struct proc *p)
140 : {
141 0 : return (0);
142 : }
143 :
144 : int
145 0 : fusefs_unmount(struct mount *mp, int mntflags, struct proc *p)
146 : {
147 : struct fusefs_mnt *fmp;
148 : struct fusebuf *fbuf;
149 : int flags = 0;
150 : int error;
151 :
152 0 : fmp = VFSTOFUSEFS(mp);
153 :
154 0 : if (mntflags & MNT_FORCE)
155 0 : flags |= FORCECLOSE;
156 :
157 0 : if ((error = vflush(mp, NULLVP, flags)))
158 0 : return (error);
159 :
160 0 : if (fmp->sess_init && fmp->sess_init != PENDING) {
161 0 : fbuf = fb_setup(0, 0, FBT_DESTROY, p);
162 :
163 0 : error = fb_queue(fmp->dev, fbuf);
164 :
165 0 : if (error)
166 0 : printf("fusefs: error %d on destroy\n", error);
167 :
168 0 : fb_delete(fbuf);
169 0 : }
170 0 : fmp->sess_init = 0;
171 :
172 0 : fuse_device_cleanup(fmp->dev);
173 0 : fuse_device_set_fmp(fmp, 0);
174 0 : free(fmp, M_FUSEFS, sizeof(*fmp));
175 0 : mp->mnt_data = NULL;
176 :
177 0 : return (0);
178 0 : }
179 :
180 : int
181 0 : fusefs_root(struct mount *mp, struct vnode **vpp)
182 : {
183 0 : struct vnode *nvp;
184 : int error;
185 :
186 0 : if ((error = VFS_VGET(mp, FUSE_ROOTINO, &nvp)) != 0)
187 0 : return (error);
188 :
189 0 : nvp->v_type = VDIR;
190 :
191 0 : *vpp = nvp;
192 0 : return (0);
193 0 : }
194 :
195 : int
196 0 : fusefs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
197 : struct proc *p)
198 : {
199 0 : return (EOPNOTSUPP);
200 : }
201 :
202 : int
203 0 : fusefs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
204 : {
205 : struct fusefs_mnt *fmp;
206 : struct fusebuf *fbuf;
207 : int error;
208 :
209 0 : fmp = VFSTOFUSEFS(mp);
210 :
211 : /* Deny other users unless allow_other mount option was specified. */
212 0 : if (!fmp->allow_other && p->p_ucred->cr_uid != mp->mnt_stat.f_owner)
213 0 : return (EPERM);
214 :
215 0 : copy_statfs_info(sbp, mp);
216 :
217 : /*
218 : * Both FBT_INIT and FBT_STATFS are sent to the FUSE file system
219 : * daemon when it is mounted. However, the daemon is the process
220 : * that called mount(2) so to prevent a deadlock return dummy
221 : * values until the response to FBT_INIT init is received. All
222 : * other VFS syscalls are queued.
223 : */
224 0 : if (!fmp->sess_init || fmp->sess_init == PENDING) {
225 0 : sbp->f_bavail = 0;
226 0 : sbp->f_bfree = 0;
227 0 : sbp->f_blocks = 0;
228 0 : sbp->f_ffree = 0;
229 0 : sbp->f_favail = 0;
230 0 : sbp->f_files = 0;
231 0 : sbp->f_bsize = 0;
232 0 : sbp->f_iosize = 0;
233 0 : sbp->f_namemax = 0;
234 0 : } else {
235 0 : fbuf = fb_setup(0, FUSE_ROOTINO, FBT_STATFS, p);
236 :
237 0 : error = fb_queue(fmp->dev, fbuf);
238 :
239 0 : if (error) {
240 0 : fb_delete(fbuf);
241 0 : return (error);
242 : }
243 :
244 0 : sbp->f_bavail = fbuf->fb_stat.f_bavail;
245 0 : sbp->f_bfree = fbuf->fb_stat.f_bfree;
246 0 : sbp->f_blocks = fbuf->fb_stat.f_blocks;
247 0 : sbp->f_files = fbuf->fb_stat.f_files;
248 0 : sbp->f_ffree = fbuf->fb_stat.f_ffree;
249 0 : sbp->f_favail = fbuf->fb_stat.f_favail;
250 0 : sbp->f_bsize = fbuf->fb_stat.f_frsize;
251 0 : sbp->f_iosize = fbuf->fb_stat.f_bsize;
252 0 : sbp->f_namemax = fbuf->fb_stat.f_namemax;
253 0 : fb_delete(fbuf);
254 : }
255 :
256 0 : return (0);
257 0 : }
258 :
259 : int
260 0 : fusefs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred,
261 : struct proc *p)
262 : {
263 0 : return (0);
264 : }
265 :
266 : int
267 0 : fusefs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
268 : {
269 0 : struct vattr vattr;
270 : struct fusefs_mnt *fmp;
271 : struct fusefs_node *ip;
272 0 : struct vnode *nvp;
273 : int i;
274 0 : int error;
275 : retry:
276 0 : fmp = VFSTOFUSEFS(mp);
277 : /*
278 : * check if vnode is in hash.
279 : */
280 0 : if ((*vpp = ufs_ihashget(fmp->dev, ino)) != NULLVP)
281 0 : return (0);
282 :
283 : /*
284 : * if not create it
285 : */
286 0 : if ((error = getnewvnode(VT_FUSEFS, mp, &fusefs_vops, &nvp)) != 0) {
287 0 : printf("fusefs: getnewvnode error\n");
288 0 : *vpp = NULLVP;
289 0 : return (error);
290 : }
291 :
292 0 : ip = malloc(sizeof(*ip), M_FUSEFS, M_WAITOK | M_ZERO);
293 0 : rrw_init_flags(&ip->ufs_ino.i_lock, "fuseinode",
294 : RWL_DUPOK | RWL_IS_VNODE);
295 0 : nvp->v_data = ip;
296 0 : ip->ufs_ino.i_vnode = nvp;
297 0 : ip->ufs_ino.i_dev = fmp->dev;
298 0 : ip->ufs_ino.i_number = ino;
299 :
300 0 : for (i = 0; i < FUFH_MAXTYPE; i++)
301 0 : ip->fufh[i].fh_type = FUFH_INVALID;
302 :
303 0 : error = ufs_ihashins(&ip->ufs_ino);
304 0 : if (error) {
305 0 : vrele(nvp);
306 :
307 0 : if (error == EEXIST)
308 0 : goto retry;
309 :
310 0 : return (error);
311 : }
312 :
313 0 : ip->ufs_ino.i_ump = (struct ufsmount *)fmp;
314 :
315 0 : if (ino == FUSE_ROOTINO)
316 0 : nvp->v_flag |= VROOT;
317 : else {
318 : /*
319 : * Initialise the file size so that file size changes can be
320 : * detected during file operations.
321 : */
322 0 : error = VOP_GETATTR(nvp, &vattr, curproc->p_ucred, curproc);
323 0 : if (error) {
324 0 : vrele(nvp);
325 0 : return (error);
326 : }
327 0 : ip->filesize = vattr.va_size;
328 : }
329 :
330 0 : *vpp = nvp;
331 :
332 0 : return (0);
333 0 : }
334 :
335 : int
336 0 : fusefs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
337 : {
338 0 : return (EINVAL);
339 : }
340 :
341 : int
342 0 : fusefs_vptofh(struct vnode *vp, struct fid *fhp)
343 : {
344 0 : return (EINVAL);
345 : }
346 :
347 : int
348 0 : fusefs_init(struct vfsconf *vfc)
349 : {
350 0 : pool_init(&fusefs_fbuf_pool, sizeof(struct fusebuf), 0, 0, PR_WAITOK,
351 : "fmsg", NULL);
352 :
353 0 : return (0);
354 : }
355 :
356 : int
357 0 : fusefs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
358 : void *newp, size_t newlen, struct proc *p)
359 : {
360 : extern int stat_fbufs_in, stat_fbufs_wait, stat_opened_fusedev;
361 :
362 : /* all sysctl names at this level are terminal */
363 0 : if (namelen != 1)
364 0 : return (ENOTDIR); /* overloaded */
365 :
366 0 : switch (name[0]) {
367 : case FUSEFS_OPENDEVS:
368 0 : return (sysctl_rdint(oldp, oldlenp, newp,
369 0 : stat_opened_fusedev));
370 : case FUSEFS_INFBUFS:
371 0 : return (sysctl_rdint(oldp, oldlenp, newp, stat_fbufs_in));
372 : case FUSEFS_WAITFBUFS:
373 0 : return (sysctl_rdint(oldp, oldlenp, newp, stat_fbufs_wait));
374 : case FUSEFS_POOL_NBPAGES:
375 0 : return (sysctl_rdint(oldp, oldlenp, newp,
376 0 : fusefs_fbuf_pool.pr_npages));
377 : default:
378 0 : return (EOPNOTSUPP);
379 : }
380 0 : }
381 :
382 : int
383 0 : fusefs_checkexp(struct mount *mp, struct mbuf *nam, int *extflagsp,
384 : struct ucred **credanonp)
385 : {
386 0 : return (EOPNOTSUPP);
387 : }
|