summaryrefslogtreecommitdiffstats
path: root/Incremental.c
diff options
context:
space:
mode:
Diffstat (limited to 'Incremental.c')
-rw-r--r--Incremental.c116
1 files changed, 74 insertions, 42 deletions
diff --git a/Incremental.c b/Incremental.c
index 60d6f8cb..228d2bdd 100644
--- a/Incremental.c
+++ b/Incremental.c
@@ -1610,22 +1610,6 @@ release:
return rv;
}
-static void remove_from_member_array(struct mdstat_ent *memb,
- struct mddev_dev *devlist, int verbose)
-{
- int subfd = open_dev(memb->devnm);
-
- if (subfd >= 0) {
- /*
- * Ignore the return value because it's necessary
- * to handle failure condition here.
- */
- Manage_subdevs(memb->devnm, subfd, devlist, verbose,
- 0, UOPT_UNDEFINED, 0);
- close(subfd);
- }
-}
-
/**
* is_devnode_path() - check if the devname passed might be devnode path.
* @devnode: the path to check.
@@ -1647,24 +1631,80 @@ static bool is_devnode_path(char *devnode)
}
/**
+ * Incremental_remove_external() - Remove the device from external container.
+ * @device_devnm: block device to remove.
+ * @container_devnm: the parent container
+ * @mdstat: mdstat file content.
+ * @verbose: verbose flag.
+ *
+ * Fail member device in each subarray and remove member device from external container.
+ * The resposibility of removing member disks from external subararys belongs to mdmon.
+ */
+static mdadm_status_t Incremental_remove_external(char *device_devnm, char *container_devnm,
+ struct mdstat_ent *mdstat, int verbose)
+{
+ mdadm_status_t rv = MDADM_STATUS_SUCCESS;
+ struct mdstat_ent *memb;
+
+ for (memb = mdstat ; memb ; memb = memb->next) {
+ mdadm_status_t ret = MDADM_STATUS_SUCCESS;
+ int state_fd;
+
+ if (!is_container_member(memb, container_devnm))
+ continue;
+
+ /*
+ * Checking mdstat is pointles because it might be outdated, try open descriptor
+ * instead. If it fails, we are fine with that, device is already gone.
+ */
+ state_fd = sysfs_open_memb_attr(memb->devnm, device_devnm, "state", O_RDWR);
+ if (!is_fd_valid(state_fd))
+ continue;
+
+ ret = sysfs_set_memb_state_fd(state_fd, MEMB_STATE_FAULTY, NULL);
+ if (ret && verbose >= 0)
+ pr_err("Cannot fail member device %s in external subarray %s.\n",
+ device_devnm, memb->devnm);
+
+ close_fd(&state_fd);
+
+ /*
+ * Don't remove member device from container if it failed to remove it
+ * from any member array.
+ */
+ rv |= ret;
+ }
+
+ if (rv == MDADM_STATUS_SUCCESS)
+ rv = sysfs_set_memb_state(container_devnm, device_devnm, MEMB_STATE_REMOVE);
+
+ if (rv && verbose >= 0)
+ pr_err("Cannot remove member device %s from container %s.\n", device_devnm,
+ container_devnm);
+
+ return rv;
+}
+
+/**
* Incremental_remove() - Remove the device from all raid arrays.
* @devname: the device we want to remove, it could be kernel device name or devnode.
* @id_path: optional, /dev/disk/by-path path to save for bare scenarios support.
* @verbose: verbose flag.
*
- * First, fail the device (if needed) and then remove the device from native raid array or external
- * container. If it is external container, the device is removed from each subarray first.
+ * First, fail the device (if needed) and then remove the device. This code is critical for system
+ * funtionality and that is why it is keept as simple as possible. We do not load devices using
+ * sysfs_read() because any unerelated failure may lead us to abort. We also do not call
+ * Manage_Subdevs().
*/
int Incremental_remove(char *devname, char *id_path, int verbose)
{
+ mdadm_status_t rv = MDADM_STATUS_SUCCESS;
char *devnm = basename(devname);
- struct mddev_dev devlist = {0};
char buf[SYSFS_MAX_BUF_SIZE];
struct mdstat_ent *mdstat;
struct mdstat_ent *ent;
struct mdinfo mdi;
- int rv = 1;
- int mdfd;
+ int mdfd = -1;
if (strcmp(devnm, devname) != 0)
if (!is_devnode_path(devname)) {
@@ -1733,32 +1773,24 @@ int Incremental_remove(char *devname, char *id_path, int verbose)
map_free(map);
}
- devlist.devname = devnm;
- devlist.disposition = 'I';
- /* for a container, we must fail each member array */
if (is_mdstat_ent_external(ent)) {
- struct mdstat_ent *memb;
- for (memb = mdstat ; memb ; memb = memb->next) {
- if (is_container_member(memb, ent->devnm))
- remove_from_member_array(memb,
- &devlist, verbose);
- }
- } else {
- /*
- * This 'I' incremental remove is a try-best effort,
- * the failure condition can be safely ignored
- * because of the following up 'r' remove.
- */
- Manage_subdevs(ent->devnm, mdfd, &devlist,
- verbose, 0, UOPT_UNDEFINED, 0);
+ rv = Incremental_remove_external(devnm, ent->devnm, mdstat, verbose);
+ goto out;
}
- devlist.disposition = 'r';
- rv = Manage_subdevs(ent->devnm, mdfd, &devlist,
- verbose, 0, UOPT_UNDEFINED, 0);
+ /* Native arrays are handled separatelly to provide more detailed error handling */
+ rv = sysfs_set_memb_state(ent->devnm, devnm, MEMB_STATE_FAULTY);
+ if (rv && verbose >= 0)
+ pr_err("Cannot fail member device %s in array %s.\n", devnm, ent->devnm);
+
+ if (rv == MDADM_STATUS_SUCCESS)
+ rv = sysfs_set_memb_state(ent->devnm, devnm, MEMB_STATE_REMOVE);
+
+ if (rv && verbose >= 0)
+ pr_err("Cannot remove member device %s from %s.\n", devnm, ent->devnm);
- close_fd(&mdfd);
out:
+ close_fd(&mdfd);
free_mdstat(mdstat);
return rv;
}