Skip to content

Commit

Permalink
1867: behlendorf/issue-1350 - Adds support for property overrides (WIP)
Browse files Browse the repository at this point in the history
Adds support for property overrides (-o property=value), property
excludes (-x property) and dataset limits (-l <volume|filesystem>)
to zfs receive.

Both -o and -x options mirror the functionality already available
in Oracle's ZFS implementation which is also mentioned in the
upstream feature request openzfs#2745:

The -l option allows receive to be limited to specific datasets within
the stream effectively allowing partial restores from a multi dataset
stream.

References:
  https://www.illumos.org/issues/2745

Ported-by: Milan-Benes
Issue openzfs#1350

NOTES: Man page updates missing and must be added, see patch:
http://blog.multiplay.co.uk/dropzone/freebsd/zfs-recv-properties.patch
  • Loading branch information
stevenh authored and FransUrbo committed Nov 5, 2014
1 parent 64188ef commit 851751d
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 41 deletions.
67 changes: 61 additions & 6 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,9 @@ get_usage(zfs_help_t idx)
case HELP_PROMOTE:
return (gettext("\tpromote <clone-filesystem>\n"));
case HELP_RECEIVE:
return (gettext("\treceive [-vnFus] <filesystem|volume|"
"snapshot>\n"
"\treceive [-vnFus] [-d | -e] <filesystem>\n"));
return (gettext("\treceive [-vnFus] [-d | -e] [-o <property>] "
"... [-x <property>] ... [-l <filesystem|volume>] ... "
" <filesystem|volume|snapshot>\n"));
case HELP_RENAME:
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
"<filesystem|volume|snapshot>\n"
Expand Down Expand Up @@ -478,6 +478,21 @@ usage(boolean_t requested)
exit(requested ? 0 : 2);
}

static int
parsepropname(nvlist_t *props)
{
char *propname = optarg;

if (nvlist_lookup_string(props, propname, NULL) == 0) {
(void) fprintf(stderr, gettext("property '%s' "
"specified multiple times\n"), propname);
return (-1);
}
if (nvlist_add_boolean(props, propname))
nomem();
return (0);
}

static int
parseprop(nvlist_t *props)
{
Expand Down Expand Up @@ -3853,18 +3868,24 @@ zfs_do_send(int argc, char **argv)
}

/*
* zfs receive [-vnFus] [-d | -e] <fs@snap>
* zfs receive [-vnFus] [-d | -e] [-l <volume|filesystem>] ...
* [-o property=value] ... [-x property] ... <volume|filesytem|snapshot>
*
* Restore a backup stream from stdin.
*/
static int
zfs_do_receive(int argc, char **argv)
{
nvlist_t *props, *limitds;
int c, err;
recvflags_t flags = { 0 };
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
nomem();
if (nvlist_alloc(&limitds, NV_UNIQUE_NAME, 0) != 0)
nomem();

/* check options */
while ((c = getopt(argc, argv, ":denuvFs")) != -1) {
while ((c = getopt(argc, argv, ":del:no:uvx:Fs")) != -1) {
switch (c) {
case 's':
flags.skip = B_TRUE;
Expand All @@ -3876,15 +3897,32 @@ zfs_do_receive(int argc, char **argv)
flags.isprefix = B_TRUE;
flags.istail = B_TRUE;
break;
case 'l':
if (parsepropname(limitds)) {
err = 1;
goto recverror;
}
break;
case 'n':
flags.dryrun = B_TRUE;
break;
case 'o':
if (parseprop(props)) {
err = 1;
goto recverror;
}
break;
case 'u':
flags.nomount = B_TRUE;
break;
case 'v':
flags.verbose = B_TRUE;
break;
case 'x':
if (parsepropname(props)) {
err = 1;
goto recverror;
}
case 'F':
flags.force = B_TRUE;
break;
Expand Down Expand Up @@ -3921,7 +3959,24 @@ zfs_do_receive(int argc, char **argv)
return (1);
}

err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, NULL);
if (nvlist_empty(props)) {
nvlist_free(props);
props = NULL;
}

if (nvlist_empty(limitds)) {
nvlist_free(limitds);
limitds = NULL;
}

err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, props, limitds, NULL);

recverror:
if (props != NULL)
nvlist_free(props);

if (limitds != NULL)
nvlist_free(limitds);

return (err != 0);
}
Expand Down
2 changes: 1 addition & 1 deletion include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ typedef struct recvflags {
} recvflags_t;

extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t *,
int, avl_tree_t *);
int, nvlist_t *, nvlist_t *, avl_tree_t *);

typedef enum diff_flags {
ZFS_DIFF_PARSEABLE = 0x1,
Expand Down
2 changes: 2 additions & 0 deletions include/libzfs_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ int changelist_haszonedchild(prop_changelist_t *);

void remove_mountpoint(zfs_handle_t *);
int create_parents(libzfs_handle_t *, char *, int);
int check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
boolean_t accept_ancestor, int *prefixlen);
boolean_t isa_child_of(const char *dataset, const char *parent);

zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
Expand Down
2 changes: 1 addition & 1 deletion lib/libzfs/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -2869,7 +2869,7 @@ parent_name(const char *path, char *buf, size_t buflen)
* 'zoned' property, which is used to validate property settings when creating
* new datasets.
*/
static int
int
check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
boolean_t accept_ancestor, int *prefixlen)
{
Expand Down
Loading

0 comments on commit 851751d

Please sign in to comment.