summaryrefslogtreecommitdiffstats
path: root/Monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'Monitor.c')
-rw-r--r--Monitor.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/Monitor.c b/Monitor.c
index b02ab3c..3197b42 100644
--- a/Monitor.c
+++ b/Monitor.c
@@ -628,3 +628,91 @@ int Wait(char *dev)
mdstat_wait(5);
}
}
+
+static char *clean_states[] = {
+ "clear", "inactive", "readonly", "read-auto", "clean", NULL };
+
+int WaitClean(char *dev)
+{
+ int fd;
+ struct mdinfo *mdi;
+ int rv = 1;
+ int devnum;
+
+ fd = open(dev, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, Name ": Couldn't open %s: %s\n", dev, strerror(errno));
+ return 1;
+ }
+
+ devnum = fd2devnum(fd);
+ mdi = sysfs_read(fd, devnum, GET_VERSION|GET_LEVEL|GET_SAFEMODE);
+ if (!mdi) {
+ fprintf(stderr, Name ": Failed to read sysfs attributes for "
+ "%s\n", dev);
+ close(fd);
+ return 0;
+ }
+
+ switch(mdi->array.level) {
+ case LEVEL_LINEAR:
+ case LEVEL_MULTIPATH:
+ case 0:
+ /* safemode delay is irrelevant for these levels */
+ rv = 0;
+
+ }
+
+ /* for internal metadata the kernel handles the final clean
+ * transition, containers can never be dirty
+ */
+ if (!is_subarray(mdi->text_version))
+ rv = 0;
+
+ /* safemode disabled ? */
+ if (mdi->safe_mode_delay == 0)
+ rv = 0;
+
+ if (rv) {
+ int state_fd = sysfs_open(fd2devnum(fd), NULL, "array_state");
+ unsigned long secs;
+ char buf[20];
+
+ secs = mdi->safe_mode_delay / 1000;
+ if (mdi->safe_mode_delay - secs * 1000)
+ secs++;
+ secs *= 2;
+
+ for (; secs; secs--) {
+ rv = read(state_fd, buf, sizeof(buf));
+ if (rv < 0)
+ break;
+ if (sysfs_match_word(buf, clean_states) <= 4)
+ break;
+ sleep(1);
+ lseek(state_fd, 0, SEEK_SET);
+ }
+ if (rv < 0)
+ rv = 1;
+ else if (secs) {
+ /* we need to ping to close the window between array
+ * state transitioning to clean and the metadata being
+ * marked clean
+ */
+ if (ping_monitor(mdi->text_version) == 0)
+ rv = 0;
+ }
+ if (rv)
+ fprintf(stderr, Name ": Error waiting for %s to be clean\n",
+ dev);
+
+ close(state_fd);
+ }
+
+ sysfs_free(mdi);
+ close(fd);
+
+ return rv;
+}
+
+