summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--managemon.c39
-rw-r--r--mdadm.h6
-rw-r--r--super-intel.c174
3 files changed, 186 insertions, 33 deletions
diff --git a/managemon.c b/managemon.c
index 26ff187..49c9034 100644
--- a/managemon.c
+++ b/managemon.c
@@ -297,12 +297,44 @@ static void add_disk_to_container(struct supertype *st, struct mdinfo *sd)
st->update_tail = NULL;
}
+/*
+ * Create and queue update structure about the removed disks.
+ * The update is prepared by super type handler and passed to the monitor
+ * thread.
+ */
+static void remove_disk_from_container(struct supertype *st, struct mdinfo *sd)
+{
+ struct metadata_update *update = NULL;
+ mdu_disk_info_t dk = {
+ .number = -1,
+ .major = sd->disk.major,
+ .minor = sd->disk.minor,
+ .raid_disk = -1,
+ .state = 0,
+ };
+ /* nothing to do if super type handler does not support
+ * remove disk primitive
+ */
+ if (!st->ss->remove_from_super)
+ return;
+ dprintf("%s: remove %d:%d from container\n",
+ __func__, sd->disk.major, sd->disk.minor);
+
+ st->update_tail = &update;
+ st->ss->remove_from_super(st, &dk);
+ st->ss->write_init_super(st);
+ queue_metadata_update(update);
+ st->update_tail = NULL;
+}
+
static void manage_container(struct mdstat_ent *mdstat,
struct supertype *container)
{
- /* The only thing of interest here is if a new device
- * has been added to the container. We add it to the
- * array ignoring any metadata on it.
+ /* Of interest here are:
+ * - if a new device has been added to the container, we
+ * add it to the array ignoring any metadata on it.
+ * - if a device has been removed from the container, we
+ * remove it from the device list and update the metadata.
* FIXME should we look for compatible metadata and take hints
* about spare assignment.... probably not.
*/
@@ -334,6 +366,7 @@ static void manage_container(struct mdstat_ent *mdstat,
if (!found) {
cd = *cdp;
*cdp = (*cdp)->next;
+ remove_disk_from_container(container, cd);
free(cd);
} else
cdp = &(*cdp)->next;
diff --git a/mdadm.h b/mdadm.h
index fcb0e3b..f5367bf 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -580,7 +580,11 @@ extern struct superswitch {
* when hot-adding a spare.
*/
int (*add_to_super)(struct supertype *st, mdu_disk_info_t *dinfo,
- int fd, char *devname);
+ int fd, char *devname);
+ /* update the metadata to delete a device,
+ * when hot-removing.
+ */
+ int (*remove_from_super)(struct supertype *st, mdu_disk_info_t *dinfo);
/* Write metadata to one device when fixing problems or adding
* a new device.
diff --git a/super-intel.c b/super-intel.c
index b3a116f..b952c06 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -233,6 +233,10 @@ struct intel_dev {
unsigned index;
};
+enum action {
+ DISK_REMOVE = 1,
+ DISK_ADD
+};
/* internal representation of IMSM metadata */
struct intel_super {
union {
@@ -258,8 +262,10 @@ struct intel_super {
int extent_cnt;
struct extent *e; /* for determining freespace @ create */
int raiddisk; /* slot to fill in autolayout */
+ enum action action;
} *disks;
- struct dl *add; /* list of disks to add while mdmon active */
+ struct dl *disk_mgmt_list; /* list of disks to add/remove while mdmon
+ active */
struct dl *missing; /* disks removed while we weren't looking */
struct bbm_log *bbm_log;
const char *hba; /* device path of the raid controller for this metadata */
@@ -284,7 +290,7 @@ enum imsm_update_type {
update_create_array,
update_kill_array,
update_rename_array,
- update_add_disk,
+ update_add_remove_disk,
};
struct imsm_update_activate_spare {
@@ -316,7 +322,7 @@ struct imsm_update_rename_array {
int dev_idx;
};
-struct imsm_update_add_disk {
+struct imsm_update_add_remove_disk {
enum imsm_update_type type;
};
@@ -2324,6 +2330,7 @@ static void __free_imsm_disk(struct dl *d)
free(d);
}
+
static void free_imsm_disks(struct intel_super *super)
{
struct dl *d;
@@ -3328,6 +3335,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
dd->devname = devname ? strdup(devname) : NULL;
dd->fd = fd;
dd->e = NULL;
+ dd->action = DISK_ADD;
rv = imsm_read_serial(fd, devname, dd->serial);
if (rv) {
fprintf(stderr,
@@ -3347,8 +3355,8 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
dd->disk.scsi_id = __cpu_to_le32(0);
if (st->update_tail) {
- dd->next = super->add;
- super->add = dd;
+ dd->next = super->disk_mgmt_list;
+ super->disk_mgmt_list = dd;
} else {
dd->next = super->disks;
super->disks = dd;
@@ -3357,6 +3365,43 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
return 0;
}
+
+static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
+{
+ struct intel_super *super = st->sb;
+ struct dl *dd;
+
+ /* remove from super works only in mdmon - for communication
+ * manager - monitor. Check if communication memory buffer
+ * is prepared.
+ */
+ if (!st->update_tail) {
+ fprintf(stderr,
+ Name ": %s shall be used in mdmon context only"
+ "(line %d).\n", __func__, __LINE__);
+ return 1;
+ }
+ dd = malloc(sizeof(*dd));
+ if (!dd) {
+ fprintf(stderr,
+ Name ": malloc failed %s:%d.\n", __func__, __LINE__);
+ return 1;
+ }
+ memset(dd, 0, sizeof(*dd));
+ dd->major = dk->major;
+ dd->minor = dk->minor;
+ dd->index = -1;
+ dd->fd = -1;
+ dd->disk.status = SPARE_DISK;
+ dd->action = DISK_REMOVE;
+
+ dd->next = super->disk_mgmt_list;
+ super->disk_mgmt_list = dd;
+
+
+ return 0;
+}
+
static int store_imsm_mpb(int fd, struct imsm_super *mpb);
static union {
@@ -3509,13 +3554,13 @@ static int create_array(struct supertype *st, int dev_idx)
return 0;
}
-static int _add_disk(struct supertype *st)
+static int mgmt_disk(struct supertype *st)
{
struct intel_super *super = st->sb;
size_t len;
- struct imsm_update_add_disk *u;
+ struct imsm_update_add_remove_disk *u;
- if (!super->add)
+ if (!super->disk_mgmt_list)
return 0;
len = sizeof(*u);
@@ -3526,7 +3571,7 @@ static int _add_disk(struct supertype *st)
return 1;
}
- u->type = update_add_disk;
+ u->type = update_add_remove_disk;
append_metadata_update(st, u, len);
return 0;
@@ -3548,10 +3593,10 @@ static int write_init_super_imsm(struct supertype *st)
/* determine if we are creating a volume or adding a disk */
if (current_vol < 0) {
- /* in the add disk case we are running in mdmon
- * context, so don't close fd's
+ /* in the mgmt (add/remove) disk case we are running
+ * in mdmon context, so don't close fd's
*/
- return _add_disk(st);
+ return mgmt_disk(st);
} else
rv = create_array(st, current_vol);
@@ -4792,6 +4837,7 @@ static void imsm_sync_metadata(struct supertype *container)
{
struct intel_super *super = container->sb;
+ dprintf("sync metadata: %d\n", super->updates_pending);
if (!super->updates_pending)
return;
@@ -5083,8 +5129,84 @@ static int disks_overlap(struct intel_super *super, int idx, struct imsm_update_
return 0;
}
+
+static struct dl *get_disk_super(struct intel_super *super, int major, int minor)
+{
+ struct dl *dl = NULL;
+ for (dl = super->disks; dl; dl = dl->next)
+ if ((dl->major == major) && (dl->minor == minor))
+ return dl;
+ return NULL;
+}
+
+static int remove_disk_super(struct intel_super *super, int major, int minor)
+{
+ struct dl *prev = NULL;
+ struct dl *dl;
+
+ prev = NULL;
+ for (dl = super->disks; dl; dl = dl->next) {
+ if ((dl->major == major) && (dl->minor == minor)) {
+ /* remove */
+ if (prev)
+ prev->next = dl->next;
+ else
+ super->disks = dl->next;
+ dl->next = NULL;
+ __free_imsm_disk(dl);
+ dprintf("%s: removed %x:%x\n",
+ __func__, major, minor);
+ break;
+ }
+ prev = dl;
+ }
+ return 0;
+}
+
static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned index);
+static int add_remove_disk_update(struct intel_super *super)
+{
+ int check_degraded = 0;
+ struct dl *disk = NULL;
+ /* add/remove some spares to/from the metadata/contrainer */
+ while (super->disk_mgmt_list) {
+ struct dl *disk_cfg;
+
+ disk_cfg = super->disk_mgmt_list;
+ super->disk_mgmt_list = disk_cfg->next;
+ disk_cfg->next = NULL;
+
+ if (disk_cfg->action == DISK_ADD) {
+ disk_cfg->next = super->disks;
+ super->disks = disk_cfg;
+ check_degraded = 1;
+ dprintf("%s: added %x:%x\n",
+ __func__, disk_cfg->major,
+ disk_cfg->minor);
+ } else if (disk_cfg->action == DISK_REMOVE) {
+ dprintf("Disk remove action processed: %x.%x\n",
+ disk_cfg->major, disk_cfg->minor);
+ disk = get_disk_super(super,
+ disk_cfg->major,
+ disk_cfg->minor);
+ if (disk) {
+ /* store action status */
+ disk->action = DISK_REMOVE;
+ /* remove spare disks only */
+ if (disk->index == -1) {
+ remove_disk_super(super,
+ disk_cfg->major,
+ disk_cfg->minor);
+ }
+ }
+ /* release allocate disk structure */
+ __free_imsm_disk(disk_cfg);
+ }
+ }
+ return check_degraded;
+}
+
static void imsm_process_update(struct supertype *st,
struct metadata_update *update)
{
@@ -5394,31 +5516,24 @@ static void imsm_process_update(struct supertype *st,
super->updates_pending++;
break;
}
- case update_add_disk:
-
+ case update_add_remove_disk: {
/* we may be able to repair some arrays if disks are
- * being added */
- if (super->add) {
+ * being added, check teh status of add_remove_disk
+ * if discs has been added.
+ */
+ if (add_remove_disk_update(super)) {
struct active_array *a;
super->updates_pending++;
- for (a = st->arrays; a; a = a->next)
+ for (a = st->arrays; a; a = a->next)
a->check_degraded = 1;
}
- /* add some spares to the metadata */
- while (super->add) {
- struct dl *al;
-
- al = super->add;
- super->add = al->next;
- al->next = super->disks;
- super->disks = al;
- dprintf("%s: added %x:%x\n",
- __func__, al->major, al->minor);
- }
-
break;
}
+ default:
+ fprintf(stderr, "error: unsuported process update type:"
+ "(type: %d)\n", type);
+ }
}
static void imsm_prepare_update(struct supertype *st,
@@ -5569,6 +5684,7 @@ struct superswitch super_imsm = {
.validate_geometry = validate_geometry_imsm,
.default_chunk = default_chunk_imsm,
.add_to_super = add_to_super_imsm,
+ .remove_from_super = remove_from_super_imsm,
.detail_platform = detail_platform_imsm,
.kill_subarray = kill_subarray_imsm,
.update_subarray = update_subarray_imsm,