On 11/08/2015 20:54, Matthew Ahrens wrote:
> On Fri, Aug 7, 2015 at 7:18 AM, Andriy Gapon <[email protected]
> <mailto:[email protected]>> wrote:
> 
>     Your proposal seems like a more flexible approach. One thing that bothers 
> me a
>     little bit is that every consumer of the new lzc_receive would have to 
> duplicate
>     the code for reading / interpreting the BEGIN record.
> 
> Yes, but every consumer might want to interpret the BEGIN record a different 
> way
> (i.e. use the fromsnap name in different ways to determine the name of the
> snapshot to create)
> 
>     Possible alternative is to not read the begin record in userland at all 
> and let
>     the kernel driver do it. After all, the current lzc_receive just passes 
> the
>     record down to the kernel without any interpretation. That would require
>     changing the ZFS_IOC_RECV interface, of course.
> 
> But then you'd have to teach the kernel all possible ways that userland might
> want to specify the name to receive based on the fromsnap name in the BEGIN
> record.  Today /sbin/zfs supports at least 4 ways of doing it:
> 
>  - specify full pool/fs@snap
>  - specify pool/fs, get @snap from BEGIN
>  - specify pool/fs -d, append /everything/but/the/poolname@snap from BEGIN
>  - specify pool/fs -e, get /last_elem@snap from BEGIN

Indeed.  So, you have me convinced.

The only potentially unfortunate side effect is that struct drr_begin would
become a part of the API.  We could try to make it opaque to libzfs_core users,
though, by providing a function to read the record from a file descriptor and
then providing a number of accessor functions to extract useful values from the
record.  But not sure if that approach is worth the trouble, it certainly seems
a bit cumbersome.

I'm attaching my current work-in-progress on implementing your suggestion (as I
understood it, possibly incorrectly).  'lzc_receive_basic' is the best name with
which I could come up, but it's probably not the best name.  I had a trouble
picking up a name that would be expressive (of the intent) or descriptive (of
the behavior) enough while still being not very long.

-- 
Andriy Gapon
--- a/usr/src/lib/libzfs_core/common/libzfs_core.h
+++ b/usr/src/lib/libzfs_core/common/libzfs_core.h
@@ -67,6 +67,11 @@ enum lzc_send_flags {
 
 int lzc_send(const char *, const char *, int, enum lzc_send_flags);
-int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
+
+struct drr_begin;
+
+int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int,
+    const struct drr_begin *);
+int lzc_receive_basic(const char *, nvlist_t *, const char *, boolean_t, int);
 int lzc_send_space(const char *, const char *, uint64_t *);
 int lzc_send_progress(const char *, int, uint64_t *);
 
--- a/usr/src/lib/libzfs_core/common/libzfs_core.c
+++ b/usr/src/lib/libzfs_core/common/libzfs_core.c
@@ -625,6 +625,11 @@ recv_read(int fd, void *buf, int ilen)
  * flag will cause the target filesystem to be rolled back or destroyed if
  * necessary to receive.
  *
+ * lzc_receive_basic reads the whole stream while lzc_receive 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.
+ *
  * Return 0 on success or an errno on failure.
  *
  * Note: this interface does not work on dedup'd streams
@@ -632,7 +637,7 @@ recv_read(int fd, void *buf, int ilen)
  */
 int
 lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
-    boolean_t force, int fd)
+    boolean_t force, int fd, const struct drr_begin *begin_record)
 {
 	/*
 	 * The receive ioctl is still legacy, so we need to construct our own
@@ -642,7 +647,6 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
 	char *atp;
 	char *packed = NULL;
 	size_t size;
-	dmu_replay_record_t drr;
 	int error;
 
 	ASSERT3S(g_refcount, >, 0);
@@ -678,10 +682,7 @@ lzc_receive(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, &drr, sizeof (drr));
-	if (error != 0)
-		goto out;
-	zc.zc_begin_record = drr.drr_u.drr_begin;
+	zc.zc_begin_record = *begin_record;
 
 	/* zc_cookie is fd to read from */
 	zc.zc_cookie = fd;
@@ -703,6 +704,21 @@ out:
 	return (error);
 }
 
+int
+lzc_receive_basic(const char *snapname, nvlist_t *props, const char *origin,
+    boolean_t force, int fd)
+{
+	dmu_replay_record_t drr;
+	int error;
+
+	error = recv_read(fd, &drr, sizeof (drr));
+	if (error == 0) {
+		error = lzc_receive(snapname, props, origin, force, fd,
+		    &drr.drr_u.drr_begin);
+	}
+	return (error);
+}
+
 /*
  * Roll back this filesystem or volume to its most recent snapshot.
  * If snapnamebuf is not NULL, it will be filled in with the name
_______________________________________________
developer mailing list
[email protected]
http://lists.open-zfs.org/mailman/listinfo/developer

Reply via email to