summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Monitor.c88
-rw-r--r--ReadMe.c1
-rw-r--r--mdadm.86
-rw-r--r--mdadm.c4
-rw-r--r--mdadm.h5
-rw-r--r--monitor.c39
-rw-r--r--sysfs.c55
7 files changed, 166 insertions, 32 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;
+}
+
+
diff --git a/ReadMe.c b/ReadMe.c
index 12ed17f..1fcad30 100644
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -161,6 +161,7 @@ struct option long_options[] = {
{"readwrite", 0, 0, 'w'},
{"no-degraded",0,0, NoDegraded },
{"wait", 0, 0, 'W'},
+ {"wait-clean", 0, 0, Waitclean },
/* For Detail/Examine */
{"brief", 0, 0, 'b'},
diff --git a/mdadm.8 b/mdadm.8
index 3c283ca..ab659fc 100644
--- a/mdadm.8
+++ b/mdadm.8
@@ -1014,6 +1014,12 @@ activity to finish before returning.
will return with success if it actually waited for every device
listed, otherwise it will return failure.
+.TP
+.BR \-\-wait\-clean
+For each md device given, wait for the array to be marked clean before
+returning. For native arrays this returns immediately as the kernel
+handles dirty-clean transistions at shutdown.
+
.SH For Incremental Assembly mode:
.TP
.BR \-\-rebuild\-map ", " \-r
diff --git a/mdadm.c b/mdadm.c
index b7865ef..6732352 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -214,6 +214,7 @@ int main(int argc, char *argv[])
case 'o':
case 'w':
case 'W':
+ case Waitclean:
case 'K': if (!mode) newmode = MISC; break;
}
if (mode && newmode == mode) {
@@ -770,6 +771,7 @@ int main(int argc, char *argv[])
case O(MISC,'o'):
case O(MISC,'w'):
case O(MISC,'W'):
+ case O(MISC, Waitclean):
if (devmode && devmode != opt &&
(devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
fprintf(stderr, Name ": --examine/-E cannot be given with -%c\n",
@@ -1280,6 +1282,8 @@ int main(int argc, char *argv[])
rv |= ExamineBitmap(dv->devname, brief, ss); continue;
case 'W':
rv |= Wait(dv->devname); continue;
+ case Waitclean:
+ rv |= WaitClean(dv->devname); continue;
}
mdfd = open_mddev(dv->devname, 1);
if (mdfd>=0) {
diff --git a/mdadm.h b/mdadm.h
index 2eaaffd..5ef69f3 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -224,6 +224,7 @@ enum special_options {
AutoHomeHost,
Symlinks,
AutoDetect,
+ Waitclean,
};
/* structures read from config file */
@@ -327,6 +328,7 @@ extern void map_add(struct map_ent **melp,
#define GET_VERSION 64
#define GET_DISKS 128
#define GET_DEGRADED 256
+#define GET_SAFEMODE 512
#define GET_DEVS 1024 /* gets role, major, minor */
#define GET_OFFSET 2048
@@ -340,6 +342,8 @@ extern void map_add(struct map_ent **melp,
extern int sysfs_open(int devnum, char *devname, char *attr);
extern void sysfs_free(struct mdinfo *sra);
extern struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options);
+extern int sysfs_attr_match(const char *attr, const char *str);
+extern int sysfs_match_word(const char *word, char **list);
extern int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
char *name, char *val);
extern int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
@@ -705,6 +709,7 @@ extern int Monitor(mddev_dev_t devlist,
extern int Kill(char *dev, int force, int quiet, int noexcl);
extern int Wait(char *dev);
+extern int WaitClean(char *dev);
extern int Incremental(char *devname, int verbose, int runstop,
struct supertype *st, char *homehost, int autof);
diff --git a/monitor.c b/monitor.c
index a1d87e1..35f80a7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -47,7 +47,6 @@ static int read_attr(char *buf, int len, int fd)
return n;
}
-
int get_resync_start(struct active_array *a)
{
char buf[30];
@@ -62,30 +61,6 @@ int get_resync_start(struct active_array *a)
return 1;
}
-static int attr_match(const char *attr, const char *str)
-{
- /* See if attr, read from a sysfs file, matches
- * str. They must either be the same, or attr can
- * have a trailing newline or comma
- */
- while (*attr && *str && *attr == *str) {
- attr++;
- str++;
- }
-
- if (*str || (*attr && *attr != ',' && *attr != '\n'))
- return 0;
- return 1;
-}
-
-static int match_word(const char *word, char **list)
-{
- int n;
- for (n=0; list[n]; n++)
- if (attr_match(word, list[n]))
- break;
- return n;
-}
static enum array_state read_state(int fd)
{
@@ -94,7 +69,7 @@ static enum array_state read_state(int fd)
if (n <= 0)
return bad_word;
- return (enum array_state) match_word(buf, array_states);
+ return (enum array_state) sysfs_match_word(buf, array_states);
}
static enum sync_action read_action( int fd)
@@ -104,7 +79,7 @@ static enum sync_action read_action( int fd)
if (n <= 0)
return bad_action;
- return (enum sync_action) match_word(buf, sync_actions);
+ return (enum sync_action) sysfs_match_word(buf, sync_actions);
}
int read_dev_state(int fd)
@@ -119,15 +94,15 @@ int read_dev_state(int fd)
cp = buf;
while (cp) {
- if (attr_match(cp, "faulty"))
+ if (sysfs_attr_match(cp, "faulty"))
rv |= DS_FAULTY;
- if (attr_match(cp, "in_sync"))
+ if (sysfs_attr_match(cp, "in_sync"))
rv |= DS_INSYNC;
- if (attr_match(cp, "write_mostly"))
+ if (sysfs_attr_match(cp, "write_mostly"))
rv |= DS_WRITE_MOSTLY;
- if (attr_match(cp, "spare"))
+ if (sysfs_attr_match(cp, "spare"))
rv |= DS_SPARE;
- if (attr_match(cp, "blocked"))
+ if (sysfs_attr_match(cp, "blocked"))
rv |= DS_BLOCKED;
cp = strchr(cp, ',');
if (cp)
diff --git a/sysfs.c b/sysfs.c
index dced322..182028c 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -25,6 +25,7 @@
#include "mdadm.h"
#include <dirent.h>
+#include <ctype.h>
int load_sys(char *path, char *buf)
{
@@ -185,6 +186,35 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
goto abort;
sra->mismatch_cnt = strtoul(buf, NULL, 0);
}
+ if (options & GET_SAFEMODE) {
+ int scale = 1;
+ int dot = 0;
+ int i;
+ unsigned long msec;
+ size_t len;
+
+ strcpy(base, "safe_mode_delay");
+ if (load_sys(fname, buf))
+ goto abort;
+
+ /* remove a period, and count digits after it */
+ len = strlen(buf);
+ for (i = 0; i < len; i++) {
+ if (dot) {
+ if (isdigit(buf[i])) {
+ buf[i-1] = buf[i];
+ scale *= 10;
+ }
+ buf[i] = 0;
+ } else if (buf[i] == '.') {
+ dot=1;
+ buf[i] = 0;
+ }
+ }
+ msec = strtoul(buf, NULL, 10);
+ msec = (msec * 1000) / scale;
+ sra->safe_mode_delay = msec;
+ }
if (! (options & GET_DEVS))
return sra;
@@ -265,6 +295,31 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
return NULL;
}
+int sysfs_attr_match(const char *attr, const char *str)
+{
+ /* See if attr, read from a sysfs file, matches
+ * str. They must either be the same, or attr can
+ * have a trailing newline or comma
+ */
+ while (*attr && *str && *attr == *str) {
+ attr++;
+ str++;
+ }
+
+ if (*str || (*attr && *attr != ',' && *attr != '\n'))
+ return 0;
+ return 1;
+}
+
+int sysfs_match_word(const char *word, char **list)
+{
+ int n;
+ for (n=0; list[n]; n++)
+ if (sysfs_attr_match(word, list[n]))
+ break;
+ return n;
+}
+
unsigned long long get_component_size(int fd)
{
/* Find out the component size of the array.