Btrfs-progs: receive, allow to continue after errors happen
authorFilipe David Borba Manana <fdmanana@gmail.com>
Fri, 23 May 2014 19:14:56 +0000 (20:14 +0100)
committerDavid Sterba <dsterba@suse.cz>
Fri, 22 Aug 2014 12:39:32 +0000 (14:39 +0200)
Due to either bugs in send (kernel) that generate a command against
a wrong path for example, or transient errors on the receiving side,
we stopped processing the send stream immediately and exited with
an error.

It's often desirable to continue processing the send stream even if an
error happens while processing a single command from the send stream.

This change just adds a --max-errors <N> parameter, whose default value
is 1 (preserving current behaviour), that allows to tolerate N errors
before stopping. A value of 0 means to never stop no matter how many
errors we get into while processing the send stream. Regardless of its
value, errors are always printed to stderr when they happen, just like
before this change.

Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.cz>
Documentation/btrfs-receive.txt
cmds-receive.c
send-stream.c
send-stream.h

index 8261160..78dc511 100644 (file)
@@ -38,6 +38,9 @@ Use this option to specify a file to use instead.
 Terminate after receiving an <end cmd> in the data stream.
 Without this option, the receiver terminates only if an error is recognized
 or on EOF.
+--max-errors <N>::
+Terminate as soon as N errors happened while processing commands from the send
+stream. Default value is 1. A value of 0 means no limit.
 
 EXIT STATUS
 -----------
index 8d85ca9..87dc1b4 100644 (file)
@@ -32,6 +32,7 @@
 #include <ftw.h>
 #include <wait.h>
 #include <assert.h>
+#include <getopt.h>
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -816,7 +817,8 @@ static struct btrfs_send_ops send_ops = {
        .utimes = process_utimes,
 };
 
-static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
+static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd,
+                     u64 max_errors)
 {
        int ret;
        char *dest_dir_full_path;
@@ -868,7 +870,8 @@ static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
 
        while (!end) {
                ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
-                                                        r->honor_end_cmd);
+                                                        r->honor_end_cmd,
+                                                        max_errors);
                if (ret < 0)
                        goto out;
                if (ret)
@@ -911,6 +914,11 @@ out:
        return ret;
 }
 
+static const struct option long_opts[] = {
+       { "max-errors", 1, NULL, 'E' },
+       { NULL, 0, NULL, 0 }
+};
+
 int cmd_receive(int argc, char **argv)
 {
        int c;
@@ -918,7 +926,7 @@ int cmd_receive(int argc, char **argv)
        char *fromfile = NULL;
        struct btrfs_receive r;
        int receive_fd = fileno(stdin);
-
+       u64 max_errors = 1;
        int ret;
 
        memset(&r, 0, sizeof(r));
@@ -926,7 +934,7 @@ int cmd_receive(int argc, char **argv)
        r.write_fd = -1;
        r.dest_dir_fd = -1;
 
-       while ((c = getopt(argc, argv, "evf:")) != -1) {
+       while ((c = getopt_long(argc, argv, "evf:", long_opts, NULL)) != -1) {
                switch (c) {
                case 'v':
                        g_verbose++;
@@ -937,6 +945,9 @@ int cmd_receive(int argc, char **argv)
                case 'e':
                        r.honor_end_cmd = 1;
                        break;
+               case 'E':
+                       max_errors = arg_strtou64(optarg);
+                       break;
                case '?':
                default:
                        fprintf(stderr, "ERROR: receive args invalid.\n");
@@ -957,7 +968,7 @@ int cmd_receive(int argc, char **argv)
                }
        }
 
-       ret = do_receive(&r, tomnt, receive_fd);
+       ret = do_receive(&r, tomnt, receive_fd, max_errors);
 
        return !!ret;
 }
@@ -983,5 +994,8 @@ const char * const cmd_receive_usage[] = {
        "                 in the data stream. Without this option,",
        "                 the receiver terminates only if an error",
        "                 is recognized or on EOF.",
+       "--max-errors <N> Terminate as soon as N errors happened while",
+       "                 processing commands from the send stream.",
+       "                 Default value is 1. A value of 0 means no limit.",
        NULL
 };
index 88e18e2..ef4d889 100644 (file)
@@ -435,13 +435,21 @@ out:
        return ret;
 }
 
+/*
+ * If max_errors is 0, then don't stop processing the stream if one of the
+ * callbacks in btrfs_send_ops structure returns an error. If greater than
+ * zero, stop after max_errors errors happened.
+ */
 int btrfs_read_and_process_send_stream(int fd,
                                       struct btrfs_send_ops *ops, void *user,
-                                      int honor_end_cmd)
+                                      int honor_end_cmd,
+                                      u64 max_errors)
 {
        int ret;
        struct btrfs_send_stream s;
        struct btrfs_stream_header hdr;
+       u64 errors = 0;
+       int last_err = 0;
 
        s.fd = fd;
        s.ops = ops;
@@ -471,9 +479,12 @@ int btrfs_read_and_process_send_stream(int fd,
 
        while (1) {
                ret = read_and_process_cmd(&s);
-               if (ret < 0)
-                       goto out;
-               if (ret) {
+               if (ret < 0) {
+                       last_err = ret;
+                       errors++;
+                       if (max_errors > 0 && errors >= max_errors)
+                               goto out;
+               } else if (ret > 0) {
                        if (!honor_end_cmd)
                                ret = 0;
                        goto out;
@@ -481,5 +492,8 @@ int btrfs_read_and_process_send_stream(int fd,
        }
 
 out:
+       if (last_err && !ret)
+               ret = last_err;
+
        return ret;
 }
index 17bc669..293bf6a 100644 (file)
@@ -58,7 +58,8 @@ struct btrfs_send_ops {
 
 int btrfs_read_and_process_send_stream(int fd,
                                       struct btrfs_send_ops *ops, void *user,
-                                      int honor_end_cmd);
+                                      int honor_end_cmd,
+                                      u64 max_errors);
 
 #ifdef __cplusplus
 }