/* * Create the '.zfs' directory. This directory is cached as part of the VFS * structure. This results in a hold on the vfs_t. The code in zfs_umount() * therefore checks against a vfs_count of 2 instead of 1. This reference * is removed when the ctldir is destroyed in the unmount. */ void zfsctl_create(zfsvfs_t *zfsvfs) { vnode_t *vp, *rvp; zfsctl_node_t *zcp; ASSERT(zfsvfs->z_ctldir == NULL); vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs, zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries, zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL); zcp = vp->v_data; zcp->zc_id = ZFSCTL_INO_ROOT; VERIFY(VFS_ROOT(zfsvfs->z_vfs, &rvp) == 0); ZFS_TIME_DECODE(&zcp->zc_cmtime, VTOZ(rvp)->z_phys->zp_crtime); VN_RELE(rvp); /* * We're only faking the fact that we have a root of a filesystem for * the sake of the GFS interfaces. Undo the flag manipulation it did * for us. */ vp->v_flag &= ~(VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT); zfsvfs->z_ctldir = vp; }
/* * Create the '.zfs' directory. This directory is cached as part of the VFS * structure. This results in a hold on the vfs_t. The code in zfs_umount() * therefore checks against a vfs_count of 2 instead of 1. This reference * is removed when the ctldir is destroyed in the unmount. */ void zfsctl_create(zfsvfs_t *zfsvfs) { vnode_t *vp, *rvp; zfsctl_node_t *zcp; uint64_t crtime[2]; ASSERT(zfsvfs->z_ctldir == NULL); vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs, &zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries, zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL); zcp = vp->v_data; zcp->zc_id = ZFSCTL_INO_ROOT; VERIFY(VFS_ROOT(zfsvfs->z_vfs, LK_EXCLUSIVE, &rvp) == 0); VERIFY(0 == sa_lookup(VTOZ(rvp)->z_sa_hdl, SA_ZPL_CRTIME(zfsvfs), &crtime, sizeof (crtime))); ZFS_TIME_DECODE(&zcp->zc_cmtime, crtime); VN_URELE(rvp); /* * We're only faking the fact that we have a root of a filesystem for * the sake of the GFS interfaces. Undo the flag manipulation it did * for us. */ vp->v_vflag &= ~VV_ROOT; zfsvfs->z_ctldir = vp; VOP_UNLOCK(vp, 0); }
/* * ctfs_mount - the VFS_MOUNT entry point */ static int ctfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) { ctfs_vfs_t *data; dev_t dev; gfs_dirent_t *dirent; int i; if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) return (EPERM); if (mvp->v_type != VDIR) return (ENOTDIR); if ((uap->flags & MS_OVERLAY) == 0 && (mvp->v_count > 1 || (mvp->v_flag & VROOT))) return (EBUSY); data = kmem_alloc(sizeof (ctfs_vfs_t), KM_SLEEP); /* * Initialize vfs fields not initialized by VFS_INIT/domount */ vfsp->vfs_bsize = DEV_BSIZE; vfsp->vfs_fstype = ctfs_fstype; do dev = makedevice(ctfs_major, atomic_add_32_nv(&ctfs_minor, 1) & L_MAXMIN32); while (vfs_devismounted(dev)); vfs_make_fsid(&vfsp->vfs_fsid, dev, ctfs_fstype); vfsp->vfs_data = data; vfsp->vfs_dev = dev; /* * Dynamically create gfs_dirent_t array for the root directory. */ dirent = kmem_zalloc((ct_ntypes + 2) * sizeof (gfs_dirent_t), KM_SLEEP); for (i = 0; i < ct_ntypes; i++) { dirent[i].gfse_name = (char *)ct_types[i]->ct_type_name; dirent[i].gfse_ctor = ctfs_create_tdirnode; dirent[i].gfse_flags = GFS_CACHE_VNODE; } dirent[i].gfse_name = "all"; dirent[i].gfse_ctor = ctfs_create_adirnode; dirent[i].gfse_flags = GFS_CACHE_VNODE; dirent[i+1].gfse_name = NULL; /* * Create root vnode */ data->ctvfs_root = gfs_root_create(sizeof (ctfs_rootnode_t), vfsp, ctfs_ops_root, CTFS_INO_ROOT, dirent, ctfs_root_do_inode, CTFS_NAME_MAX, NULL, NULL); kmem_free(dirent, (ct_ntypes + 2) * sizeof (gfs_dirent_t)); return (0); }