diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h
index 2e1f9847f34c..565efd173b75 100644
--- a/include/sys/dsl_dataset.h
+++ b/include/sys/dsl_dataset.h
@@ -268,6 +268,10 @@ typedef struct dsl_dataset {
/* Protected by ds_lock; keep at end of struct for better locality */
char ds_snapname[ZFS_MAX_DATASET_NAME_LEN];
+
+#ifdef __FreeBSD__
+ char *ds_jailname;
+#endif
} dsl_dataset_t;
static inline dsl_dataset_phys_t *
diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h
index 49ab9d3db795..13db73f39204 100644
--- a/include/sys/fs/zfs.h
+++ b/include/sys/fs/zfs.h
@@ -203,6 +203,7 @@ typedef enum {
ZFS_PROP_DEFAULTUSEROBJQUOTA,
ZFS_PROP_DEFAULTGROUPOBJQUOTA,
ZFS_PROP_DEFAULTPROJECTOBJQUOTA,
+ ZFS_PROP_ZONE,
ZFS_NUM_PROPS
} zfs_prop_t;
diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi
index 184ea4a55b43..45a78cb5ac6a 100644
--- a/lib/libzfs/libzfs.abi
+++ b/lib/libzfs/libzfs.abi
@@ -2259,7 +2259,8 @@
-
+
+
diff --git a/man/man7/zfsprops.7 b/man/man7/zfsprops.7
index 77e994b912b6..145cbf7037d2 100644
--- a/man/man7/zfsprops.7
+++ b/man/man7/zfsprops.7
@@ -2095,6 +2095,16 @@ for more information.
Jails are a
.Fx
feature and this property is not available on other platforms.
+.It Sy jail
+This read-only property reports name of the jail that mounted the jailed
+dataset.
+The "0" name is used for datasets that are not mounted or not jailed.
+This differs from the normal ZFS convention to print dash ('-') for unset
+values, since it can be a valid jail name.
+If the jail is renamed, the property will still report its old name from
+the time the dataset was mounted.
+The reported jail may no longer exist, while the dataset remains mounted.
+The property is not revealed to jails themselves, the "0" is reported instead.
.It Sy zoned Ns = Ns Sy off Ns | Ns Sy on
Controls whether the dataset is managed from a non-global zone or namespace.
See
diff --git a/module/os/freebsd/zfs/zfs_vfsops.c b/module/os/freebsd/zfs/zfs_vfsops.c
index 79b784288911..32d4fb7de9d4 100644
--- a/module/os/freebsd/zfs/zfs_vfsops.c
+++ b/module/os/freebsd/zfs/zfs_vfsops.c
@@ -1310,6 +1310,18 @@ zfs_domount(vfs_t *vfsp, char *osname)
if (!zfsvfs->z_issnap)
zfsctl_create(zfsvfs);
+
+#ifdef __FreeBSD__
+ if (error == 0) {
+ /* zone dataset visiblity was checked before in zfs_mount() */
+ struct prison *pr = curthread->td_ucred->cr_prison;
+ if (pr != &prison0) {
+ zfsvfs->z_os->os_dsl_dataset->ds_jailname =
+ kmem_strdup(pr->pr_name);
+ }
+ }
+#endif
+
out:
if (error) {
dmu_objset_disown(zfsvfs->z_os, B_TRUE, zfsvfs);
@@ -1783,6 +1795,12 @@ zfs_umount(vfs_t *vfsp, int fflag)
dmu_objset_set_user(os, NULL);
mutex_exit(&os->os_user_ptr_lock);
+#ifdef __FreeBSD__
+ if (os->os_dsl_dataset->ds_jailname)
+ kmem_strfree(os->os_dsl_dataset->ds_jailname);
+ os->os_dsl_dataset->ds_jailname = NULL;
+#endif
+
/*
* Finally release the objset
*/
diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c
index 864e3898b365..b58e94ce347b 100644
--- a/module/zcommon/zfs_prop.c
+++ b/module/zcommon/zfs_prop.c
@@ -516,9 +516,13 @@ zfs_prop_init(void)
zprop_register_index(ZFS_PROP_ZONED, "jailed", 0, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM, "on | off", "JAILED", boolean_table,
sfeatures);
+ zprop_register_string(ZFS_PROP_ZONE, "jail", NULL, PROP_READONLY,
+ ZFS_TYPE_FILESYSTEM, " | 0", "JAIL", sfeatures);
#else
zprop_register_index(ZFS_PROP_ZONED, "zoned", 0, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM, "on | off", "ZONED", boolean_table, sfeatures);
+ zprop_register_string(ZFS_PROP_ZONE, "zone", NULL, PROP_READONLY,
+ ZFS_TYPE_FILESYSTEM, "", "ZONE", sfeatures);
#endif
zprop_register_index(ZFS_PROP_VSCAN, "vscan", 0, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM, "on | off", "VSCAN", boolean_table, sfeatures);
diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c
index 51f624da5689..65323f8268d5 100644
--- a/module/zfs/dsl_prop.c
+++ b/module/zfs/dsl_prop.c
@@ -1230,6 +1230,15 @@ dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
goto out;
}
+#ifdef __FreeBSD__
+ nvlist_t *propval = fnvlist_alloc();
+ fnvlist_add_string(propval, ZPROP_VALUE,
+ (ds->ds_jailname && INGLOBALZONE(curproc)) ?
+ ds->ds_jailname : "0");
+ fnvlist_add_nvlist(*nvp, "jail", propval);
+ nvlist_free(propval);
+#endif
+
for (; dd != NULL; dd = dd->dd_parent) {
if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
if (flags & (DSL_PROP_GET_LOCAL |
diff --git a/tests/runfiles/freebsd.run b/tests/runfiles/freebsd.run
index ae39cb532dd0..03c1f0b048d8 100644
--- a/tests/runfiles/freebsd.run
+++ b/tests/runfiles/freebsd.run
@@ -23,7 +23,7 @@ failsafe = callbacks/zfs_failsafe
tags = ['functional']
[tests/functional/cli_root/zfs_jail:FreeBSD]
-tests = ['zfs_jail_001_pos']
+tests = ['zfs_jail_001_pos', 'zfs_jail_property']
tags = ['functional', 'cli_root', 'zfs_jail']
[tests/functional/pam:FreeBSD]
diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am
index 1517f90e99a5..6d00c666c5d8 100644
--- a/tests/zfs-tests/tests/Makefile.am
+++ b/tests/zfs-tests/tests/Makefile.am
@@ -761,6 +761,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zfs_jail/cleanup.ksh \
functional/cli_root/zfs_jail/setup.ksh \
functional/cli_root/zfs_jail/zfs_jail_001_pos.ksh \
+ functional/cli_root/zfs_jail/zfs_jail_property.ksh \
functional/cli_root/zfs_load-key/cleanup.ksh \
functional/cli_root/zfs_load-key/setup.ksh \
functional/cli_root/zfs_load-key/zfs_load-key_all.ksh \
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_jail/zfs_jail_001_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_jail/zfs_jail_001_pos.ksh
index 7ce03a4b9047..6f4c0aa4cbe5 100755
--- a/tests/zfs-tests/tests/functional/cli_root/zfs_jail/zfs_jail_001_pos.ksh
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_jail/zfs_jail_001_pos.ksh
@@ -35,7 +35,7 @@
# 1. Create a jail.
# 2. Perform some basic ZFS operations on a dataset both in the host and
# in the jail to confirm the dataset is functional in the host
-# and hidden in in the jail.
+# and hidden in the jail.
# 3. Run `zfs jail` to expose the dataset in the jail.
# 4. Perform some basic ZFS operations on the dataset both in the host and
# in the jail to confirm the dataset is functional in the jail and host.
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_jail/zfs_jail_property.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_jail/zfs_jail_property.ksh
new file mode 100755
index 000000000000..20ff75d9b790
--- /dev/null
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_jail/zfs_jail_property.ksh
@@ -0,0 +1,90 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2025 SkunkWerks, GmbH
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Test basic use cases of "jail" zfs dataset property.
+#
+# STRATEGY:
+# 1. Create a dataset. Verify.
+# 2. Create a jail. Verify.
+# 3. Jail the dataset. Verify.
+# 4. Mount the dataset by the jail. Verify.
+# 5. Unmount the dataset. Verify.
+#
+
+verify_runnable "global"
+
+JAIL="testjail"
+JAIL_CONF="$STF_SUITE/tests/functional/cli_root/zfs_jail/jail.conf"
+DATASET="$TESTPOOL/dataset1"
+DATASET_JAILED_MOUNTPOINT="/jailed"
+
+function cleanup
+{
+ if jls -j $JAIL name >/dev/null 2>&1; then
+ jail -r -f $JAIL_CONF $JAIL
+ fi
+}
+
+log_onexit cleanup
+
+log_assert "Verify basic use cases of jail zfs property."
+
+# Root dataset has default value
+log_must test "0" = "$(zfs get -o value -H jail $TESTPOOL)"
+
+# Create the dataset
+log_must zfs create -o jailed=on -o mountpoint=$DATASET_JAILED_MOUNTPOINT $DATASET
+log_must test "0" = "$(zfs get -o value -H jail $DATASET)"
+
+# Create the jail
+log_must jail -c -f $JAIL_CONF $JAIL
+log_mustnot jexec $JAIL zfs list $DATASET
+log_must test "0" = "$(zfs get -o value -H jail $DATASET)"
+
+# Jail the dataset
+log_must zfs jail $JAIL $DATASET
+log_must jexec $JAIL zfs list $DATASET
+log_must test "0" = "$(zfs get -o value -H jail $DATASET)"
+log_must test "0" = "$(jexec $JAIL zfs get -o value -H jail $DATASET)"
+
+# Mount the dataset by the jail
+log_must jexec $JAIL zfs mount $DATASET
+# Now we see who mounted it
+log_must test "$JAIL" = "$(zfs get -o value -H jail $DATASET)"
+# But it is hidden from the jail itself
+log_must test "0" = "$(jexec $JAIL zfs get -o value -H jail $DATASET)"
+
+# Unmount the dataset by the jail
+log_must jexec $JAIL zfs unmount $DATASET
+log_must test "0" = "$(zfs get -o value -H jail $DATASET)"
+log_must test "0" = "$(jexec $JAIL zfs get -o value -H jail $DATASET)"
+
+log_pass "Verify basic use cases of jail zfs property."