Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c (revision 205115) +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c (working copy) @@ -4963,6 +4963,45 @@ zfs_freebsd_aclcheck(ap) return (EOPNOTSUPP); } +static int +zfs_vptocnp(struct vop_vptocnp_args *ap) +{ + struct vop_vptocnp_args args; + struct vnode *coveredvp; + struct vnode *vp = ap->a_vp; + zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; + int error, locked; + + ZFS_ENTER(zfsvfs); + + if (zfsvfs->z_issnap && VTOZ(vp)->z_id == zfsvfs->z_root) { + coveredvp = zfsvfs->z_vfs->mnt_vnodecovered; + ASSERT(vp != coveredvp); + + VREF(vp); + locked = VOP_ISLOCKED(vp); + VOP_UNLOCK(vp, 0); + + vn_lock(coveredvp, LK_SHARED | LK_RETRY); + args = *ap; + args.a_vp = coveredvp; + + ZFS_EXIT(zfsvfs); + + error = zfsctl_snapshot_vptocnp(&args); + + VOP_UNLOCK(coveredvp, 0); + vn_lock(vp, locked | LK_RETRY); + vrele(vp); + + return (error); + } + + ZFS_EXIT(zfsvfs); + + return (vop_stdvptocnp(ap)); +} + struct vop_vector zfs_vnodeops; struct vop_vector zfs_fifoops; @@ -5005,6 +5044,7 @@ struct vop_vector zfs_vnodeops = { .vop_getacl = zfs_freebsd_getacl, .vop_setacl = zfs_freebsd_setacl, .vop_aclcheck = zfs_freebsd_aclcheck, + .vop_vptocnp = zfs_vptocnp, }; struct vop_vector zfs_fifoops = { Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c (revision 205115) +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c (working copy) @@ -461,6 +461,62 @@ zfsctl_freebsd_root_lookup(ap) return (err); } +static int +zfsctl_common_vptocnp(struct vop_vptocnp_args *ap) +{ + struct vnode *dvp; + struct vnode *vp = ap->a_vp; + zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; + size_t namelen; + char *name; + znode_t *rootzp; + int error; + + error = 0; + name = NULL; + + ZFS_ENTER(zfsvfs); + + switch (gfs_file_inode(vp)) { + case ZFSCTL_INO_ROOT: + error = zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp); + if (error == 0 && zfs_has_ctldir(rootzp) == 0) { + VN_RELE(ZTOV(rootzp)); + error = ENOENT; + } + if (error != 0) + break; + name = ZFS_CTLDIR_NAME; + dvp = ZTOV(rootzp); + vhold(dvp); + VN_RELE(dvp); + break; + case ZFSCTL_INO_SNAPDIR: + name = "snapshot"; + dvp = zfsvfs->z_ctldir; + vhold(dvp); + break; + } + + ZFS_EXIT(zfsvfs); + + if (error != 0) + return (error); + + if (name != NULL) { + namelen = strlen(name); + if (*ap->a_buflen < namelen) { + vdrop(dvp); + return (ENOMEM); + } + *ap->a_buflen -= namelen; + bcopy(name, ap->a_buf + *ap->a_buflen, namelen); + *ap->a_vpp = dvp; + return (0); + } else + return (vop_stdvptocnp(ap)); +} + static struct vop_vector zfsctl_ops_root = { .vop_default = &default_vnodeops, .vop_open = zfsctl_common_open, @@ -473,6 +529,7 @@ static struct vop_vector zfsctl_ops_root .vop_inactive = gfs_vop_inactive, .vop_reclaim = zfsctl_common_reclaim, .vop_fid = zfsctl_common_fid, + .vop_vptocnp = zfsctl_common_vptocnp, }; static int @@ -1041,6 +1098,7 @@ static struct vop_vector zfsctl_ops_snap .vop_inactive = zfsctl_snapdir_inactive, .vop_reclaim = zfsctl_common_reclaim, .vop_fid = zfsctl_common_fid, + .vop_vptocnp = zfsctl_common_vptocnp, }; /* @@ -1211,7 +1269,7 @@ zfsctl_snapshot_lookup(ap) return (error); } -static int +int zfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap) { zfsvfs_t *zfsvfs = ap->a_vp->v_vfsp->vfs_data; @@ -1242,11 +1300,16 @@ zfsctl_snapshot_vptocnp(struct vop_vptoc size_t len; len = strlen(sep->se_name); - *ap->a_buflen -= len; - bcopy(sep->se_name, ap->a_buf + *ap->a_buflen, len); - mutex_exit(&sdp->sd_lock); - vhold(dvp); - *ap->a_vpp = dvp; + if (*ap->a_buflen < len) { + mutex_exit(&sdp->sd_lock); + error = ENOMEM; + } else { + *ap->a_buflen -= len; + bcopy(sep->se_name, ap->a_buf + *ap->a_buflen, len); + mutex_exit(&sdp->sd_lock); + vhold(dvp); + *ap->a_vpp = dvp; + } } VN_RELE(dvp); Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h (revision 205115) +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h (working copy) @@ -61,6 +61,8 @@ int zfsctl_root_lookup(vnode_t *dvp, cha int zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp); +int zfsctl_snapshot_vptocnp(struct vop_vptocnp_args *); + #define ZFSCTL_INO_ROOT 0x1 #define ZFSCTL_INO_SNAPDIR 0x2