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