6051 lzc_receive: allow the caller to read the begin record

illumos/illumos-gate@620f322510
620f322510

https://www.illumos.org/issues/6051
  Currently lzc_receive() requires that its snapname argument is a snapshot name
  (contains '').
  @zfs receive allows to specify just a dataset name and would try to deduce the
  snapshot name from the stream.
  I propose to allow lzc_receive() to do the same.
  That seems to be quite easy to implement, it requires only a small amount of
  logic, it does not require any additional system calls or any additional data
  from the stream.
  The benefit is that the new behavior would allow to keep the snapshot names the
  same between the sender and receiver at zero cost, without a need to pass the
  names out of band.

Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Author: Andriy Gapon <avg@icyb.net.ua>
This commit is contained in:
Andriy Gapon 2016-11-02 17:32:31 +00:00
parent 0a682531f4
commit c01a79842c
2 changed files with 41 additions and 8 deletions

View File

@ -549,8 +549,9 @@ recv_read(int fd, void *buf, int ilen)
}
static int
lzc_receive_impl(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, boolean_t resumable, int fd)
recv_impl(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, boolean_t resumable, int fd,
const dmu_replay_record_t *begin_record)
{
/*
* The receive ioctl is still legacy, so we need to construct our own
@ -595,9 +596,14 @@ lzc_receive_impl(const char *snapname, nvlist_t *props, const char *origin,
(void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
/* zc_begin_record is non-byteswapped BEGIN record */
error = recv_read(fd, &zc.zc_begin_record, sizeof (zc.zc_begin_record));
if (error != 0)
goto out;
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;
}
/* zc_cookie is fd to read from */
zc.zc_cookie = fd;
@ -638,7 +644,7 @@ int
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, int fd)
{
return (lzc_receive_impl(snapname, props, origin, force, B_FALSE, fd));
return (recv_impl(snapname, props, origin, force, B_FALSE, fd, NULL));
}
/*
@ -651,7 +657,29 @@ int
lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, int fd)
{
return (lzc_receive_impl(snapname, props, origin, force, B_TRUE, fd));
return (recv_impl(snapname, props, origin, force, B_TRUE, fd, NULL));
}
/*
* Like lzc_receive, but allows the caller to read the begin record and then to
* pass it in. That could be useful if the caller wants to derive, for example,
* the snapname or the origin parameters based on the information contained in
* the begin record.
* The begin record must be in its original form as read from the stream,
* in other words, it should not be byteswapped.
*
* The 'resumable' parameter allows to obtain the same behavior as with
* lzc_receive_resumable.
*/
int
lzc_receive_with_header(const char *snapname, nvlist_t *props,
const char *origin, boolean_t force, boolean_t resumable, int fd,
const dmu_replay_record_t *begin_record)
{
if (begin_record == NULL)
return (EINVAL);
return (recv_impl(snapname, props, origin, force, resumable, fd,
begin_record));
}
/*

View File

@ -68,10 +68,15 @@ enum lzc_send_flags {
int lzc_send(const char *, const char *, int, enum lzc_send_flags);
int lzc_send_resume(const char *, const char *, int,
enum lzc_send_flags, uint64_t, uint64_t);
int lzc_send_space(const char *, const char *, uint64_t *);
struct dmu_replay_record;
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
int lzc_receive_resumable(const char *, nvlist_t *, const char *,
boolean_t, int);
int lzc_send_space(const char *, const char *, uint64_t *);
int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
boolean_t, int, const struct dmu_replay_record *);
boolean_t lzc_exists(const char *);