summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2014-10-02 19:15:38 +0200
committerDavid Sterba <dsterba@suse.cz>2014-10-10 10:38:36 +0200
commitd5fd05a773e2b19455be7e1208e9003a607483c6 (patch)
treec18b82618c80c9a13aca91c5bb862f92ddac3ae4
parentf32d749e66c2914d18f0acaad759e98fd829926a (diff)
btrfs-progs: scrub, detect stale information in the status file
If scrub is not cancelled nor finished, the recorded status will prevent scrub to start again though it's not running. There's a force option to run it anyway, but this is just a bandaid and the true status of scrub should be detected automatically. The force option should not be necessary anymore. The test introduced in 9681f82853360aac1ff2 checks only the status file, not kernel status of scrub. Signed-off-by: David Sterba <dsterba@suse.cz>
-rw-r--r--cmds-scrub.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/cmds-scrub.c b/cmds-scrub.c
index 731c5c94..eb50d8a6 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -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,28 @@ 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 < 0 && errno == ENODEV)
+ continue;
+ if (ret < 0 && errno == ENOTCONN)
+ return 0;
+ if (!ret)
+ return 1;
+ }
+
+ return 1;
+}
+
static const char * const cmd_scrub_start_usage[];
static const char * const cmd_scrub_resume_usage[];
@@ -1206,6 +1233,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
@@ -1636,6 +1670,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;
@@ -1725,6 +1760,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);
@@ -1737,6 +1773,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",
@@ -1744,6 +1781,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);