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