mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Add property overriding (-o|-x) to 'zfs receive'
This allows users to specify "-o property=value" to override and "-x property" to exclude properties when receiving a zfs send stream. Both native and user properties can be specified. This is useful when using zfs send/receive for periodic backup/replication because it lets users change properties such as canmount, mountpoint, or compression without modifying the source. References: https://www.illumos.org/issues/2745 https://www.illumos.org/issues/3753 Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed-by: Alek Pinchuk <apinchuk@datto.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: loli10K <ezomori.nozomu@gmail.com> Closes #1350 Closes #5349
This commit is contained in:
+225
-16
@@ -28,6 +28,7 @@
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
* Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
|
||||
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
|
||||
* Copyright (c) 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
@@ -69,7 +70,7 @@ extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
|
||||
|
||||
static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
|
||||
recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
|
||||
uint64_t *, const char *);
|
||||
uint64_t *, const char *, nvlist_t *);
|
||||
static int guid_to_name(libzfs_handle_t *, const char *,
|
||||
uint64_t, boolean_t, char *);
|
||||
|
||||
@@ -2745,7 +2746,8 @@ doagain:
|
||||
static int
|
||||
zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
|
||||
recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
|
||||
char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
|
||||
char **top_zfs, int cleanup_fd, uint64_t *action_handlep,
|
||||
nvlist_t *cmdprops)
|
||||
{
|
||||
nvlist_t *stream_nv = NULL;
|
||||
avl_tree_t *stream_avl = NULL;
|
||||
@@ -2921,7 +2923,7 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
|
||||
*/
|
||||
error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
|
||||
sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
|
||||
action_handlep, sendsnap);
|
||||
action_handlep, sendsnap, cmdprops);
|
||||
if (error == ENODATA) {
|
||||
error = 0;
|
||||
break;
|
||||
@@ -3085,6 +3087,131 @@ recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,
|
||||
zfs_close(zhp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare a new nvlist of properties that are to override (-o) or be excluded
|
||||
* (-x) from the received dataset
|
||||
* recvprops: received properties from the send stream
|
||||
* cmdprops: raw input properties from command line
|
||||
* origprops: properties, both locally-set and received, currently set on the
|
||||
* target dataset if it exists, NULL otherwise.
|
||||
* oxprops: valid output override (-o) and excluded (-x) properties
|
||||
*/
|
||||
static int
|
||||
zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type, boolean_t zoned,
|
||||
boolean_t recursive, boolean_t toplevel, nvlist_t *recvprops,
|
||||
nvlist_t *cmdprops, nvlist_t *origprops, nvlist_t **oxprops,
|
||||
const char *errbuf)
|
||||
{
|
||||
nvpair_t *nvp;
|
||||
nvlist_t *oprops, *voprops;
|
||||
zfs_handle_t *zhp = NULL;
|
||||
zpool_handle_t *zpool_hdl = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (nvlist_empty(cmdprops))
|
||||
return (0); /* No properties to override or exclude */
|
||||
|
||||
*oxprops = fnvlist_alloc();
|
||||
oprops = fnvlist_alloc();
|
||||
|
||||
/*
|
||||
* first iteration: process excluded (-x) properties now and gather
|
||||
* added (-o) properties to be later processed by zfs_valid_proplist()
|
||||
*/
|
||||
nvp = NULL;
|
||||
while ((nvp = nvlist_next_nvpair(cmdprops, nvp)) != NULL) {
|
||||
const char *name = nvpair_name(nvp);
|
||||
zfs_prop_t prop = zfs_name_to_prop(name);
|
||||
|
||||
/* "origin" is processed separately, don't handle it here */
|
||||
if (prop == ZFS_PROP_ORIGIN)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* we're trying to override or exclude a property that does not
|
||||
* make sense for this type of dataset, but we don't want to
|
||||
* fail if the receive is recursive: this comes in handy when
|
||||
* the send stream contains, for instance, a child ZVOL and
|
||||
* we're trying to receive it with "-o atime=on"
|
||||
*/
|
||||
if (!zfs_prop_valid_for_type(prop, type, B_FALSE) &&
|
||||
!zfs_prop_user(name)) {
|
||||
if (recursive)
|
||||
continue;
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"property '%s' does not apply to datasets of this "
|
||||
"type"), name);
|
||||
ret = zfs_error(hdl, EZFS_BADPROP, errbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (nvpair_type(nvp)) {
|
||||
case DATA_TYPE_BOOLEAN: /* -x property */
|
||||
/*
|
||||
* DATA_TYPE_BOOLEAN is the way we're asked to "exclude"
|
||||
* a property: this is done by forcing an explicit
|
||||
* inherit on the destination so the effective value is
|
||||
* not the one we received from the send stream.
|
||||
* We do this only if the property is not already
|
||||
* locally-set, in which case its value will take
|
||||
* priority over the received anyway.
|
||||
*/
|
||||
if (nvlist_exists(origprops, name)) {
|
||||
nvlist_t *attrs;
|
||||
|
||||
attrs = fnvlist_lookup_nvlist(origprops, name);
|
||||
if (strcmp(fnvlist_lookup_string(attrs,
|
||||
ZPROP_SOURCE), ZPROP_SOURCE_VAL_RECVD) != 0)
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* We can't force an explicit inherit on non-inheritable
|
||||
* properties: if we're asked to exclude this kind of
|
||||
* values we remove them from "recvprops" input nvlist.
|
||||
*/
|
||||
if (!zfs_prop_inheritable(prop) &&
|
||||
!zfs_prop_user(name) && /* can be inherited too */
|
||||
nvlist_exists(recvprops, name))
|
||||
fnvlist_remove(recvprops, name);
|
||||
else
|
||||
fnvlist_add_nvpair(*oxprops, nvp);
|
||||
break;
|
||||
case DATA_TYPE_STRING: /* -o property=value */
|
||||
fnvlist_add_nvpair(oprops, nvp);
|
||||
break;
|
||||
default:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"property '%s' must be a string or boolean"), name);
|
||||
ret = zfs_error(hdl, EZFS_BADPROP, errbuf);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (toplevel) {
|
||||
/* convert override strings properties to native */
|
||||
if ((voprops = zfs_valid_proplist(hdl, ZFS_TYPE_DATASET,
|
||||
oprops, zoned, zhp, zpool_hdl, errbuf)) == NULL) {
|
||||
ret = zfs_error(hdl, EZFS_BADPROP, errbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* second pass: process "-o" properties */
|
||||
fnvlist_merge(*oxprops, voprops);
|
||||
fnvlist_free(voprops);
|
||||
} else {
|
||||
/* override props on child dataset are inherited */
|
||||
nvp = NULL;
|
||||
while ((nvp = nvlist_next_nvpair(oprops, nvp)) != NULL) {
|
||||
const char *name = nvpair_name(nvp);
|
||||
fnvlist_add_boolean(*oxprops, name);
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
fnvlist_free(oprops);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restores a backup of tosnap from the file descriptor specified by infd.
|
||||
*/
|
||||
@@ -3093,7 +3220,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
|
||||
dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
|
||||
avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
|
||||
uint64_t *action_handlep, const char *finalsnap)
|
||||
uint64_t *action_handlep, const char *finalsnap, nvlist_t *cmdprops)
|
||||
{
|
||||
time_t begin_time;
|
||||
int ioctl_err, ioctl_errno, err;
|
||||
@@ -3116,7 +3243,12 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
char destsnap[MAXPATHLEN * 2];
|
||||
char origin[MAXNAMELEN];
|
||||
char name[MAXPATHLEN];
|
||||
nvlist_t *props = NULL;
|
||||
nvlist_t *rcvprops = NULL; /* props received from the send stream */
|
||||
nvlist_t *oxprops = NULL; /* override (-o) and exclude (-x) props */
|
||||
nvlist_t *origprops = NULL; /* original props (if destination exists) */
|
||||
zfs_type_t type;
|
||||
boolean_t toplevel;
|
||||
boolean_t zoned = B_FALSE;
|
||||
|
||||
begin_time = time(NULL);
|
||||
bzero(origin, MAXNAMELEN);
|
||||
@@ -3134,14 +3266,14 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
|
||||
(void) nvlist_lookup_uint64(fs, "parentfromsnap",
|
||||
&parent_snapguid);
|
||||
err = nvlist_lookup_nvlist(fs, "props", &props);
|
||||
err = nvlist_lookup_nvlist(fs, "props", &rcvprops);
|
||||
if (err) {
|
||||
VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
|
||||
VERIFY(0 == nvlist_alloc(&rcvprops, NV_UNIQUE_NAME, 0));
|
||||
newprops = B_TRUE;
|
||||
}
|
||||
|
||||
if (flags->canmountoff) {
|
||||
VERIFY(0 == nvlist_add_uint64(props,
|
||||
VERIFY(0 == nvlist_add_uint64(rcvprops,
|
||||
zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
|
||||
}
|
||||
if (0 == nvlist_lookup_nvlist(fs, "snapprops", &lookup)) {
|
||||
@@ -3395,6 +3527,14 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
if (resuming && zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT))
|
||||
newfs = B_TRUE;
|
||||
|
||||
/* we want to know if we're zoned when validating -o|-x props */
|
||||
zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
|
||||
|
||||
/* gather existing properties on destination */
|
||||
origprops = fnvlist_alloc();
|
||||
fnvlist_merge(origprops, zhp->zfs_props);
|
||||
fnvlist_merge(origprops, zhp->zfs_user_props);
|
||||
|
||||
zfs_close(zhp);
|
||||
} else {
|
||||
/*
|
||||
@@ -3441,9 +3581,24 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ioctl_err = lzc_receive_one(destsnap, props, origin,
|
||||
flags->force, flags->resumable, infd, drr_noswap, cleanup_fd,
|
||||
&read_bytes, &errflags, action_handlep, &prop_errors);
|
||||
toplevel = chopprefix[0] != '/';
|
||||
if (drrb->drr_type == DMU_OST_ZVOL) {
|
||||
type = ZFS_TYPE_VOLUME;
|
||||
} else if (drrb->drr_type == DMU_OST_ZFS) {
|
||||
type = ZFS_TYPE_FILESYSTEM;
|
||||
} else {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"invalid record type: 0x%d"), drrb->drr_type);
|
||||
err = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
|
||||
goto out;
|
||||
}
|
||||
if ((err = zfs_setup_cmdline_props(hdl, type, zoned, recursive,
|
||||
toplevel, rcvprops, cmdprops, origprops, &oxprops, errbuf)) != 0)
|
||||
goto out;
|
||||
|
||||
err = ioctl_err = lzc_receive_with_cmdprops(destsnap, rcvprops, oxprops,
|
||||
origin, flags->force, flags->resumable, infd, drr_noswap,
|
||||
cleanup_fd, &read_bytes, &errflags, action_handlep, &prop_errors);
|
||||
ioctl_errno = ioctl_err;
|
||||
prop_errflags = errflags;
|
||||
|
||||
@@ -3658,16 +3813,65 @@ out:
|
||||
nvlist_free(prop_errors);
|
||||
|
||||
if (newprops)
|
||||
nvlist_free(props);
|
||||
nvlist_free(rcvprops);
|
||||
|
||||
nvlist_free(oxprops);
|
||||
nvlist_free(origprops);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check properties we were asked to override (both -o|-x)
|
||||
*/
|
||||
static boolean_t
|
||||
zfs_receive_checkprops(libzfs_handle_t *hdl, nvlist_t *props,
|
||||
const char *errbuf)
|
||||
{
|
||||
nvpair_t *nvp;
|
||||
zfs_prop_t prop;
|
||||
const char *name;
|
||||
|
||||
nvp = NULL;
|
||||
while ((nvp = nvlist_next_nvpair(props, nvp)) != NULL) {
|
||||
name = nvpair_name(nvp);
|
||||
prop = zfs_name_to_prop(name);
|
||||
|
||||
if (prop == ZPROP_INVAL) {
|
||||
if (!zfs_prop_user(name)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"invalid property '%s'"), name);
|
||||
return (B_FALSE);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* "origin" is readonly but is used to receive datasets as
|
||||
* clones so we don't raise an error here
|
||||
*/
|
||||
if (prop == ZFS_PROP_ORIGIN)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* cannot override readonly, set-once and other specific
|
||||
* settable properties
|
||||
*/
|
||||
if (zfs_prop_readonly(prop) || prop == ZFS_PROP_VERSION ||
|
||||
prop == ZFS_PROP_VOLSIZE) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"invalid property '%s'"), name);
|
||||
return (B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
|
||||
const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
|
||||
nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
|
||||
uint64_t *action_handlep, const char *finalsnap)
|
||||
uint64_t *action_handlep, const char *finalsnap, nvlist_t *cmdprops)
|
||||
{
|
||||
int err;
|
||||
dmu_replay_record_t drr, drr_noswap;
|
||||
@@ -3680,6 +3884,11 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot receive"));
|
||||
|
||||
/* check cmdline props, raise an error if they cannot be received */
|
||||
if (!zfs_receive_checkprops(hdl, cmdprops, errbuf)) {
|
||||
return (zfs_error(hdl, EZFS_BADPROP, errbuf));
|
||||
}
|
||||
|
||||
if (flags->isprefix &&
|
||||
!zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
|
||||
@@ -3768,12 +3977,12 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
|
||||
}
|
||||
return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
|
||||
&drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
|
||||
cleanup_fd, action_handlep, finalsnap));
|
||||
cleanup_fd, action_handlep, finalsnap, cmdprops));
|
||||
} else {
|
||||
assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
|
||||
DMU_COMPOUNDSTREAM);
|
||||
return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
|
||||
&zcksum, top_zfs, cleanup_fd, action_handlep));
|
||||
&zcksum, top_zfs, cleanup_fd, action_handlep, cmdprops));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3846,7 +4055,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
|
||||
VERIFY(cleanup_fd >= 0);
|
||||
|
||||
err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
|
||||
stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
|
||||
stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL, props);
|
||||
|
||||
VERIFY(0 == close(cleanup_fd));
|
||||
|
||||
|
||||
@@ -574,8 +574,8 @@ recv_read(int fd, void *buf, int ilen)
|
||||
* Non-Linux OpenZFS platforms have opted to modify the legacy interface.
|
||||
*/
|
||||
static int
|
||||
recv_impl(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, boolean_t resumable, int input_fd,
|
||||
recv_impl(const char *snapname, nvlist_t *recvdprops, nvlist_t *localprops,
|
||||
const char *origin, boolean_t force, boolean_t resumable, int input_fd,
|
||||
const dmu_replay_record_t *begin_record, int cleanup_fd,
|
||||
uint64_t *read_bytes, uint64_t *errflags, uint64_t *action_handle,
|
||||
nvlist_t **errors)
|
||||
@@ -622,8 +622,11 @@ recv_impl(const char *snapname, nvlist_t *props, const char *origin,
|
||||
|
||||
fnvlist_add_string(innvl, "snapname", snapname);
|
||||
|
||||
if (props != NULL)
|
||||
fnvlist_add_nvlist(innvl, "props", props);
|
||||
if (recvdprops != NULL)
|
||||
fnvlist_add_nvlist(innvl, "props", recvdprops);
|
||||
|
||||
if (localprops != NULL)
|
||||
fnvlist_add_nvlist(innvl, "localprops", localprops);
|
||||
|
||||
if (origin != NULL && strlen(origin))
|
||||
fnvlist_add_string(innvl, "origin", origin);
|
||||
@@ -679,12 +682,18 @@ recv_impl(const char *snapname, nvlist_t *props, const char *origin,
|
||||
(void) strlcpy(zc.zc_name, fsname, sizeof (zc.zc_value));
|
||||
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
|
||||
if (props != NULL) {
|
||||
packed = fnvlist_pack(props, &size);
|
||||
if (recvdprops != NULL) {
|
||||
packed = fnvlist_pack(recvdprops, &size);
|
||||
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
|
||||
zc.zc_nvlist_src_size = size;
|
||||
}
|
||||
|
||||
if (localprops != NULL) {
|
||||
packed = fnvlist_pack(localprops, &size);
|
||||
zc.zc_nvlist_conf = (uint64_t)(uintptr_t)packed;
|
||||
zc.zc_nvlist_conf_size = size;
|
||||
}
|
||||
|
||||
if (origin != NULL)
|
||||
(void) strlcpy(zc.zc_string, origin,
|
||||
sizeof (zc.zc_string));
|
||||
@@ -750,7 +759,7 @@ int
|
||||
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, int fd)
|
||||
{
|
||||
return (recv_impl(snapname, props, origin, force, B_FALSE, fd,
|
||||
return (recv_impl(snapname, props, NULL, origin, force, B_FALSE, fd,
|
||||
NULL, -1, NULL, NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
@@ -764,7 +773,7 @@ int
|
||||
lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, int fd)
|
||||
{
|
||||
return (recv_impl(snapname, props, origin, force, B_TRUE, fd,
|
||||
return (recv_impl(snapname, props, NULL, origin, force, B_TRUE, fd,
|
||||
NULL, -1, NULL, NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
@@ -786,7 +795,7 @@ lzc_receive_with_header(const char *snapname, nvlist_t *props,
|
||||
{
|
||||
if (begin_record == NULL)
|
||||
return (EINVAL);
|
||||
return (recv_impl(snapname, props, origin, force, resumable, fd,
|
||||
return (recv_impl(snapname, props, NULL, origin, force, resumable, fd,
|
||||
begin_record, -1, NULL, NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
@@ -816,7 +825,26 @@ int lzc_receive_one(const char *snapname, nvlist_t *props,
|
||||
uint64_t *read_bytes, uint64_t *errflags, uint64_t *action_handle,
|
||||
nvlist_t **errors)
|
||||
{
|
||||
return (recv_impl(snapname, props, origin, force, resumable,
|
||||
return (recv_impl(snapname, props, NULL, origin, force, resumable,
|
||||
input_fd, begin_record, cleanup_fd, read_bytes, errflags,
|
||||
action_handle, errors));
|
||||
}
|
||||
|
||||
/*
|
||||
* Like lzc_receive_one, but allows the caller to pass an additional 'cmdprops'
|
||||
* argument.
|
||||
*
|
||||
* The 'cmdprops' nvlist contains both override ('zfs receive -o') and
|
||||
* exclude ('zfs receive -x') properties. Callers are responsible for freeing
|
||||
* this nvlist
|
||||
*/
|
||||
int lzc_receive_with_cmdprops(const char *snapname, nvlist_t *props,
|
||||
nvlist_t *cmdprops, const char *origin, boolean_t force,
|
||||
boolean_t resumable, int input_fd, const dmu_replay_record_t *begin_record,
|
||||
int cleanup_fd, uint64_t *read_bytes, uint64_t *errflags,
|
||||
uint64_t *action_handle, nvlist_t **errors)
|
||||
{
|
||||
return (recv_impl(snapname, props, cmdprops, origin, force, resumable,
|
||||
input_fd, begin_record, cleanup_fd, read_bytes, errflags,
|
||||
action_handle, errors));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user