Skip to content

Commit 7b4e272

Browse files
author
Ryan Moeller
authored
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
1 parent 88d19d7 commit 7b4e272

File tree

21 files changed

+284
-39
lines changed

21 files changed

+284
-39
lines changed

cmd/zfs/zfs_main.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,8 @@ get_usage(zfs_help_t idx)
311311
case HELP_RENAME:
312312
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
313313
"<filesystem|volume|snapshot>\n"
314-
"\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
314+
"\trename -p [-f] <filesystem|volume> <filesystem|volume>\n"
315+
"\trename -u [-f] <filesystem> <filesystem>\n"
315316
"\trename -r <snapshot> <snapshot>\n"));
316317
case HELP_ROLLBACK:
317318
return (gettext("\trollback [-rRf] <snapshot>\n"));
@@ -3603,36 +3604,40 @@ zfs_do_list(int argc, char **argv)
36033604
}
36043605

36053606
/*
3606-
* zfs rename [-f] <fs | snap | vol> <fs | snap | vol>
3607+
* zfs rename [-fu] <fs | snap | vol> <fs | snap | vol>
36073608
* zfs rename [-f] -p <fs | vol> <fs | vol>
3608-
* zfs rename -r <snap> <snap>
3609+
* zfs rename [-u] -r <snap> <snap>
36093610
*
36103611
* Renames the given dataset to another of the same type.
36113612
*
36123613
* The '-p' flag creates all the non-existing ancestors of the target first.
3614+
* The '-u' flag prevents file systems from being remounted during rename.
36133615
*/
36143616
/* ARGSUSED */
36153617
static int
36163618
zfs_do_rename(int argc, char **argv)
36173619
{
36183620
zfs_handle_t *zhp;
3621+
renameflags_t flags = { 0 };
36193622
int c;
36203623
int ret = 0;
3621-
boolean_t recurse = B_FALSE;
3624+
int types;
36223625
boolean_t parents = B_FALSE;
3623-
boolean_t force_unmount = B_FALSE;
36243626

36253627
/* check options */
3626-
while ((c = getopt(argc, argv, "prf")) != -1) {
3628+
while ((c = getopt(argc, argv, "pruf")) != -1) {
36273629
switch (c) {
36283630
case 'p':
36293631
parents = B_TRUE;
36303632
break;
36313633
case 'r':
3632-
recurse = B_TRUE;
3634+
flags.recursive = B_TRUE;
3635+
break;
3636+
case 'u':
3637+
flags.nounmount = B_TRUE;
36333638
break;
36343639
case 'f':
3635-
force_unmount = B_TRUE;
3640+
flags.forceunmount = B_TRUE;
36363641
break;
36373642
case '?':
36383643
default:
@@ -3661,20 +3666,32 @@ zfs_do_rename(int argc, char **argv)
36613666
usage(B_FALSE);
36623667
}
36633668

3664-
if (recurse && parents) {
3669+
if (flags.recursive && parents) {
36653670
(void) fprintf(stderr, gettext("-p and -r options are mutually "
36663671
"exclusive\n"));
36673672
usage(B_FALSE);
36683673
}
36693674

3670-
if (recurse && strchr(argv[0], '@') == 0) {
3675+
if (flags.nounmount && parents) {
3676+
(void) fprintf(stderr, gettext("-u and -p options are mutually "
3677+
"exclusive\n"));
3678+
usage(B_FALSE);
3679+
}
3680+
3681+
if (flags.recursive && strchr(argv[0], '@') == 0) {
36713682
(void) fprintf(stderr, gettext("source dataset for recursive "
36723683
"rename must be a snapshot\n"));
36733684
usage(B_FALSE);
36743685
}
36753686

3676-
if ((zhp = zfs_open(g_zfs, argv[0], parents ? ZFS_TYPE_FILESYSTEM |
3677-
ZFS_TYPE_VOLUME : ZFS_TYPE_DATASET)) == NULL)
3687+
if (flags.nounmount)
3688+
types = ZFS_TYPE_FILESYSTEM;
3689+
else if (parents)
3690+
types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
3691+
else
3692+
types = ZFS_TYPE_DATASET;
3693+
3694+
if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL)
36783695
return (1);
36793696

36803697
/* If we were asked and the name looks good, try to create ancestors. */
@@ -3684,7 +3701,7 @@ zfs_do_rename(int argc, char **argv)
36843701
return (1);
36853702
}
36863703

3687-
ret = (zfs_rename(zhp, argv[1], recurse, force_unmount) != 0);
3704+
ret = (zfs_rename(zhp, argv[1], flags) != 0);
36883705

36893706
zfs_close(zhp);
36903707
return (ret);

include/libzfs.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,19 @@ extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
642642
extern int zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps,
643643
nvlist_t *props);
644644
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
645-
extern int zfs_rename(zfs_handle_t *, const char *, boolean_t, boolean_t);
645+
646+
typedef struct renameflags {
647+
/* recursive rename */
648+
int recursive : 1;
649+
650+
/* don't unmount file systems */
651+
int nounmount : 1;
652+
653+
/* force unmount file systems */
654+
int forceunmount : 1;
655+
} renameflags_t;
656+
657+
extern int zfs_rename(zfs_handle_t *, const char *, renameflags_t);
646658

647659
typedef struct sendflags {
648660
/* Amount of extra information to print. */

include/libzfs_impl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ int zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp,
166166
* changelist_gather() flag to force it to iterate on mounted datasets only
167167
*/
168168
#define CL_GATHER_ITER_MOUNTED 2
169+
/*
170+
* Use this changelist_gather() flag to prevent unmounting of file systems.
171+
*/
172+
#define CL_GATHER_DONT_UNMOUNT 4
169173

170174
typedef struct prop_changelist prop_changelist_t;
171175

include/os/freebsd/zfs/sys/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ KERNEL_H = \
66
zfs_ctldir.h \
77
zfs_dir.h \
88
zfs_ioctl_compat.h \
9-
zfs_vfsops.h \
9+
zfs_vfsops_os.h \
1010
zfs_vnops.h \
1111
zfs_znode_impl.h \
1212
zpl.h

include/os/freebsd/zfs/sys/zfs_vfsops.h renamed to include/os/freebsd/zfs/sys/zfs_vfsops_os.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ extern boolean_t zfs_is_readonly(zfsvfs_t *zfsvfs);
168168
extern int zfs_get_temporary_prop(struct dsl_dataset *ds, zfs_prop_t zfs_prop,
169169
uint64_t *val, char *setpoint);
170170
extern int zfs_busy(void);
171-
extern void zfsvfs_update_fromname(const char *oldname, const char *newname);
172171

173172
#ifdef __cplusplus
174173
}

include/os/linux/zfs/sys/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ KERNEL_H = \
1919
zfs_context_os.h \
2020
zfs_ctldir.h \
2121
zfs_dir.h \
22-
zfs_vfsops.h \
22+
zfs_vfsops_os.h \
2323
zfs_vnops.h \
2424
zfs_znode_impl.h \
2525
zpl.h
File renamed without changes.

include/sys/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ COMMON_H = \
115115
zfs_sa.h \
116116
zfs_stat.h \
117117
zfs_sysfs.h \
118+
zfs_vfsops.h \
118119
zfs_znode.h \
119120
zil.h \
120121
zil_impl.h \

include/sys/zfs_vfsops.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9+
* or http://www.opensolaris.org/os/licensing.
10+
* See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*
13+
* When distributing Covered Code, include this CDDL HEADER in each
14+
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15+
* If applicable, add the following below this CDDL HEADER, with the
16+
* fields enclosed by brackets "[]" replaced with your own identifying
17+
* information: Portions Copyright [yyyy] [name of copyright owner]
18+
*
19+
* CDDL HEADER END
20+
*/
21+
22+
/*
23+
* Portions Copyright 2020 iXsystems, Inc.
24+
*/
25+
26+
#ifndef _SYS_ZFS_VFSOPS_H
27+
#define _SYS_ZFS_VFSOPS_H
28+
29+
#ifdef _KERNEL
30+
#include <sys/zfs_vfsops_os.h>
31+
#endif
32+
33+
extern void zfsvfs_update_fromname(const char *, const char *);
34+
35+
#endif /* _SYS_ZFS_VFSOPS_H */

lib/libzfs/libzfs_changelist.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ changelist_prefix(prop_changelist_t *clp)
128128
*/
129129
switch (clp->cl_prop) {
130130
case ZFS_PROP_MOUNTPOINT:
131+
if (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)
132+
break;
131133
if (zfs_unmount(cn->cn_handle, NULL,
132134
clp->cl_mflags) != 0) {
133135
ret = -1;
@@ -184,7 +186,8 @@ changelist_postfix(prop_changelist_t *clp)
184186
if ((cn = uu_avl_last(clp->cl_tree)) == NULL)
185187
return (0);
186188

187-
if (clp->cl_prop == ZFS_PROP_MOUNTPOINT)
189+
if (clp->cl_prop == ZFS_PROP_MOUNTPOINT &&
190+
!(clp->cl_gflags & CL_GATHER_DONT_UNMOUNT))
188191
remove_mountpoint(cn->cn_handle);
189192

190193
/*
@@ -235,7 +238,8 @@ changelist_postfix(prop_changelist_t *clp)
235238
needs_key = (zfs_prop_get_int(cn->cn_handle,
236239
ZFS_PROP_KEYSTATUS) == ZFS_KEYSTATUS_UNAVAILABLE);
237240

238-
mounted = zfs_is_mounted(cn->cn_handle, NULL);
241+
mounted = (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT) ||
242+
zfs_is_mounted(cn->cn_handle, NULL);
239243

240244
if (!mounted && !needs_key && (cn->cn_mounted ||
241245
((sharenfs || sharesmb || clp->cl_waslegacy) &&

0 commit comments

Comments
 (0)