int layerfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) { struct vnode *vp; int error; error = VFS_VGET(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, ino, &vp); if (error) { *vpp = NULL; return error; } VOP_UNLOCK(vp); error = layer_node_create(mp, vp, vpp); if (error) { vrele(vp); *vpp = NULL; return error; } error = vn_lock(*vpp, LK_EXCLUSIVE); if (error) { vrele(*vpp); *vpp = NULL; return error; } return 0; }
int layerfs_fhtovp(struct mount *mp, struct fid *fidp, struct vnode **vpp) { struct vnode *vp; int error; error = VFS_FHTOVP(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, fidp, &vp); if (error) { *vpp = NULL; return error; } VOP_UNLOCK(vp); error = layer_node_create(mp, vp, vpp); if (error) { vput(vp); *vpp = NULL; return (error); } error = vn_lock(*vpp, LK_EXCLUSIVE); if (error) { vrele(*vpp); *vpp = NULL; return error; } return 0; }
/* * Mount umap layer */ int umapfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) { struct lwp *l = curlwp; struct pathbuf *pb; struct nameidata nd; struct umap_args *args = data; struct vnode *lowerrootvp, *vp; struct umap_mount *amp; int error; #ifdef UMAPFS_DIAGNOSTIC int i; #endif if (args == NULL) return EINVAL; if (*data_len < sizeof *args) return EINVAL; if (mp->mnt_flag & MNT_GETARGS) { amp = MOUNTTOUMAPMOUNT(mp); if (amp == NULL) return EIO; args->la.target = NULL; args->nentries = amp->info_nentries; args->gnentries = amp->info_gnentries; *data_len = sizeof *args; return 0; } /* only for root */ error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, KAUTH_REQ_SYSTEM_MOUNT_UMAP, NULL, NULL, NULL); if (error) return error; #ifdef UMAPFS_DIAGNOSTIC printf("umapfs_mount(mp = %p)\n", mp); #endif /* * Update is not supported */ if (mp->mnt_flag & MNT_UPDATE) return EOPNOTSUPP; /* * Find lower node */ error = pathbuf_copyin(args->umap_target, &pb); if (error) { return error; } NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, pb); if ((error = namei(&nd)) != 0) { pathbuf_destroy(pb); return error; } /* * Sanity check on lower vnode */ lowerrootvp = nd.ni_vp; pathbuf_destroy(pb); #ifdef UMAPFS_DIAGNOSTIC printf("vp = %p, check for VDIR...\n", lowerrootvp); #endif if (lowerrootvp->v_type != VDIR) { vput(lowerrootvp); return (EINVAL); } #ifdef UMAPFS_DIAGNOSTIC printf("mp = %p\n", mp); #endif amp = kmem_zalloc(sizeof(struct umap_mount), KM_SLEEP); mp->mnt_data = amp; amp->umapm_vfs = lowerrootvp->v_mount; if (amp->umapm_vfs->mnt_flag & MNT_LOCAL) mp->mnt_flag |= MNT_LOCAL; /* * Now copy in the number of entries and maps for umap mapping. */ if (args->nentries > MAPFILEENTRIES || args->gnentries > GMAPFILEENTRIES) { vput(lowerrootvp); return (error); } amp->info_nentries = args->nentries; amp->info_gnentries = args->gnentries; error = copyin(args->mapdata, amp->info_mapdata, 2*sizeof(u_long)*args->nentries); if (error) { vput(lowerrootvp); return (error); } #ifdef UMAPFS_DIAGNOSTIC printf("umap_mount:nentries %d\n",args->nentries); for (i = 0; i < args->nentries; i++) printf(" %ld maps to %ld\n", amp->info_mapdata[i][0], amp->info_mapdata[i][1]); #endif error = copyin(args->gmapdata, amp->info_gmapdata, 2*sizeof(u_long)*args->gnentries); if (error) { vput(lowerrootvp); return (error); } #ifdef UMAPFS_DIAGNOSTIC printf("umap_mount:gnentries %d\n",args->gnentries); for (i = 0; i < args->gnentries; i++) printf("\tgroup %ld maps to %ld\n", amp->info_gmapdata[i][0], amp->info_gmapdata[i][1]); #endif /* * Make sure the mount point's sufficiently initialized * that the node create call will work. */ vfs_getnewfsid(mp); amp->umapm_size = sizeof(struct umap_node); amp->umapm_tag = VT_UMAP; amp->umapm_bypass = umap_bypass; amp->umapm_vnodeop_p = umap_vnodeop_p; /* * fix up umap node for root vnode. */ VOP_UNLOCK(lowerrootvp); error = layer_node_create(mp, lowerrootvp, &vp); /* * Make sure the node alias worked */ if (error) { vrele(lowerrootvp); kmem_free(amp, sizeof(struct umap_mount)); return error; } /* * Keep a held reference to the root vnode. * It is vrele'd in umapfs_unmount. */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vp->v_vflag |= VV_ROOT; amp->umapm_rootvp = vp; VOP_UNLOCK(vp); error = set_statvfs_info(path, UIO_USERSPACE, args->umap_target, UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); #ifdef UMAPFS_DIAGNOSTIC printf("umapfs_mount: lower %s, alias at %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); #endif return error; }
/* * Mount overlay layer */ int ov_mount(struct mount *mp, const char *path, void *data, size_t *data_len) { struct lwp *l = curlwp; int error = 0; struct overlay_args *args = data; struct vnode *lowerrootvp, *vp; struct overlay_mount *nmp; struct layer_mount *lmp; #ifdef OVERLAYFS_DIAGNOSTIC printf("ov_mount(mp = %p)\n", mp); #endif if (args == NULL) return EINVAL; if (*data_len < sizeof *args) return EINVAL; if (mp->mnt_flag & MNT_GETARGS) { lmp = MOUNTTOLAYERMOUNT(mp); if (lmp == NULL) return EIO; args->la.target = NULL; *data_len = sizeof *args; return 0; } /* * Update is not supported */ if (mp->mnt_flag & MNT_UPDATE) return EOPNOTSUPP; /* * Find lower node */ lowerrootvp = mp->mnt_vnodecovered; vref(lowerrootvp); if ((error = vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY))) { vrele(lowerrootvp); return (error); } /* * First cut at fixing up upper mount point */ nmp = kmem_zalloc(sizeof(struct overlay_mount), KM_SLEEP); mp->mnt_data = nmp; nmp->ovm_vfs = lowerrootvp->v_mount; if (nmp->ovm_vfs->mnt_flag & MNT_LOCAL) mp->mnt_flag |= MNT_LOCAL; /* * Make sure that the mount point is sufficiently initialized * that the node create call will work. */ vfs_getnewfsid(mp); nmp->ovm_size = sizeof (struct overlay_node); nmp->ovm_tag = VT_OVERLAY; nmp->ovm_bypass = layer_bypass; nmp->ovm_vnodeop_p = overlay_vnodeop_p; /* * Fix up overlay node for root vnode */ VOP_UNLOCK(lowerrootvp); error = layer_node_create(mp, lowerrootvp, &vp); /* * Make sure the fixup worked */ if (error) { vrele(lowerrootvp); kmem_free(nmp, sizeof(struct overlay_mount)); return error; } /* * Keep a held reference to the root vnode. * It is vrele'd in ov_unmount. */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vp->v_vflag |= VV_ROOT; nmp->ovm_rootvp = vp; VOP_UNLOCK(vp); error = set_statvfs_info(path, UIO_USERSPACE, args->la.target, UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); #ifdef OVERLAYFS_DIAGNOSTIC printf("ov_mount: lower %s, alias at %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); #endif return error; }