Skip to content

Conversation

ihoro
Copy link
Contributor

@ihoro ihoro commented Sep 21, 2025

Sponsored-by: SkunkWerks, GmbH

Motivation and Context

It targets #15710 feature request to add a read-only property to report name of the jail that mounted the dataset.

Description

The decisions made:

  • The 0 name is used for datasets that are not mounted or not jailed. The default zfs style is to use - for a missing value, but it's allowed to have a jail named like that. At the same time there is no way to name a jail as 0: jail: name cannot be numeric (unless it is the jid).
  • The mechanism remembers the name only, not jid. It can be treated as a caching mechanism to avoid time complexity increase. The reason is that all properties are prepared before listing only requested ones, and traversing all prisons (with allprison_lock) to lookup jail name by jid does not feel good for the cases with many jailed datasets and/or jails.
  • Because of the above, jail renaming is not supported -- it will still report the old name.
  • Nested jails are not supported for simplicity -- only non-jailed root can see actual value of the jail property, others are provided with 0. Such way it covers the requirement not to reveal jail name to the jail itself.
  • As long as the name is cached, it's okay to have a situation when the dataset is still mounted even though the jail reported by this property is no longer present. It's not expected to be a usual case.
  • The zfsprops.7 man page was extended to outline the property. It is mentioned within the section of tunables even though it is a read-only one, it seems to be better to keep it closer to the jailed property.

Hence, the mechanism is simple:

  • zfs_domount() caches pr_name
  • zfs_umount() clears the name

The proposed implementation covers usual cases without extra complexity and property retrieval performance impact. The opportunities for improvements are left for the future.

How Has This Been Tested?

Originally the patch was created months ago for 15-CURRENT, it was re-tested for the latest 16-CURRENT. The UI/UX demonstration:

# cat /etc/jail.conf
jail1 {
        host.hostname = "jail1.local";
        path = "/root/tmp/jailroot_15current_1";
        persist = true;
        mount.devfs = true;
        allow.mount = true;
        allow.mount.zfs = true;
        enforce_statfs = 1;
        exec.created = "/sbin/zfs jail jail1 p3/dataset2";
        exec.start = "/bin/sh /etc/rc.d/zfs start";
        exec.stop = "/bin/sh /etc/rc.d/zfs stop";
        exec.poststop = "/sbin/zfs unjail jail1 p3/dataset2";
        children.max = 99;
}

# zpool import -d tmp/p3 p3

# zfs list -o name,mountpoint,mounted,jailed,jail
NAME         MOUNTPOINT     MOUNTED  JAILED  JAIL
p3           /p3            yes      off     0
p3/dataset1  /p3/dataset1   yes      off     0
p3/dataset2  /dataset2_mnt  no       on      0
p3/dataset3  /dataset3_mnt  no       on      0

# service jail onestart jail1

# zfs list -o name,mountpoint,mounted,jailed,jail
NAME         MOUNTPOINT     MOUNTED  JAILED  JAIL
p3           /p3            yes      off     0
p3/dataset1  /p3/dataset1   yes      off     0
p3/dataset2  /dataset2_mnt  yes      on      jail1
p3/dataset3  /dataset3_mnt  no       on      0

# jexec jail1 zfs list -o name,mountpoint,mounted,jailed,jail
NAME         MOUNTPOINT     MOUNTED  JAILED  JAIL
p3           /p3            no       off     0
p3/dataset2  /dataset2_mnt  yes      on      0

# jexec jail1 jail -c persist name=child allow.mount=true allow.mount.zfs=true enforce_statfs=1
# zfs jail jail1.child p3/dataset3
# jexec jail1.child zfs mount p3/dataset3

# jexec jail1.child zfs list -o name,mountpoint,mounted,jailed,jail
NAME         MOUNTPOINT     MOUNTED  JAILED  JAIL
p3           /p3            yes      off     0
p3/dataset3  /dataset3_mnt  yes      on      0

# jexec jail1 zfs list -o name,mountpoint,mounted,jailed,jail
NAME         MOUNTPOINT     MOUNTED  JAILED  JAIL
p3           /p3            no       off     0
p3/dataset2  /dataset2_mnt  yes      on      0

# zfs list -o name,mountpoint,mounted,jailed,jail
NAME         MOUNTPOINT     MOUNTED  JAILED  JAIL
p3           /p3            yes      off     0
p3/dataset1  /p3/dataset1   yes      off     0
p3/dataset2  /dataset2_mnt  yes      on      jail1
p3/dataset3  /dataset3_mnt  yes      on      jail1.child

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance enhancement (non-breaking change which improves efficiency)
  • Code cleanup (non-breaking change which makes code smaller or more readable)
  • Quality assurance (non-breaking change which makes the code more robust against bugs)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Library ABI change (libzfs, libzfs_core, libnvpair, libuutil and libzfsbootenv)
  • Documentation (a change to man pages or other documentation)

Checklist:

@ikozhukhov
Copy link
Contributor

under illumos based platform we have zone property. probably we can prepare and use universal name for all platforms ?
zones are virtual environment where we can provide dataset and exclude it from global zone and others.
I think we can use zone property or rename it to more universal/applicable name and use it.
I see duplicate logic for the same properties.

A read-only property to report name of the jail that mounted the
dataset.

Sponsored-by: SkunkWerks, GmbH
Signed-off-by: Igor Ostapenko <pm@igoro.pro>
@ihoro ihoro force-pushed the 0064-zfs-jail-prop branch from 9a8e5cb to a5e0913 Compare September 21, 2025 13:14
@ihoro
Copy link
Contributor Author

ihoro commented Sep 21, 2025

under illumos based platform we have zone property. probably we can prepare and use universal name for all platforms ? zones are virtual environment where we can provide dataset and exclude it from global zone and others. I think we can use zone property or rename it to more universal/applicable name and use it. I see duplicate logic for the same properties.

Thanks for taking this moment into consideration. Indeed, the cross-platform term in the codebase is zone, and it's turned out that in the past the decision was made to follow FreeBSD specific terminology when FreeBSD Jails support was added. Hence, we have already established interface with "jail" word: zfs jail, zfs unjail, zfs get jailed, zfs list -o jailed, etc. As long as it is directly related to the existing jailed feature, the FreeBSD users expect to have this new property named jail, otherwise it could be misleading.

This read-only property reports the name of the jail that mounted the jailed
dataset.
The "0" name is used for datasets that are not mounted or not jailed.
If a jail is renamed, the property will still report its old name from
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention the reasoning for "0". What do you think of?:

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 '-' can be a valid jail name.

@tonyhutter
Copy link
Contributor

  1. I saw this in the JSON output (zfs list -j ...):
        "jail": {
          "value": "0",
          "source": {
            "type": "LOCAL",
            "data": "-"
          }
        }

I would have expected type to be NONE since this is read-only.

  1. Could you update tests/zfs-tests/tests/functional/cli_root/zfs_jail/zfs_jail_001_pos.ksh with some simple tests to verify zfs list -o jail ... works?

@behlendorf behlendorf added the Status: Code Review Needed Ready for review and testing label Sep 25, 2025
zfsvfs->z_os->os_dsl_dataset->ds_jailname =
kmem_zalloc(strlen(pr->pr_name) + 1, KM_SLEEP);
strcpy(zfsvfs->z_os->os_dsl_dataset->ds_jailname,
pr->pr_name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use kmem_strdup(pr->pr_name); to simplify this.

(ds->ds_jailname && INGLOBALZONE(curproc)) ?
ds->ds_jailname : "0"));
VERIFY0(nvlist_add_string(propval, ZPROP_SOURCE, setpoint));
VERIFY0(nvlist_add_nvlist(*nvp, "jail", propval));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fnvlist_* wrappers should be used here, or better yet add the required error handling even if they're almost certain never to fail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Code Review Needed Ready for review and testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants