summaryrefslogtreecommitdiff
path: root/Incremental.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2013-03-05 09:46:34 +1100
committerNeilBrown <neilb@suse.de>2013-03-05 09:46:34 +1100
commit8af530b07fce27f56c56b2ffd254a40b4ab67c6b (patch)
tree618f49d47873ac20fea4cbe24bcc8dc16e23ec48 /Incremental.c
parent401f095c39b732b4247bd728cb493eb7bb692298 (diff)
Enhance incremental removal.
When asked to incrementally-remove a device, try marking the array read-auto first. That will delay recording the failure in the metadata until it is really relevant. This way, if the device are just unplugged when the array is not really in use, the metadata will remain clean. If marking the default as faulty fails because it is EBUSY, that implies that the array would be failed without the device. As the device has (presumably gone) - that means the array is dead. So try to stop it. If that fails because it is in use, send a uevent to report that it is gone. Hopefully whoever mounted it will now let go. This means that if you plug in some devices and they are auto-assembled, then unplugging them will auto-deassemble relatively cleanly. To be complete, we really need the kernel to disassemble the array after the last close somehow. Maybe if a REMOVE has failed and a STOP has failed and nothing else much has happened, it could safely stop the array on last close. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'Incremental.c')
-rw-r--r--Incremental.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/Incremental.c b/Incremental.c
index 36f79ef5..1b7ebfaf 100644
--- a/Incremental.c
+++ b/Incremental.c
@@ -1578,9 +1578,11 @@ static int Incremental_container(struct supertype *st, char *devname,
int IncrementalRemove(char *devname, char *id_path, int verbose)
{
int mdfd;
- int rv;
+ int rv = 0;
struct mdstat_ent *ent;
struct mddev_dev devlist;
+ struct mdinfo mdi;
+ char buf[32];
if (!id_path)
dprintf(Name ": incremental removal without --path <id_path> "
@@ -1598,6 +1600,14 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
"of any array\n", devname);
return 1;
}
+ sysfs_init(&mdi, -1, ent->devnm);
+ if (sysfs_get_str(&mdi, NULL, "array_state",
+ buf, sizeof(buf)) > 0) {
+ if (strncmp(buf, "active", 6) == 0 ||
+ strncmp(buf, "clean", 5) == 0)
+ sysfs_set_str(&mdi, NULL,
+ "array_state", "read-auto");
+ }
mdfd = open_dev(ent->devnm);
if (mdfd < 0) {
pr_err("Cannot open array %s!!\n", ent->dev);
@@ -1625,17 +1635,30 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
if (is_container_member(memb, ent->dev)) {
int subfd = open_dev(memb->devnm);
if (subfd >= 0) {
- Manage_subdevs(memb->dev, subfd,
- &devlist, verbose, 0,
- NULL, 0);
+ rv |= Manage_subdevs(
+ memb->dev, subfd,
+ &devlist, verbose, 0,
+ NULL, 0);
close(subfd);
}
}
free_mdstat(mdstat);
} else
- Manage_subdevs(ent->dev, mdfd, &devlist, verbose, 0, NULL, 0);
- devlist.disposition = 'r';
- rv = Manage_subdevs(ent->dev, mdfd, &devlist, verbose, 0, NULL, 0);
+ rv |= Manage_subdevs(ent->dev, mdfd, &devlist,
+ verbose, 0, NULL, 0);
+ if (rv & 2) {
+ /* Failed due to EBUSY, try to stop the array
+ */
+ rv = Manage_runstop(ent->dev, mdfd, -1,
+ verbose, 1);
+ if (rv)
+ /* At least we can try to trigger a 'remove' */
+ sysfs_uevent(&mdi, "remove");
+ } else {
+ devlist.disposition = 'r';
+ rv = Manage_subdevs(ent->dev, mdfd, &devlist,
+ verbose, 0, NULL, 0);
+ }
close(mdfd);
free_mdstat(ent);
return rv;