From b75299830a2e3cf6fe944866063eb45aa36cb022 Mon Sep 17 00:00:00 2001 From: hannken Date: Mon, 18 Mar 2019 09:22:14 +0000 Subject: [PATCH] Make ZFS exportable by NFS, implement zfsctl_vptofh(), zfs_netbsd_vptofh() and zfs_netbsd_fhtovp(). Undo changes to now completely unused zfs_fhtovp(). --- .../dist/uts/common/fs/zfs/sys/zfs_ctldir.h | 1 + .../osnet/dist/uts/common/fs/zfs/zfs_ctldir.c | 27 +++ .../osnet/dist/uts/common/fs/zfs/zfs_vfsops.c | 187 ++++++++++++++++-- 3 files changed, 199 insertions(+), 16 deletions(-) diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_ctldir.h b/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_ctldir.h index 3fb111210747..b423569d8d5a 100644 --- a/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_ctldir.h +++ b/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_ctldir.h @@ -46,6 +46,7 @@ void zfsctl_create(zfsvfs_t *); void zfsctl_destroy(zfsvfs_t *); #ifdef __NetBSD__ int zfsctl_loadvnode(vfs_t *, vnode_t *, const void *, size_t, const void **); +int zfsctl_vptofh(vnode_t *, fid_t *, size_t *); int zfsctl_root(zfsvfs_t *, vnode_t **); int zfsctl_snapshot(zfsvfs_t *, vnode_t **); #else diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c index 400ea4184fba..8ac619838186 100644 --- a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c +++ b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c @@ -1885,6 +1885,33 @@ zfsctl_loadvnode(vfs_t *vfsp, vnode_t *vp, return 0; } +int +zfsctl_vptofh(vnode_t *vp, fid_t *fidp, size_t *fh_size) +{ + struct sfs_node *node = VTOSFS(vp); + uint64_t object = node->sn_id; + zfid_short_t *zfid = (zfid_short_t *)fidp; + int i; + + SFS_NODE_ASSERT(vp); + + if (*fh_size < SHORT_FID_LEN) { + *fh_size = SHORT_FID_LEN; + return SET_ERROR(E2BIG); + } + *fh_size = SHORT_FID_LEN; + + zfid->zf_len = SHORT_FID_LEN; + for (i = 0; i < sizeof(zfid->zf_object); i++) + zfid->zf_object[i] = (uint8_t)(object >> (8 * i)); + + /* .zfs nodes always have a generation number of 0 */ + for (i = 0; i < sizeof(zfid->zf_gen); i++) + zfid->zf_gen[i] = 0; + + return 0; +} + /* * Return the ".zfs" vnode. */ diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c index 27e11ee10ceb..8bd674dd9465 100644 --- a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c +++ b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c @@ -136,7 +136,8 @@ static int zfs_umount(vfs_t *vfsp, int fflag); static int zfs_root(vfs_t *vfsp, int flags, vnode_t **vpp); static int zfs_netbsd_root(vfs_t *vfsp, vnode_t **vpp); static int zfs_statvfs(vfs_t *vfsp, struct statvfs *statp); -static int zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp); +static int zfs_netbsd_vptofh(vnode_t *vp, fid_t *fidp, size_t *fh_size); +static int zfs_netbsd_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp); static int zfs_vget(vfs_t *vfsp, ino_t ino, vnode_t **vpp); static int zfs_sync(vfs_t *vfsp, int waitfor); static int zfs_netbsd_sync(vfs_t *vfsp, int waitfor, cred_t *cr); @@ -172,8 +173,8 @@ struct vfsops zfs_vfsops = { .vfs_renamelock_enter = genfs_renamelock_enter, .vfs_renamelock_exit = genfs_renamelock_exit, .vfs_reinit = (void *)nullop, - .vfs_vptofh = (void *)eopnotsupp, - .vfs_fhtovp = (void *)eopnotsupp, + .vfs_vptofh = zfs_netbsd_vptofh, + .vfs_fhtovp = zfs_netbsd_fhtovp, .vfs_quotactl = (void *)eopnotsupp, .vfs_extattrctl = (void *)eopnotsupp, .vfs_suspendctl = genfs_suspendctl, @@ -254,6 +255,171 @@ zfs_netbsd_root(vfs_t *vfsp, vnode_t **vpp) return zfs_root(vfsp, LK_EXCLUSIVE | LK_RETRY, vpp); } +static int +zfs_netbsd_vptofh(vnode_t *vp, fid_t *fidp, size_t *fh_size) +{ + znode_t *zp; + zfsvfs_t *zfsvfs; + uint32_t gen; + uint64_t gen64; + uint64_t object; + zfid_short_t *zfid; + int size, i, error; + + if (zfsctl_is_node(vp)) + return zfsctl_vptofh(vp, fidp, fh_size); + + zp = VTOZ(vp); + zfsvfs = zp->z_zfsvfs; + object = zp->z_id; + + ZFS_ENTER(zfsvfs); + ZFS_VERIFY_ZP(zp); + + if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zfsvfs), + &gen64, sizeof (uint64_t))) != 0) { + ZFS_EXIT(zfsvfs); + return (error); + } + + gen = (uint32_t)gen64; + + size = (zfsvfs->z_parent != zfsvfs) ? LONG_FID_LEN : SHORT_FID_LEN; + + if (*fh_size < size) { + ZFS_EXIT(zfsvfs); + *fh_size = size; + return SET_ERROR(E2BIG); + } + *fh_size = size; + + zfid = (zfid_short_t *)fidp; + + zfid->zf_len = size; + + for (i = 0; i < sizeof (zfid->zf_object); i++) + zfid->zf_object[i] = (uint8_t)(object >> (8 * i)); + + /* Must have a non-zero generation number to distinguish from .zfs */ + if (gen == 0) + gen = 1; + for (i = 0; i < sizeof (zfid->zf_gen); i++) + zfid->zf_gen[i] = (uint8_t)(gen >> (8 * i)); + + if (size == LONG_FID_LEN) { + uint64_t objsetid = dmu_objset_id(zfsvfs->z_os); + zfid_long_t *zlfid; + + zlfid = (zfid_long_t *)fidp; + + for (i = 0; i < sizeof (zlfid->zf_setid); i++) + zlfid->zf_setid[i] = (uint8_t)(objsetid >> (8 * i)); + + /* XXX - this should be the generation number for the objset */ + for (i = 0; i < sizeof (zlfid->zf_setgen); i++) + zlfid->zf_setgen[i] = 0; + } + + ZFS_EXIT(zfsvfs); + return 0; +} + +static int +zfs_netbsd_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp) +{ + zfsvfs_t *zfsvfs = vfsp->vfs_data; + znode_t *zp; + vnode_t *dvp; + uint64_t object = 0; + uint64_t fid_gen = 0; + uint64_t gen_mask; + uint64_t zp_gen; + int i, err; + + *vpp = NULL; + + ZFS_ENTER(zfsvfs); + + if (zfsvfs->z_parent == zfsvfs && fidp->fid_len == LONG_FID_LEN) { + zfid_long_t *zlfid = (zfid_long_t *)fidp; + uint64_t objsetid = 0; + uint64_t setgen = 0; + + for (i = 0; i < sizeof (zlfid->zf_setid); i++) + objsetid |= ((uint64_t)zlfid->zf_setid[i]) << (8 * i); + + for (i = 0; i < sizeof (zlfid->zf_setgen); i++) + setgen |= ((uint64_t)zlfid->zf_setgen[i]) << (8 * i); + + ZFS_EXIT(zfsvfs); + + err = zfsctl_lookup_objset(vfsp, objsetid, &zfsvfs); + if (err) + return (SET_ERROR(EINVAL)); + ZFS_ENTER(zfsvfs); + } + + if (fidp->fid_len == SHORT_FID_LEN || fidp->fid_len == LONG_FID_LEN) { + zfid_short_t *zfid = (zfid_short_t *)fidp; + + for (i = 0; i < sizeof (zfid->zf_object); i++) + object |= ((uint64_t)zfid->zf_object[i]) << (8 * i); + + for (i = 0; i < sizeof (zfid->zf_gen); i++) + fid_gen |= ((uint64_t)zfid->zf_gen[i]) << (8 * i); + } else { + ZFS_EXIT(zfsvfs); + return (SET_ERROR(EINVAL)); + } + + /* A zero fid_gen means we are in the .zfs control directories */ + if (fid_gen == 0 && + (object == ZFSCTL_INO_ROOT || object == ZFSCTL_INO_SNAPDIR)) { + ZFS_EXIT(zfsvfs); + if (object == ZFSCTL_INO_ROOT) + err = zfsctl_root(zfsvfs, vpp); + else + err = zfsctl_snapshot(zfsvfs, vpp); + if (err) + return err; + err = vn_lock(*vpp, LK_EXCLUSIVE); + if (err) { + vrele(*vpp); + *vpp = NULL; + return err; + } + return 0; + } + + gen_mask = -1ULL >> (64 - 8 * i); + + dprintf("getting %llu [%u mask %llx]\n", object, fid_gen, gen_mask); + if (err = zfs_zget(zfsvfs, object, &zp)) { + ZFS_EXIT(zfsvfs); + return SET_ERROR(ESTALE); + } + (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zfsvfs), &zp_gen, + sizeof (uint64_t)); + zp_gen = zp_gen & gen_mask; + if (zp_gen == 0) + zp_gen = 1; + if (zp->z_unlinked || zp_gen != fid_gen) { + dprintf("znode gen (%u) != fid gen (%u)\n", zp_gen, fid_gen); + VN_RELE(ZTOV(zp)); + ZFS_EXIT(zfsvfs); + return SET_ERROR(ESTALE); + } + + *vpp = ZTOV(zp); + ZFS_EXIT(zfsvfs); + err = vn_lock(*vpp, LK_EXCLUSIVE); + if (err) { + vrele(*vpp); + *vpp = NULL; + return err; + } + return 0; +} #endif /* __NetBSD__ */ /* @@ -2368,11 +2534,6 @@ CTASSERT(LONG_FID_LEN <= sizeof(struct fid)); #ifdef __FreeBSD_kernel__ static int zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, int flags, vnode_t **vpp) -#endif -#ifdef __NetBSD__ -static int -zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp) -#endif { struct componentname cn; zfsvfs_t *zfsvfs = vfsp->vfs_data; @@ -2386,13 +2547,8 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp) *vpp = NULL; -#ifdef __NetBSD__ - return (SET_ERROR(ENOTSUP)); -#endif - ZFS_ENTER(zfsvfs); -#ifdef __FreeBSD_kernel__ /* * On FreeBSD we can get snapshot's mount point or its parent file * system mount point depending if snapshot is already mounted or not. @@ -2465,7 +2621,7 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp) } return (err); } -#endif + gen_mask = -1ULL >> (64 - 8 * i); dprintf("getting %llu [%u mask %llx]\n", object, fid_gen, gen_mask); @@ -2487,15 +2643,14 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp) *vpp = ZTOV(zp); ZFS_EXIT(zfsvfs); -#ifdef __FreeBSD_kernel__ err = vn_lock(*vpp, flags); if (err == 0) vnode_create_vobject(*vpp, zp->z_size, curthread); else *vpp = NULL; -#endif return (err); } +#endif /* __FreeBSD_kernel__ */ /* * Block out VOPs and close zfsvfs_t::z_os