summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorRyan Moeller <[email protected]>2020-09-01 19:14:16 -0400
committerBrian Behlendorf <[email protected]>2020-09-03 16:16:15 -0700
commit76a157f00408cbd686b1f270babedfbbf7a3fd3c (patch)
treec1bad06dc5cf1dc85f4340719d5f639d10c24310 /module
parent6512c18fe1b439a7f3db8aff17623499d866185e (diff)
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 <[email protected]> Reviewed-by: Allan Jude <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Ported by: Matt Macy <[email protected]> Signed-off-by: Ryan Moeller <[email protected]> Closes #10839
Diffstat (limited to 'module')
-rw-r--r--module/os/linux/zfs/zfs_vfsops.c10
-rw-r--r--module/os/linux/zfs/zpl_super.c20
-rw-r--r--module/zfs/dsl_dir.c6
-rw-r--r--module/zfs/zfs_ioctl.c3
4 files changed, 35 insertions, 4 deletions
diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c
index db831bf54..389200b52 100644
--- a/module/os/linux/zfs/zfs_vfsops.c
+++ b/module/os/linux/zfs/zfs_vfsops.c
@@ -2126,6 +2126,16 @@ zfs_get_vfs_flag_unmounted(objset_t *os)
return (unmounted);
}
+/*ARGSUSED*/
+void
+zfsvfs_update_fromname(const char *oldname, const char *newname)
+{
+ /*
+ * We don't need to do anything here, the devname is always current by
+ * virtue of zfsvfs->z_sb->s_op->show_devname.
+ */
+}
+
void
zfs_init(void)
{
diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c
index 75adff517..333c64746 100644
--- a/module/os/linux/zfs/zpl_super.c
+++ b/module/os/linux/zfs/zpl_super.c
@@ -183,6 +183,25 @@ zpl_remount_fs(struct super_block *sb, int *flags, char *data)
}
static int
+__zpl_show_devname(struct seq_file *seq, zfsvfs_t *zfsvfs)
+{
+ char *fsname;
+
+ fsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
+ dmu_objset_name(zfsvfs->z_os, fsname);
+ seq_puts(seq, fsname);
+ kmem_free(fsname, ZFS_MAX_DATASET_NAME_LEN);
+
+ return (0);
+}
+
+static int
+zpl_show_devname(struct seq_file *seq, struct dentry *root)
+{
+ return (__zpl_show_devname(seq, root->d_sb->s_fs_info));
+}
+
+static int
__zpl_show_options(struct seq_file *seq, zfsvfs_t *zfsvfs)
{
seq_printf(seq, ",%s",
@@ -314,6 +333,7 @@ const struct super_operations zpl_super_operations = {
.sync_fs = zpl_sync_fs,
.statfs = zpl_statfs,
.remount_fs = zpl_remount_fs,
+ .show_devname = zpl_show_devname,
.show_options = zpl_show_options,
.show_stats = NULL,
};
diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c
index 29672e9a6..90dd78702 100644
--- a/module/zfs/dsl_dir.c
+++ b/module/zfs/dsl_dir.c
@@ -46,14 +46,12 @@
#include <sys/sunddi.h>
#include <sys/zfeature.h>
#include <sys/policy.h>
+#include <sys/zfs_vfsops.h>
#include <sys/zfs_znode.h>
#include <sys/zvol.h>
#include <sys/zthr.h>
#include "zfs_namecheck.h"
#include "zfs_prop.h"
-#ifdef _KERNEL
-#include <sys/zfs_vfsops.h>
-#endif
/*
* Filesystem and Snapshot Limits
@@ -2124,6 +2122,8 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
VERIFY0(zap_add(mos, dsl_dir_phys(newparent)->dd_child_dir_zapobj,
dd->dd_myname, 8, 1, &dd->dd_object, tx));
+ /* TODO: A rename callback to avoid these layering violations. */
+ zfsvfs_update_fromname(ddra->ddra_oldname, ddra->ddra_newname);
zvol_rename_minors(dp->dp_spa, ddra->ddra_oldname,
ddra->ddra_newname, B_TRUE);
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index 7f623bb04..495ff4707 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -4316,6 +4316,7 @@ zfs_ioc_rename(zfs_cmd_t *zc)
objset_t *os;
dmu_objset_type_t ost;
boolean_t recursive = zc->zc_cookie & 1;
+ boolean_t nounmount = !!(zc->zc_cookie & 2);
char *at;
int err;
@@ -4341,7 +4342,7 @@ zfs_ioc_rename(zfs_cmd_t *zc)
if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1))
return (SET_ERROR(EXDEV));
*at = '\0';
- if (ost == DMU_OST_ZFS) {
+ if (ost == DMU_OST_ZFS && !nounmount) {
error = dmu_objset_find(zc->zc_name,
recursive_unmount, at + 1,
recursive ? DS_FIND_CHILDREN : 0);