summaryrefslogtreecommitdiff
path: root/super-intel.c
diff options
context:
space:
mode:
Diffstat (limited to 'super-intel.c')
-rw-r--r--super-intel.c174
1 files changed, 145 insertions, 29 deletions
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,