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