libzfs: use mount_setattr for selective remount including legacy mounts

When a namespace property is changed via zfs set, libzfs remounts the
filesystem to propagate the new VFS mount flags. The current approach
uses mount(2) with MS_REMOUNT, which reads all namespace properties
from ZFS and applies them together. This has two problems:

1. Linux VFS resets unspecified per-mount flags on remount. If an
   administrator sets a temporary flag (e.g. mount -o remount,noatime),
   a subsequent zfs set on any namespace property clobbers it.

2. Two concurrent zfs set operations on different namespace properties
   can overwrite each other's mount flags.

Additionally, legacy datasets (mountpoint=legacy) were never remounted
on namespace property changes since zfs_is_mountable() returns false
for them.

Add zfs_mount_setattr() which uses mount_setattr(2) to selectively
update only the mount flags that correspond to the changed property.
For legacy datasets, /proc/mounts is iterated to update all
mountpoints. On kernels without mount_setattr (ENOSYS), non-legacy
datasets fall back to a full remount; legacy mounts are skipped to
avoid clobbering temporary flags.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com>
Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
Closes #18257
This commit is contained in:
Ameer Hamza
2026-03-09 23:06:22 +05:00
committed by Tony Hutter
parent a94b137aac
commit cb2e2f9c4f
7 changed files with 247 additions and 26 deletions
+17
View File
@@ -90,6 +90,19 @@ struct zfs_handle {
uint8_t *zfs_props_table;
};
/*
* Internal namespace property flags for selective remount via
* mount_setattr(2). Passed to zfs_mount_setattr().
*/
#define ZFS_MNT_PROP_ATIME (1U << 0)
#define ZFS_MNT_PROP_RELATIME (1U << 1)
#define ZFS_MNT_PROP_DEVICES (1U << 2)
#define ZFS_MNT_PROP_EXEC (1U << 3)
#define ZFS_MNT_PROP_SETUID (1U << 4)
#define ZFS_MNT_PROP_READONLY (1U << 5)
#define ZFS_MNT_PROP_XATTR (1U << 6)
#define ZFS_MNT_PROP_NBMAND (1U << 7)
/*
* This is different from checking zfs_type, because it will also catch
* snapshots of volumes.
@@ -182,6 +195,10 @@ extern prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int,
extern int changelist_unshare(prop_changelist_t *, const enum sa_protocol *);
extern int changelist_haszonedchild(prop_changelist_t *);
extern boolean_t zfs_is_namespace_prop(zfs_prop_t);
extern uint32_t zfs_namespace_prop_flag(zfs_prop_t);
extern boolean_t zfs_is_mountable_internal(zfs_handle_t *);
extern int zfs_mount_setattr(zfs_handle_t *, uint32_t);
extern void remove_mountpoint(zfs_handle_t *);
extern int create_parents(libzfs_handle_t *, char *, int);