summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs_core
diff options
context:
space:
mode:
authorloli10K <ezomori.nozomu@gmail.com>2019-07-23 15:22:07 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2019-07-31 11:57:16 +0000
commit6ccda740e007c01cb5d1436fe337851ff8c5d422 (patch)
tree89e68035d49559e0004280b98187af6a0885a1d5 /usr/src/lib/libzfs_core
parentfed692705a66b80d86971df5b579fcac7386f7df (diff)
downloadillumos-joyent-6ccda740e007c01cb5d1436fe337851ff8c5d422.tar.gz
11282 port ZoL send/recv fixes
Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com> Portions contributed by: Brian Behlendorf <behlendorf1@llnl.gov> Portions contributed by: Paul Zuchowski <pzuchowski@datto.com> Portions contributed by: Tom Caputi <tcaputi@datto.com> Portions contributed by: Roman Strashkin <roman.strashkin@nexenta.com> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Olaf Faaland <faaland1@llnl.gov> Reviewed by: Tom Caputi <tcaputi@datto.com> Reviewed by: Alek Pinchuk <apinchuk@datto.com> Reviewed by: loli10K <ezomori.nozomu@gmail.com> Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Jorgen Lundman <lundman@lundman.net> Reviewed by: Richard Elling <Richard.Elling@RichardElling.com> Reviewed by: Giuseppe Di Natale <dinatale2@llnl.gov> Reviewed by: George Melikov <mail@gmelikov.ru> Reviewed by: Kody Kantor <kody.kantor@joyent.com> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/lib/libzfs_core')
-rw-r--r--usr/src/lib/libzfs_core/common/libzfs_core.c140
-rw-r--r--usr/src/lib/libzfs_core/common/libzfs_core.h4
-rw-r--r--usr/src/lib/libzfs_core/common/mapfile-vers6
3 files changed, 112 insertions, 38 deletions
diff --git a/usr/src/lib/libzfs_core/common/libzfs_core.c b/usr/src/lib/libzfs_core/common/libzfs_core.c
index df973b532d..ac8ec6d11a 100644
--- a/usr/src/lib/libzfs_core/common/libzfs_core.c
+++ b/usr/src/lib/libzfs_core/common/libzfs_core.c
@@ -670,82 +670,126 @@ recv_read(int fd, void *buf, int ilen)
}
static int
-recv_impl(const char *snapname, nvlist_t *props, const char *origin,
- boolean_t force, boolean_t resumable, boolean_t raw, int fd,
- const dmu_replay_record_t *begin_record)
+recv_impl(const char *snapname, nvlist_t *recvdprops, nvlist_t *localprops,
+ uint8_t *wkeydata, uint_t wkeylen, const char *origin, boolean_t force,
+ boolean_t resumable, boolean_t raw, 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)
{
+
/*
* The receive ioctl is still legacy, so we need to construct our own
* zfs_cmd_t rather than using zfsc_ioctl().
*/
zfs_cmd_t zc = { 0 };
- char *atp;
char *packed = NULL;
size_t size;
+
+ dmu_replay_record_t drr;
+ char fsname[MAXPATHLEN];
+ char *atp;
int error;
ASSERT3S(g_refcount, >, 0);
VERIFY3S(g_fd, !=, -1);
- /* zc_name is name of containing filesystem */
- (void) strlcpy(zc.zc_name, snapname, sizeof (zc.zc_name));
- atp = strchr(zc.zc_name, '@');
+ /* Set 'fsname' to the name of containing filesystem */
+ (void) strlcpy(fsname, snapname, sizeof (fsname));
+ atp = strchr(fsname, '@');
if (atp == NULL)
return (EINVAL);
*atp = '\0';
/* if the fs does not exist, try its parent. */
- if (!lzc_exists(zc.zc_name)) {
- char *slashp = strrchr(zc.zc_name, '/');
+ if (!lzc_exists(fsname)) {
+ char *slashp = strrchr(fsname, '/');
if (slashp == NULL)
return (ENOENT);
*slashp = '\0';
+ }
+ /*
+ * The begin_record is normally a non-byteswapped BEGIN record.
+ * For resumable streams it may be set to any non-byteswapped
+ * dmu_replay_record_t.
+ */
+ if (begin_record == NULL) {
+ error = recv_read(input_fd, &drr, sizeof (drr));
+ if (error != 0)
+ return (error);
+ } else {
+ drr = *begin_record;
}
- /* zc_value is full name of the snapshot to create */
+ (void) strlcpy(zc.zc_name, fsname, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
- if (props != NULL) {
- /* zc_nvlist_src is props to set */
- 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;
}
- /* zc_string is name of clone origin (if DRR_FLAG_CLONE) */
- if (origin != NULL)
- (void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
+ if (localprops != NULL) {
+ packed = fnvlist_pack(localprops, &size);
+ zc.zc_nvlist_conf = (uint64_t)(uintptr_t)packed;
+ zc.zc_nvlist_conf_size = size;
+ }
- /* zc_begin_record is non-byteswapped BEGIN record */
- if (begin_record == NULL) {
- error = recv_read(fd, &zc.zc_begin_record,
- sizeof (zc.zc_begin_record));
- if (error != 0)
- goto out;
- } else {
- zc.zc_begin_record = *begin_record;
+ /* Use zc_history_ members for hidden args */
+ if (wkeydata != NULL) {
+ nvlist_t *hidden_args = fnvlist_alloc();
+ fnvlist_add_uint8_array(hidden_args, "wkeydata", wkeydata,
+ wkeylen);
+ packed = fnvlist_pack(hidden_args, &size);
+ zc.zc_history_offset = (uint64_t)(uintptr_t)packed;
+ zc.zc_history_len = size;
}
- /* zc_cookie is fd to read from */
- zc.zc_cookie = fd;
+ if (origin != NULL)
+ (void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
- /* zc guid is force flag */
+ ASSERT3S(drr.drr_type, ==, DRR_BEGIN);
+ zc.zc_begin_record = drr;
zc.zc_guid = force;
-
+ zc.zc_cookie = input_fd;
+ zc.zc_cleanup_fd = -1;
+ zc.zc_action_handle = 0;
zc.zc_resumable = resumable;
- /* zc_cleanup_fd is unused */
- zc.zc_cleanup_fd = -1;
+ if (cleanup_fd >= 0)
+ zc.zc_cleanup_fd = cleanup_fd;
+
+ if (action_handle != NULL)
+ zc.zc_action_handle = *action_handle;
+
+ zc.zc_nvlist_dst_size = 128 * 1024;
+ zc.zc_nvlist_dst = (uint64_t)(uintptr_t)malloc(zc.zc_nvlist_dst_size);
error = ioctl(g_fd, ZFS_IOC_RECV, &zc);
- if (error != 0)
+ if (error != 0) {
error = errno;
+ } else {
+ if (read_bytes != NULL)
+ *read_bytes = zc.zc_cookie;
+
+ if (errflags != NULL)
+ *errflags = zc.zc_obj;
+
+ if (action_handle != NULL)
+ *action_handle = zc.zc_action_handle;
+
+ if (errors != NULL)
+ VERIFY0(nvlist_unpack(
+ (void *)(uintptr_t)zc.zc_nvlist_dst,
+ zc.zc_nvlist_dst_size, errors, KM_SLEEP));
+ }
-out:
if (packed != NULL)
fnvlist_pack_free(packed, size);
free((void*)(uintptr_t)zc.zc_nvlist_dst);
+
return (error);
}
@@ -766,8 +810,8 @@ int
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
boolean_t raw, boolean_t force, int fd)
{
- return (recv_impl(snapname, props, origin, force, B_FALSE, raw, fd,
- NULL));
+ return (recv_impl(snapname, props, NULL, NULL, 0, origin, force,
+ B_FALSE, raw, fd, NULL, -1, NULL, NULL, NULL, NULL));
}
/*
@@ -780,8 +824,8 @@ int
lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, boolean_t raw, int fd)
{
- return (recv_impl(snapname, props, origin, force, B_TRUE, raw, fd,
- NULL));
+ return (recv_impl(snapname, props, NULL, NULL, 0, origin, force,
+ B_TRUE, raw, fd, NULL, -1, NULL, NULL, NULL, NULL));
}
/*
@@ -802,8 +846,28 @@ lzc_receive_with_header(const char *snapname, nvlist_t *props,
{
if (begin_record == NULL)
return (EINVAL);
- return (recv_impl(snapname, props, origin, force, resumable, raw, fd,
- begin_record));
+
+ return (recv_impl(snapname, props, NULL, NULL, 0, origin, force,
+ resumable, raw, fd, begin_record, -1, NULL, NULL, NULL, NULL));
+}
+
+/*
+ * 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, uint8_t *wkeydata, uint_t wkeylen, const char *origin,
+ boolean_t force, boolean_t resumable, boolean_t raw, 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, wkeydata, wkeylen, origin,
+ force, resumable, raw, input_fd, begin_record, cleanup_fd,
+ read_bytes, errflags, action_handle, errors));
}
/*
diff --git a/usr/src/lib/libzfs_core/common/libzfs_core.h b/usr/src/lib/libzfs_core/common/libzfs_core.h
index f1905f9968..e1574feff6 100644
--- a/usr/src/lib/libzfs_core/common/libzfs_core.h
+++ b/usr/src/lib/libzfs_core/common/libzfs_core.h
@@ -92,6 +92,10 @@ int lzc_receive_resumable(const char *, nvlist_t *, const char *,
boolean_t, boolean_t, int);
int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
boolean_t, boolean_t, int, const struct dmu_replay_record *);
+int lzc_receive_with_cmdprops(const char *, nvlist_t *, nvlist_t *,
+ uint8_t *, uint_t, const char *, boolean_t, boolean_t, boolean_t, int,
+ const struct dmu_replay_record *, int, uint64_t *, uint64_t *,
+ uint64_t *, nvlist_t **);
boolean_t lzc_exists(const char *);
diff --git a/usr/src/lib/libzfs_core/common/mapfile-vers b/usr/src/lib/libzfs_core/common/mapfile-vers
index c14ec17a43..5bcb42c726 100644
--- a/usr/src/lib/libzfs_core/common/mapfile-vers
+++ b/usr/src/lib/libzfs_core/common/mapfile-vers
@@ -38,6 +38,12 @@
$mapfile_version 2
+SYMBOL_VERSION ILLUMOS_0.6 {
+ global:
+
+ lzc_receive_with_cmdprops;
+} ILLUMOS_0.5;
+
SYMBOL_VERSION ILLUMOS_0.5 {
global: