On  7/07/10 12:06 AM, Pawel Jakub Dawidek wrote:
On Tue, Jul 06, 2010 at 05:37:41PM -0700, Darren Reed wrote:
I had some spare time over the long weekend to have a play with this.

I've filed the bug as CR#6967089. The patch (or suggested fix) is below.

I'll probably work on it a bit more to test it and see if it needs any
other changes.
[...]
      zc.zc_begin_record = drr_noswap->drr_u.drr_begin;
      zc.zc_cookie = infd;
-    zc.zc_guid = flags.force;
-    if (flags.verbose) {
-        (void) printf("%s %s stream of %s into %s\n",
-            flags.dryrun ? "would receive" : "receiving",
-            drrb->drr_fromguid ? "incremental" : "full",
-            drrb->drr_toname, zc.zc_value);
-        (void) fflush(stdout);
+    zc.zc_guid = flags->force;
+    skipstream = flags->dryrun;
+    if (flags->verbose) {
+        if (flags->matching != NULL&&
+            strcmp(drrb->drr_toname, flags->matching)) {
+            (void) printf("skipping stream %s due to mismatch\n",
+                drrb->drr_toname);
+            (void) fflush(stdout);
+            skipstream = B_TRUE;

Am I correct in reading the patch that unmatching streams will be
skipped only in verbose mode?

Like I said, it needed further testing O:-) See below.

Someone asked me why I thought I needed this because "zfs send
t...@send" should send only "t...@send" and not all of its
descendants. In reviewing the man page for zfs(1m), I note that
I interpret the documentation to mean that unless I do "-R",
then not all of the properties are sent across.  From the man
page:

     zfs send [-vR] [-[iI] snapshot] snapshot

         Creates a stream representation of the second  snapshot,
         which  is  written to standard output. The output can be
         redirected to a file or to a different system (for exam-
         ple,  using  ssh(1).  By  default, a full stream is gen-
         erated.

... no mention here of properties ...


         -R

             Generate a replication stream  package,  which  will
             replicate  the specified filesystem, and all descen-
             dent file systems, up to the  named  snapshot.  When
             received, all properties, snapshots, descendent file
             systems, and clones are preserved.

... here properties are mentioned, implying that without "-R"
the data stream will not have all of the properties associated
with the filesystem included. If "full stream" is meant to cover
this then I'd suggest that the man page needs to explicitly
state what a "full stream" is. At present, "full stream" does
not appear to be defined by that man page.

Thus having read the man page, I'm given the impression that
I always need to use "-R" even if I just want to send a single
snapshot of a pool. It might also be worth mentioning the word
"recursive" with "-R" (I know that this is a keyword I look
for when reading man pages to do with filesystems and
directories if I'm concerned about that type of behaviour.)

Having said all of that, I can conceive of times when it
would be useful to just receive a particular dataset from
inside a zfs data stream (like you've dump'd an entire
pool using 'zfs send t...@send' but then after restoring,
you have an accident and destroy one filesystem on your
recipient and you're not real keen on sending that whole
data set back again, making the entire pool unusable for
the same of one small filesystem.)

Darren

remote: Not trusting file /export/onnv-clone/.hg/hgrc from untrusted user onhg, group gk remote: Not trusting file /export/onnv-clone/.hg/hgrc from untrusted user onhg, group gk
diff -r 6ab6e1b7e92f usr/src/cmd/zfs/zfs_main.c
--- a/usr/src/cmd/zfs/zfs_main.c    Wed Jun 30 19:40:00 2010 -0400
+++ b/usr/src/cmd/zfs/zfs_main.c    Wed Jul 07 15:44:58 2010 -0700
@@ -2758,10 +2758,10 @@
 zfs_do_receive(int argc, char **argv)
 {
     int c, err;
-    recvflags_t flags = { 0 };
-
-    /* check options */
-    while ((c = getopt(argc, argv, ":denuvF")) != -1) {
+    recvflags_t flags = { 0, NULL };
+
+    /* check options */
+    while ((c = getopt(argc, argv, ":denm:uvF")) != -1) {
         switch (c) {
         case 'd':
             flags.isprefix = B_TRUE;
@@ -2770,6 +2770,9 @@
             flags.isprefix = B_TRUE;
             flags.istail = B_TRUE;
             break;
+        case 'm':
+            flags.matching = optarg;
+            break;
         case 'n':
             flags.dryrun = B_TRUE;
             break;
@@ -2815,7 +2818,7 @@
         return (1);
     }

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

     return (err != 0);
 }
diff -r 6ab6e1b7e92f usr/src/lib/libzfs/common/libzfs.h
--- a/usr/src/lib/libzfs/common/libzfs.h    Wed Jun 30 19:40:00 2010 -0400
+++ b/usr/src/lib/libzfs/common/libzfs.h    Wed Jul 07 15:44:58 2010 -0700
@@ -574,9 +574,12 @@

     /* do not mount file systems as they are extracted (private) */
     int nomount : 1;
+
+    /* only receive the matching volume */
+    char *matching;
 } recvflags_t;

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

 /*
diff -r 6ab6e1b7e92f usr/src/lib/libzfs/common/libzfs_sendrecv.c
--- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c Wed Jun 30 19:40:00 2010 -0400 +++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c Wed Jul 07 15:44:58 2010 -0700
@@ -50,7 +50,7 @@
 /* in libzfs_dataset.c */
 extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);

-static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t,
+static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t *,
int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *);

 static const zio_cksum_t zero_cksum = { 0 };
@@ -1470,7 +1470,7 @@

 static int
 recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
-    int baselen, char *newname, recvflags_t flags)
+    int baselen, char *newname, recvflags_t *flags)
 {
     static int seq;
     zfs_cmd_t zc = { 0 };
@@ -1482,7 +1482,7 @@
     if (zhp == NULL)
         return (-1);
     clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
-        flags.force ? MS_FORCE : 0);
+        flags->force ? MS_FORCE : 0);
     zfs_close(zhp);
     if (clp == NULL)
         return (-1);
@@ -1498,7 +1498,7 @@

         (void) strlcpy(zc.zc_value, tryname, sizeof (zc.zc_value));

-        if (flags.verbose) {
+        if (flags->verbose) {
             (void) printf("attempting rename %s to %s\n",
                 zc.zc_name, zc.zc_value);
         }
@@ -1517,19 +1517,19 @@
             "recv-%u-%u", getpid(), seq);
         (void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value));

-        if (flags.verbose) {
+        if (flags->verbose) {
             (void) printf("failed - trying rename %s to %s\n",
                 zc.zc_name, zc.zc_value);
         }
         err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc);
         if (err == 0)
             changelist_rename(clp, name, newname);
-        if (err && flags.verbose) {
+        if (err && flags->verbose) {
             (void) printf("failed (%u) - "
                 "will try again on next pass\n", errno);
         }
         err = EAGAIN;
-    } else if (flags.verbose) {
+    } else if (flags->verbose) {
         if (err == 0)
             (void) printf("success\n");
         else
@@ -1544,7 +1544,7 @@

 static int
 recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
-    char *newname, recvflags_t flags)
+    char *newname, recvflags_t *flags)
 {
     zfs_cmd_t zc = { 0 };
     int err = 0;
@@ -1557,7 +1557,7 @@
     if (zhp == NULL)
         return (-1);
     clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
-        flags.force ? MS_FORCE : 0);
+        flags->force ? MS_FORCE : 0);
     if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
         zfs_spa_version(zhp, &spa_version) == 0 &&
         spa_version >= SPA_VERSION_USERREFS)
@@ -1573,11 +1573,11 @@
     zc.zc_defer_destroy = defer;
     (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));

-    if (flags.verbose)
+    if (flags->verbose)
         (void) printf("attempting destroy %s\n", zc.zc_name);
     err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc);
     if (err == 0) {
-        if (flags.verbose)
+        if (flags->verbose)
             (void) printf("success\n");
         changelist_remove(clp, zc.zc_name);
     }
@@ -1701,7 +1701,7 @@

 static int
 recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
-    recvflags_t flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
+    recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
     nvlist_t *renamed)
 {
     nvlist_t *local_nv;
@@ -1718,7 +1718,7 @@
     recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
         ENOENT);

-    if (flags.dryrun)
+    if (flags->dryrun)
         return (0);

 again:
@@ -1778,7 +1778,7 @@
                 nvlist_t *origin_nvfs;
                 char *origin_fsname;

-                if (flags.verbose)
+                if (flags->verbose)
                     (void) printf("promoting %s\n", fsname);

                 origin_nvfs = fsavl_find(local_avl, originguid,
@@ -1826,7 +1826,7 @@
             if (found == NULL) {
                 char name[ZFS_MAXNAMELEN];

-                if (!flags.force)
+                if (!flags->force)
                     continue;

                 (void) snprintf(name, sizeof (name), "%...@%s",
@@ -1884,7 +1884,7 @@

         /* check for delete */
         if (stream_nvfs == NULL) {
-            if (!flags.force)
+            if (!flags->force)
                 continue;

             error = recv_destroy(hdl, fsname, strlen(tofs)+1,
@@ -1897,7 +1897,7 @@
         }

         if (fromguid == 0) {
-            if (flags.verbose) {
+            if (flags->verbose) {
                 (void) printf("local fs %s does not have "
                     "fromsnap (%s in stream); must have "
                     "been deleted locally; ignoring\n",
@@ -1922,7 +1922,7 @@
         if ((stream_parent_fromsnap_guid != 0 &&
             parent_fromsnap_guid != 0 &&
             stream_parent_fromsnap_guid != parent_fromsnap_guid) ||
-            ((flags.isprefix || strcmp(tofs, fsname) != 0) &&
+            ((flags->isprefix || strcmp(tofs, fsname) != 0) &&
             (s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {
             nvlist_t *parent;
             char tryname[ZFS_MAXNAMELEN];
@@ -1945,7 +1945,7 @@
                     "%s%s", pname, strrchr(stream_fsname, '/'));
             } else {
                 tryname[0] = '\0';
-                if (flags.verbose) {
+                if (flags->verbose) {
                     (void) printf("local fs %s new parent "
                         "not found\n", fsname);
                 }
@@ -1973,7 +1973,7 @@

     if (needagain && progress) {
         /* do another pass to fix up temporary names */
-        if (flags.verbose)
+        if (flags->verbose)
             (void) printf("another pass:\n");
         goto again;
     }
@@ -1983,7 +1983,7 @@

 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,
+    recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
     char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
 {
     nvlist_t *stream_nv = NULL;
@@ -2012,7 +2012,7 @@
      */
     if (drr->drr_payloadlen != 0) {
         error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen,
- &stream_nv, flags.byteswap, zc);
+ &stream_nv, flags->byteswap, zc);
         if (error) {
             error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
             goto out;
@@ -2033,9 +2033,9 @@
      * Read in the end record and verify checksum.
      */
     if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre),
-        flags.byteswap, NULL)))
+        flags->byteswap, NULL)))
         goto out;
-    if (flags.byteswap) {
+    if (flags->byteswap) {
         drre.drr_type = BSWAP_32(drre.drr_type);
         drre.drr_u.drr_end.drr_checksum.zc_word[0] =
             BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]);
@@ -2076,11 +2076,11 @@
             nvpair_t *pair = NULL;

             (void) strlcpy(tofs, destname, ZFS_MAXNAMELEN);
-            if (flags.isprefix) {
+            if (flags->isprefix) {
                 struct drr_begin *drrb = &drr->drr_u.drr_begin;
                 int i;

-                if (flags.istail) {
+                if (flags->istail) {
                     cp = strrchr(drrb->drr_toname, '/');
                     if (cp == NULL) {
                         (void) strlcat(tofs, "/",
@@ -2098,7 +2098,7 @@
                 *strchr(tofs, '@') = '\0';
             }

-            if (recursive && !flags.dryrun && !flags.nomount) {
+            if (recursive && !flags->dryrun && !flags->nomount) {
                 VERIFY(0 == nvlist_alloc(&renamed,
                     NV_UNIQUE_NAME, 0));
             }
@@ -2272,7 +2272,7 @@
  */
 static int
 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
-    recvflags_t flags, dmu_replay_record_t *drr,
+    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)
@@ -2292,6 +2292,7 @@
     nvlist_t *snapprops_nvlist = NULL;
     zprop_errflags_t prop_errflags;
     boolean_t recursive;
+    boolean_t skipstream;

     begin_time = time(NULL);

@@ -2314,7 +2315,7 @@
         if (err)
             VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));

-        if (flags.canmountoff) {
+        if (flags->canmountoff) {
             VERIFY(0 == nvlist_add_uint64(props,
                 zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
         }
@@ -2341,7 +2342,7 @@
      * If they specified a snapshot, chop the entire name stored in
      * the stream.
      */
-    if (flags.istail) {
+    if (flags->istail) {
         /*
          * A filesystem was specified with -e. We want to tack on only
          * the tail of the sent snapshot path.
@@ -2367,7 +2368,7 @@
         } else {
             chopprefix = drrb->drr_toname + (chopprefix - sendfs);
         }
-    } else if (flags.isprefix) {
+    } else if (flags->isprefix) {
         /*
          * A filesystem was specified with -d. We want to tack on
          * everything but the first element of the sent snapshot path
@@ -2429,7 +2430,7 @@
                 zc.zc_value);
             return (zfs_error(hdl, EZFS_NOENT, errbuf));
         }
-        if (flags.verbose)
+        if (flags->verbose)
             (void) printf("found clone origin %s\n", zc.zc_string);
     }

@@ -2474,7 +2475,7 @@
          * topmost path in the stream, then if the fs does not exist we
          * should look no further.
          */
-        if ((flags.isprefix || (*(chopprefix = drrb->drr_toname +
+        if ((flags->isprefix || (*(chopprefix = drrb->drr_toname +
             strlen(sendfs)) != '\0' && *chopprefix != '@')) &&
             !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
             char snap[ZFS_MAXNAMELEN];
@@ -2501,7 +2502,7 @@
          * snapshots).
          */
         if (stream_wantsnewfs) {
-            if (!flags.force) {
+            if (!flags->force) {
                 zcmd_free_nvlists(&zc);
                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                     "destination '%s' exists\n"
@@ -2537,7 +2538,7 @@
             return (zfs_error(hdl, EZFS_EXISTS, errbuf));
         }

-        if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
+        if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
             stream_wantsnewfs) {
             /* We can't do online recv in this case */
             clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0);
@@ -2576,7 +2577,7 @@
          */
         *cp = '\0';

-        if (flags.isprefix && !flags.istail && !flags.dryrun &&
+        if (flags->isprefix && !flags->istail && !flags->dryrun &&
             create_parents(hdl, zc.zc_value, strlen(tosnap)) != 0) {
             zcmd_free_nvlists(&zc);
             return (zfs_error(hdl, EZFS_BADRESTORE, errbuf));
@@ -2587,18 +2588,31 @@

     zc.zc_begin_record = drr_noswap->drr_u.drr_begin;
     zc.zc_cookie = infd;
-    zc.zc_guid = flags.force;
-    if (flags.verbose) {
-        (void) printf("%s %s stream of %s into %s\n",
-            flags.dryrun ? "would receive" : "receiving",
-            drrb->drr_fromguid ? "incremental" : "full",
-            drrb->drr_toname, zc.zc_value);
-        (void) fflush(stdout);
+    zc.zc_guid = flags->force;
+    skipstream = flags->dryrun;
+
+    if (flags->verbose) {
+        if (flags->matching != NULL &&
+            strcmp(drrb->drr_toname, flags->matching)) {
+            (void) printf("skipping stream %s due to mismatch\n",
+                drrb->drr_toname);
+            (void) fflush(stdout);
+            skipstream = B_TRUE;
+        } else {
+            (void) printf("%s %s stream of %s into %s\n",
+                flags->dryrun ? "would receive" : "receiving",
+                drrb->drr_fromguid ? "incremental" : "full",
+                drrb->drr_toname, zc.zc_value);
+            (void) fflush(stdout);
+        }
+    } else if (!skipstream && flags->matching != NULL &&
+        strcmp(drrb->drr_toname, flags->matching) != 0) {
+        skipstream = B_TRUE;
     }

-    if (flags.dryrun) {
+    if (skipstream) {
         zcmd_free_nvlists(&zc);
-        return (recv_skip(hdl, infd, flags.byteswap));
+        return (recv_skip(hdl, infd, flags->byteswap));
     }

     zc.zc_nvlist_dst = (uint64_t)(uintptr_t)prop_errbuf;
@@ -2679,12 +2693,12 @@
             nvlist_free(local_nv);

             if (fs != NULL) {
-                if (flags.verbose) {
+                if (flags->verbose) {
                     (void) printf("snap %s already exists; "
                         "ignoring\n", zc.zc_value);
                 }
                 err = ioctl_err = recv_skip(hdl, infd,
-                    flags.byteswap);
+                    flags->byteswap);
             }
         }
         *cp = '@';
@@ -2794,7 +2808,7 @@

     *action_handlep = zc.zc_action_handle;

-    if (flags.verbose) {
+    if (flags->verbose) {
         char buf1[64];
         char buf2[64];
         uint64_t bytes = zc.zc_cookie;
@@ -2812,7 +2826,7 @@
 }

 static int
-zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags, +zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, 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)
 {
@@ -2827,7 +2841,7 @@
     (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
         "cannot receive"));

-    if (flags.isprefix &&
+    if (flags->isprefix &&
         !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
         zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
             "(%s) does not exist"), tosnap);
@@ -2847,7 +2861,7 @@
     /* the kernel needs the non-byteswapped begin record */
     drr_noswap = drr;

-    flags.byteswap = B_FALSE;
+    flags->byteswap = B_FALSE;
     if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
         /*
          * We computed the checksum in the wrong byteorder in
@@ -2855,7 +2869,7 @@
          */
         bzero(&zcksum, sizeof (zio_cksum_t));
         fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum);
-        flags.byteswap = B_TRUE;
+        flags->byteswap = B_TRUE;

         drr.drr_type = BSWAP_32(drr.drr_type);
         drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen);
@@ -2923,7 +2937,7 @@
  * (-1 will override -2).
  */
 int
-zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
+zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
     int infd, avl_tree_t *stream_avl)
 {
     char *top_zfs = NULL;
@@ -2939,7 +2953,7 @@

     VERIFY(0 == close(cleanup_fd));

-    if (err == 0 && !flags.nomount && top_zfs) {
+    if (err == 0 && !flags->nomount && top_zfs) {
         zfs_handle_t *zhp;
         prop_changelist_t *clp;

_______________________________________________
zfs-code mailing list
[email protected]
http://mail.opensolaris.org/mailman/listinfo/zfs-code

Reply via email to