Skip to content

Commit

Permalink
Introduce recursive '-r' option for zfs-promote(8)
Browse files Browse the repository at this point in the history
This patch introduces a new recurse parameter to zfs_promote.
The new signature is zfs_promote(zfs_handle_t *, boolean_t).
When activating boot environments, it is necessary to recursively
promote datasets. External tooling like bectl(8) implement
this property locally by wrapping zfs_promote. However, it is
also useful to have this option '-r' in upstream zfs-promote(8).
Here we push this functionality into libzfs where it can be shared
by zfs-promote(8).

Signed-off-by:	R. Christian McDonald <[email protected]>
Sponsored by:	Rubicon Communications, LLC ("Netgate")
  • Loading branch information
rcmcdonald91 committed Jan 18, 2024
1 parent a1771d2 commit 47972f0
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 21 deletions.
34 changes: 19 additions & 15 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ get_usage(zfs_help_t idx)
return (gettext("\tmount\n"
"\tmount [-flvO] [-o opts] <-a | filesystem>\n"));
case HELP_PROMOTE:
return (gettext("\tpromote <clone-filesystem>\n"));
return (gettext("\tpromote [-r] <clone-filesystem>\n"));
case HELP_RECEIVE:
return (gettext("\treceive [-vMnsFhu] "
"[-o <property>=<value>] ... [-x <property>] ...\n"
Expand Down Expand Up @@ -3869,32 +3869,36 @@ static int
zfs_do_promote(int argc, char **argv)
{
zfs_handle_t *zhp;
int ret = 0;
int c, ret = 0;
boolean_t recursive = B_FALSE;

/* check options */
if (argc > 1 && argv[1][0] == '-') {
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
argv[1][1]);
usage(B_FALSE);
while ((c = getopt(argc, argv, "r")) != -1) {
switch (c) {
case 'r':
recursive = B_TRUE;
break;
default:
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
usage(B_FALSE);
}
}

argc -= optind;
argv += optind;

/* check number of arguments */
if (argc < 2) {
if (argc < 1) {
(void) fprintf(stderr, gettext("missing clone filesystem"
" argument\n"));
usage(B_FALSE);
}
if (argc > 2) {
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
}

zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
if (zhp == NULL)
return (1);

ret = (zfs_promote(zhp) != 0);

ret = (zfs_promote(zhp, recursive) != 0);

zfs_close(zhp);
return (ret);
Expand Down
2 changes: 1 addition & 1 deletion include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ _LIBZFS_H int zfs_send_saved(zfs_handle_t *, sendflags_t *, int, const char *);
_LIBZFS_H nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
const char *token);

_LIBZFS_H int zfs_promote(zfs_handle_t *);
_LIBZFS_H int zfs_promote(zfs_handle_t *, boolean_t);
_LIBZFS_H int zfs_hold(zfs_handle_t *, const char *, const char *,
boolean_t, int);
_LIBZFS_H int zfs_hold_nvl(zfs_handle_t *, int, nvlist_t *);
Expand Down
43 changes: 38 additions & 5 deletions lib/libzfs/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -4106,11 +4106,8 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
return (ret);
}

/*
* Promotes the given clone fs to be the clone parent.
*/
int
zfs_promote(zfs_handle_t *zhp)
static int
zfs_promote_impl(zfs_handle_t *zhp)
{
libzfs_handle_t *hdl = zhp->zfs_hdl;
char snapname[ZFS_MAX_DATASET_NAME_LEN];
Expand Down Expand Up @@ -4163,6 +4160,42 @@ zfs_promote(zfs_handle_t *zhp)
return (ret);
}

static int
zfs_promote_recursive_cb(zfs_handle_t *zhp, void *arg)
{
int err, *ret = (void *)arg;

/* Bubble up last non-zero error to caller, best we can do */
if ((err = zfs_promote_impl(zhp)) != 0)
*ret = err;

return (zfs_iter_filesystems(zhp, zfs_promote_recursive_cb, arg));
}

static int
zfs_promote_recursive_impl(zfs_handle_t *zhp)
{
int err, ret = 0;

/* Bubble up last non-zero error to caller, best we can do */
if ((err = zfs_promote_recursive_cb(zhp, &ret)) != 0)
ret = err;

return (ret);
}

/*
* Promotes the given clone fs to be the clone parent.
*/
int
zfs_promote(zfs_handle_t *zhp, boolean_t recurse)
{
if (recurse)
return (zfs_promote_recursive_impl(zhp));

return (zfs_promote_impl(zhp));
}

typedef struct snapdata {
nvlist_t *sd_nvl;
const char *sd_snapname;
Expand Down
6 changes: 6 additions & 0 deletions man/man8/zfs-promote.8
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
.Sh SYNOPSIS
.Nm zfs
.Cm promote
.Op Fl r
.Ar clone
.
.Sh DESCRIPTION
Expand All @@ -55,10 +56,15 @@ The space they use moves from the origin dataset to the promoted clone, so
enough space must be available to accommodate these snapshots.
No new space is consumed by this operation, but the space accounting is
adjusted.
.Pp
The promoted clone must not have any conflicting snapshot names of its own.
The
.Nm zfs Cm rename
subcommand can be used to rename any conflicting snapshots.
.Bl -tag -width "-H"
.It Fl r
Recursively promote all descendent datasets.
.El
.
.Sh EXAMPLES
.\" These are, respectively, examples 10 from zfs.8
Expand Down

0 comments on commit 47972f0

Please sign in to comment.