NeilBrown: Add support for "--re-add missing"

Martin F. Krafft madduck at alioth.debian.org
Sun Aug 29 11:54:24 UTC 2010


Module: mdadm
Branch: debian/conffile-location
Commit: a4e13010df574a1ce597efe9cb15ed6d6003b8bb
URL:    http://git.debian.org/?p=pkg-mdadm/mdadm.git;a=commit;h=a4e13010df574a1ce597efe9cb15ed6d6003b8bb

Author: NeilBrown <neilb at suse.de>
Date:   Mon Jul  5 15:06:27 2010 +1000

Add support for "--re-add missing"

If the device name "missing" is given for --re-add, then mdadm will
attempt to find any device which should be a member of the array but
currently isn't and will --re-add it to the array.
This can be useful if a device disappeared due to a cabling problem,
and was then re-connected.
The appropriate sequence would be
  mdadm /dev/mdX --fail detached
  mdadm /dev/mdX --remove detached
  mdadm /dev/mdX --re-add missing

Signed-off-by: NeilBrown <neilb at suse.de>

---

 Manage.c   |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 mdadm.8.in |   26 +++++++++++++-------
 2 files changed, 81 insertions(+), 20 deletions(-)

diff --git a/Manage.c b/Manage.c
index edf41e9..b4e3900 100644
--- a/Manage.c
+++ b/Manage.c
@@ -342,6 +342,7 @@ int Manage_subdevs(char *devname, int fd,
 	 * For 'f' and 'r', the device can also be a kernel-internal
 	 * name such as 'sdb'.
 	 */
+	mddev_dev_t add_devlist = NULL;
 	mdu_array_info_t array;
 	mdu_disk_info_t disc;
 	unsigned long long array_size;
@@ -381,6 +382,7 @@ int Manage_subdevs(char *devname, int fd,
 		unsigned long long ldsize;
 		char dvname[20];
 		char *dnprintable = dv->devname;
+		char *add_dev = dv->devname;
 		int err;
 
 		next = dv->next;
@@ -458,6 +460,24 @@ int Manage_subdevs(char *devname, int fd,
 			}
 			if (jnext == 0)
 				continue;
+		} else if (strcmp(dv->devname, "missing") == 0) {
+			if (dv->disposition != 'a' || dv->re_add == 0) {
+				fprintf(stderr, Name ": 'missing' only meaningful "
+					"with --re-add\n");
+				return 1;
+			}
+			if (add_devlist == NULL)
+				add_devlist = conf_get_devs();
+			if (add_devlist == NULL) {
+				fprintf(stderr, Name ": no devices to scan for missing members.");
+				continue;
+			}
+			add_dev = add_devlist->devname;
+			add_devlist = add_devlist->next;
+			if (add_devlist != NULL)
+				next = dv;
+			if (stat(add_dev, &stb) < 0)
+				continue;
 		} else if (strchr(dv->devname, '/') == NULL &&
 			   strlen(dv->devname) < 50) {
 			/* Assume this is a kernel-internal name like 'sda1' */
@@ -533,39 +553,44 @@ int Manage_subdevs(char *devname, int fd,
 				return 1;
 			}
 			/* Make sure it isn't in use (in 2.6 or later) */
-			tfd = dev_open(dv->devname, O_RDONLY|O_EXCL|O_DIRECT);
+			tfd = dev_open(add_dev, O_RDONLY|O_EXCL|O_DIRECT);
+			if (tfd < 0 && add_dev != dv->devname)
+				continue;
 			if (tfd < 0) {
 				fprintf(stderr, Name ": Cannot open %s: %s\n",
 					dv->devname, strerror(errno));
 				return 1;
 			}
-			remove_partitions(tfd);
 
 			st = dup_super(tst);
 
 			if (array.not_persistent==0)
 				st->ss->load_super(st, tfd, NULL);
 
-			if (!get_dev_size(tfd, dv->devname, &ldsize)) {
+			if (add_dev == dv->devname) {
+				if (!get_dev_size(tfd, dv->devname, &ldsize)) {
+					close(tfd);
+					return 1;
+				}
+			} else if (!get_dev_size(tfd, NULL, &ldsize)) {
 				close(tfd);
-				return 1;
+				continue;
 			}
-			close(tfd);
-
 
 			if (!tst->ss->external &&
 			    array.major_version == 0 &&
 			    md_get_version(fd)%100 < 2) {
+				close(tfd);
 				if (ioctl(fd, HOT_ADD_DISK,
 					  (unsigned long)stb.st_rdev)==0) {
 					if (verbose >= 0)
 						fprintf(stderr, Name ": hot added %s\n",
-							dv->devname);
+							add_dev);
 					continue;
 				}
 
 				fprintf(stderr, Name ": hot add failed for %s: %s\n",
-					dv->devname, strerror(errno));
+					add_dev, strerror(errno));
 				return 1;
 			}
 
@@ -576,7 +601,9 @@ int Manage_subdevs(char *devname, int fd,
 				 * For 'external' array (well, container based),
 				 * We can just load the metadata for the array.
 				 */
-				if (tst->ss->external) {
+				if (tst->sb)
+					/* already loaded */;
+				else if (tst->ss->external) {
 					tst->ss->load_super(tst, fd, NULL);
 				} else for (j = 0; j < tst->max_devs; j++) {
 					char *dev;
@@ -602,6 +629,7 @@ int Manage_subdevs(char *devname, int fd,
 				}
 				/* FIXME this is a bad test to be using */
 				if (!tst->sb) {
+					close(tfd);
 					fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
 					return 1;
 				}
@@ -609,6 +637,9 @@ int Manage_subdevs(char *devname, int fd,
 				/* Make sure device is large enough */
 				if (tst->ss->avail_size(tst, ldsize/512) <
 				    array_size) {
+					close(tfd);
+					if (add_dev != dv->devname)
+						continue;
 					fprintf(stderr, Name ": %s not large enough to join array\n",
 						dv->devname);
 					return 1;
@@ -644,23 +675,40 @@ int Manage_subdevs(char *devname, int fd,
 							disc.state |= 1 << MD_DISK_WRITEMOSTLY;
 						if (dv->writemostly == 2)
 							disc.state &= ~(1 << MD_DISK_WRITEMOSTLY);
+						remove_partitions(tfd);
+						close(tfd);
+						tfd = -1;
 						/* don't even try if disk is marked as faulty */
 						errno = 0;
 						if ((disc.state & 1) == 0 &&
 						    ioctl(fd, ADD_NEW_DISK, &disc) == 0) {
 							if (verbose >= 0)
-								fprintf(stderr, Name ": re-added %s\n", dv->devname);
+								fprintf(stderr, Name ": re-added %s\n", add_dev);
 							continue;
 						}
 						if (errno == ENOMEM || errno == EROFS) {
+							close(tfd);
 							fprintf(stderr, Name ": add new device failed for %s: %s\n",
-								dv->devname, strerror(errno));
+								add_dev, strerror(errno));
+							if (add_dev != dv->devname)
+								continue;
 							return 1;
 						}
 						/* fall back on normal-add */
 					}
 				}
+				if (add_dev != dv->devname) {
+					if (verbose > 0)
+						fprintf(stderr, Name
+							": --re-add for %s to %s is not possible\n",
+							add_dev, devname);
+					if (tfd >= 0)
+						close(tfd);
+					continue;
+				}
 				if (dv->re_add) {
+					if (tfd >= 0)
+						close(tfd);
 					fprintf(stderr, Name
 						": --re-add for %s to %s is not possible\n",
 						dv->devname, devname);
@@ -676,6 +724,11 @@ int Manage_subdevs(char *devname, int fd,
 					return 1;
 				}
 			}
+			/* committed to really trying this device now*/
+			if (tfd >= 0) {
+				remove_partitions(tfd);
+				close(tfd);
+			}
 			/* in 2.6.17 and earlier, version-1 superblocks won't
 			 * use the number we write, but will choose a free number.
 			 * we must choose the same free number, which requires
diff --git a/mdadm.8.in b/mdadm.8.in
index f6f6b75..f9c336f 100644
--- a/mdadm.8.in
+++ b/mdadm.8.in
@@ -1018,16 +1018,24 @@ immediately start recovering data on to one of these spares.
 
 .TP
 .BR \-\-re\-add
-re-add a device that was recently removed from an array.  This is only
-needed for arrays that have be built (i.e. with
+re\-add a device that was recently removed from an array.  This is
+normally only needed for arrays that have be built (i.e. with
 .BR --build ).
-For created arrays, devices are always re-added if that is possible.
-When re-adding a device, if nothing has changed on the array since the
+For created arrays, devices are always re\-added if that is possible,
+however using \-\-re\-add will ensure the device isn't made into a
+spare if the \-\-re\-add failed.
+
+When re\-adding a device, if nothing has changed on the array since the
 device was removed, no recovery is performed.  Also, if the array has
-a write-intent bitmap, then the recovery performed after a re-add will
+a write-intent bitmap, then the recovery performed after a re\-add will
 be limited to those blocks which, according to the bitmap, might have
 changed since the device was removed.
 
+If the device name given is
+.B missing
+then mdadm will try to find any device that looks like it should be
+part of the array but isn't and will try to re\-add all such devices.
+
 .TP
 .BR \-r ", " \-\-remove
 remove listed devices.  They must not be active.  i.e. they should
@@ -1062,12 +1070,12 @@ same as
 
 .TP
 .BR \-\-write\-mostly
-Subsequent devices that are added or re-added will have the 'write-mostly'
+Subsequent devices that are added or re\-added will have the 'write-mostly'
 flag set.  This is only valid for RAID1 and means that the 'md' driver
 will avoid reading from these devices if possible.
 .TP
 .BR \-\-readwrite
-Subsequent devices that are added or re-added will have the 'write-mostly'
+Subsequent devices that are added or re\-added will have the 'write-mostly'
 flag cleared.
 
 .P
@@ -1082,7 +1090,7 @@ Each operation applies to all devices listed until the next
 operation.
 
 If an array is using a write-intent bitmap, then devices which have
-been removed can be re-added in a way that avoids a full
+been removed can be re\-added in a way that avoids a full
 reconstruction but instead just updates the blocks that have changed
 since the device was removed.  For arrays with persistent metadata
 (superblocks) this is done automatically.  For arrays created with
@@ -1691,7 +1699,7 @@ command.
 
 When a device is added to an active array, mdadm checks to see if it
 has metadata on it which suggests that it was recently a member of the
-array.  If it does, it tried to "re-add" the device.  If there have
+array.  If it does, it tries to "re\-add" the device.  If there have
 been no changes since the device was removed, or if the array has a
 write-intent bitmap which has recorded whatever changes there were,
 then the device will immediately become a full member of the array and




More information about the pkg-mdadm-commits mailing list