diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 51a0fbd43c..55e69f5a6f 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -319,7 +319,7 @@ get_usage(zfs_help_t idx) "\tmount [-flvO] [-o opts] <-a|-R filesystem|" "filesystem>\n")); case HELP_PROMOTE: - return (gettext("\tpromote \n")); + return (gettext("\tpromote [-r] \n")); case HELP_RECEIVE: return (gettext("\treceive [-vMnsFhu] " "[-o =] ... [-x ] ...\n" @@ -4128,32 +4128,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); diff --git a/include/libzfs.h b/include/libzfs.h index bf5579f38f..ef66e06bd9 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -837,7 +837,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 *); diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 231bbbd92d..46eb73a433 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -4114,11 +4114,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]; @@ -4171,6 +4168,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; diff --git a/man/man8/zfs-promote.8 b/man/man8/zfs-promote.8 index cdb04d05de..b0f6118526 100644 --- a/man/man8/zfs-promote.8 +++ b/man/man8/zfs-promote.8 @@ -39,6 +39,7 @@ .Sh SYNOPSIS .Nm zfs .Cm promote +.Op Fl r .Ar clone . .Sh DESCRIPTION @@ -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