Add 'zfs rename -u' to rename without remounting

Allow to rename file systems without remounting if it is possible.
It is possible for file systems with 'mountpoint' property set to
'legacy' or 'none' - we don't have to change mount directory for them.
Currently such file systems are unmounted on rename and not even
mounted back.

This introduces layering violation, as we need to update
'f_mntfromname' field in statfs structure related to mountpoint (for
the dataset we are renaming and all its children).

In my opinion it is worth it, as it allow to update FreeBSD in even
cleaner way - in ZFS-only configuration root file system is ZFS file
system with 'mountpoint' property set to 'legacy'. If root dataset is
named system/rootfs, we can snapshot it (system/rootfs@upgrade), clone
it (system/oldrootfs), update FreeBSD and if it doesn't boot we can
boot back from system/oldrootfs and rename it back to system/rootfs
while it is mounted as /. Before it was not possible, because
unmounting / was not possible.

Authored by: Pawel Jakub Dawidek <pjd@FreeBSD.org>
Reviewed-by: Allan Jude <allan@klarasystems.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Ported by: Matt Macy <mmacy@freebsd.org>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes #10839
This commit is contained in:
Ryan Moeller
2020-09-01 19:14:16 -04:00
committed by Brian Behlendorf
parent 6512c18fe1
commit 76a157f004
21 changed files with 284 additions and 39 deletions
@@ -18,7 +18,8 @@ dist_pkgdata_SCRIPTS = \
zfs_rename_014_neg.ksh \
zfs_rename_encrypted_child.ksh \
zfs_rename_to_encrypted.ksh \
zfs_rename_mountpoint.ksh
zfs_rename_mountpoint.ksh \
zfs_rename_nounmount.ksh
dist_pkgdata_DATA = \
zfs_rename.cfg \
@@ -34,8 +34,8 @@ verify_runnable "both"
function rename_cleanup
{
log_note zfs destroy -fR $TESTPOOL/rename_test
log_note zfs destroy -fR $TESTPOOL/renamed
zfs destroy -fR $TESTPOOL/rename_test
zfs destroy -fR $TESTPOOL/renamed
}
log_onexit rename_cleanup
@@ -0,0 +1,93 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy is of the CDDL is also available via the Internet
# at http://www.illumos.org/license/CDDL.
#
# CDDL HEADER END
#
#
# Copyright (c) 2019 iXsystems, Inc.
#
. $STF_SUITE/include/libtest.shlib
#
# DESCRIPTION:
# zfs rename -u should rename datasets without unmounting them
#
# STRATEGY:
# 1. Create a set of nested datasets.
# 2. Verify datasets are mounted.
# 3. Rename with -u and verify all datasets stayed mounted.
#
verify_runnable "both"
function rename_cleanup
{
cd $back
zfs destroy -fR $TESTPOOL/rename_test
zfs destroy -fR $TESTPOOL/renamed
}
back=$(pwd)
log_onexit rename_cleanup
log_must zfs create $TESTPOOL/rename_test
log_must zfs create $TESTPOOL/rename_test/child
log_must zfs create $TESTPOOL/rename_test/child/grandchild
if ! ismounted $TESTPOOL/rename_test; then
log_fail "$TESTPOOL/rename_test is not mounted"
fi
if ! ismounted $TESTPOOL/rename_test/child; then
log_fail "$TESTPOOL/rename_test/child is not mounted"
fi
if ! ismounted $TESTPOOL/rename_test/child/grandchild; then
log_fail "$TESTPOOL/rename_test/child/grandchild is not mounted"
fi
mntp_p=$(get_prop mountpoint $TESTPOOL/rename_test)
mntp_c=$(get_prop mountpoint $TESTPOOL/rename_test/child)
mntp_g=$(get_prop mountpoint $TESTPOOL/rename_test/child/grandchild)
log_must cd $mntp_g
log_mustnot zfs rename $TESTPOOL/rename_test $TESTPOOL/renamed
log_must zfs rename -u $TESTPOOL/rename_test $TESTPOOL/renamed
log_mustnot zfs list $TESTPOOL/rename_test
log_mustnot zfs list $TESTPOOL/rename_test/child
log_mustnot zfs list $TESTPOOL/rename_test/child/grandchild
log_must zfs list $TESTPOOL/renamed
log_must zfs list $TESTPOOL/renamed/child
log_must zfs list $TESTPOOL/renamed/child/grandchild
missing=$(zfs mount | awk -v pat=$TESTPOOL/renamed '$1 ~ pat' | awk \
-v mntp_p=$mntp_p \
-v mntp_c=$mntp_c \
-v mntp_g=$mntp_g '
BEGIN { p = c = g = 0 }
$2 == mntp_p { p = 1 }
$2 == mntp_c { c = 1 }
$2 == mntp_g { g = 1 }
END {
if (p != 1)
print mntp_p
if (c != 1)
print mntp_c
if (g != 1)
print mntp_g
}')
[[ -z "$missing" ]] || log_fail "Mountpoints no longer mounted: $missing"
log_pass "Verified rename -u does not unmount datasets"