btrfs-progs: fix check of running scrub
[platform/upstream/btrfs-progs.git] / cmds-scrub.c
index d4acfd2..06c2a30 100644 (file)
@@ -59,6 +59,7 @@ struct scrub_stats {
        u64 duration;
        u64 finished;
        u64 canceled;
+       int in_progress;
 };
 
 /* TBD: replace with #include "linux/ioprio.h" in some years */
@@ -251,7 +252,11 @@ static void _print_scrub_ss(struct scrub_stats *ss)
                printf(" and was aborted after %llu seconds\n",
                       ss->duration);
        } else {
-               printf(", running for %llu seconds\n", ss->duration);
+               if (ss->in_progress)
+                       printf(", running for %llu seconds\n", ss->duration);
+               else
+                       printf(", interrupted after %llu seconds, not running\n",
+                                       ss->duration);
        }
 }
 
@@ -1057,6 +1062,24 @@ static int is_scrub_running_on_fs(struct btrfs_ioctl_fs_info_args *fi_args,
        return 0;
 }
 
+static int is_scrub_running_in_kernel(int fd,
+               struct btrfs_ioctl_dev_info_args *di_args, u64 max_devices)
+{
+       struct scrub_progress sp;
+       int i;
+       int ret;
+
+       for (i = 0; i < max_devices; i++) {
+               memset(&sp, 0, sizeof(sp));
+               sp.scrub_args.devid = di_args[i].devid;
+               ret = ioctl(fd, BTRFS_IOC_SCRUB_PROGRESS, &sp.scrub_args);
+               if (!ret)
+                       return 1;
+       }
+
+       return 0;
+}
+
 static const char * const cmd_scrub_start_usage[];
 static const char * const cmd_scrub_resume_usage[];
 
@@ -1206,6 +1229,13 @@ static int scrub_start(int argc, char **argv, int resume)
        }
 
        /*
+        * Check for stale information in the status file, ie. if it's
+        * canceled=0, finished=0 but no scrub is running.
+        */
+       if (!is_scrub_running_in_kernel(fdmnt, di_args, fi_args.num_devices))
+               force = 1;
+
+       /*
         * check whether any involved device is already busy running a
         * scrub. This would cause damaged status messages and the state
         * "aborted" without the explanation that a scrub was already
@@ -1533,10 +1563,10 @@ static const char * const cmd_scrub_start_usage[] = {
        "-d     stats per device (-B only)",
        "-q     be quiet",
        "-r     read only mode",
-       "-R     raw print mode, print full data instead of summary"
+       "-R     raw print mode, print full data instead of summary",
        "-c     set ioprio class (see ionice(1) manpage)",
        "-n     set ioprio classdata (see ionice(1) manpage)",
-       "-f     force starting new scrub even if a scrub is already running.",
+       "-f     force starting new scrub even if a scrub is already running",
        "       this is useful when scrub stats record file is damaged",
        NULL
 };
@@ -1605,6 +1635,7 @@ static const char * const cmd_scrub_resume_usage[] = {
        "-d     stats per device (-B only)",
        "-q     be quiet",
        "-r     read only mode",
+       "-R     raw print mode, print full data instead of summary",
        "-c     set ioprio class (see ionice(1) manpage)",
        "-n     set ioprio classdata (see ionice(1) manpage)",
        NULL
@@ -1635,6 +1666,7 @@ static int cmd_scrub_status(int argc, char **argv)
        struct sockaddr_un addr = {
                .sun_family = AF_UNIX,
        };
+       int in_progress;
        int ret;
        int i;
        int fdmnt;
@@ -1724,6 +1756,7 @@ static int cmd_scrub_status(int argc, char **argv)
                        fprintf(stderr, "WARNING: failed to read status: %s\n",
                                strerror(-PTR_ERR(past_scrubs)));
        }
+       in_progress = is_scrub_running_in_kernel(fdmnt, di_args, fi_args.num_devices);
 
        printf("scrub status for %s\n", fsid);
 
@@ -1736,6 +1769,7 @@ static int cmd_scrub_status(int argc, char **argv)
                                                NULL, NULL);
                                continue;
                        }
+                       last_scrub->stats.in_progress = in_progress;
                        print_scrub_dev(&di_args[i], &last_scrub->p, print_raw,
                                        last_scrub->stats.finished ?
                                                        "history" : "status",
@@ -1743,6 +1777,7 @@ static int cmd_scrub_status(int argc, char **argv)
                }
        } else {
                init_fs_stat(&fs_stat);
+               fs_stat.s.in_progress = in_progress;
                for (i = 0; i < fi_args.num_devices; ++i) {
                        last_scrub = last_dev_scrub(past_scrubs,
                                                        di_args[i].devid);