Grow: fix hang when reshape completes too fast
authorDan Williams <dan.j.williams@intel.com>
Sun, 12 Apr 2009 07:58:28 +0000 (00:58 -0700)
committerDan Williams <dan.j.williams@intel.com>
Sun, 12 Apr 2009 07:58:28 +0000 (00:58 -0700)
For short reshapes the kernel may be done before mdadm can check that
progress has passed the critical section.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Grow.c
mdadm.h
sysfs.c

diff --git a/Grow.c b/Grow.c
index 14e48f5..7083c18 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -809,12 +809,20 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                /* wait for reshape to pass the critical region */
                while(1) {
                        unsigned long long comp;
+                       char a[20];
+
                        if (sysfs_get_ll(sra, NULL, "sync_completed", &comp)<0) {
                                sleep(5);
                                break;
                        }
                        if (comp >= nstripe)
                                break;
+
+                       /* perhaps the entire reshape has completed */
+                       if (comp == 0 &&
+                           sysfs_get_str(sra, NULL, "sync_action", a, sizeof(a)) == 0 &&
+                           strncmp(a, "idle", 4) == 0)
+                               break;
                        sleep(1);
                }
 
diff --git a/mdadm.h b/mdadm.h
index c33ec24..82c7ded 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -372,6 +372,8 @@ extern int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
 extern int sysfs_uevent(struct mdinfo *sra, char *event);
 extern int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
                        char *name, unsigned long long *val);
+extern int sysfs_get_str(struct mdinfo *sra, struct mdinfo *dev,
+                        char *name, char *buf, int buf_len);
 extern int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms);
 extern int sysfs_set_array(struct mdinfo *info, int vers);
 extern int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd);
diff --git a/sysfs.c b/sysfs.c
index 48d1f54..31c92f7 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -466,6 +466,26 @@ int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
        return 0;
 }
 
+int sysfs_get_str(struct mdinfo *sra, struct mdinfo *dev,
+                 char *name, char *buf, int buf_len)
+{
+       char fname[50];
+       int n;
+       int fd;
+
+       sprintf(fname, "/sys/block/%s/md/%s/%s",
+               sra->sys_name, dev?dev->sys_name:"", name);
+       fd = open(fname, O_RDONLY);
+       if (fd < 0)
+               return -1;
+       n = read(fd, buf, buf_len);
+       close(fd);
+       if (n <= 0)
+               return -1;
+       buf[n] = 0;
+       return 0;
+}
+
 int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms)
 {
        unsigned long sec;