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