DDF: implement kill_subarray

Implement kill_subarray, for mdmon running and not running.

The way Kill_subarray() is implemented, this requires that the
DDF layer uses "currentconf" to remember the last subarray
queried with container_content(), and use it as the one to kill.
I don't like this much but IMSM does it the same way.

Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
mwilck@arcor.de 2013-07-08 23:50:40 +02:00 committed by NeilBrown
parent 19041058d2
commit f646805e80
1 changed files with 99 additions and 7 deletions

View File

@ -3616,7 +3616,8 @@ static struct mdinfo *container_content_ddf(struct supertype *st, char *subarray
ddf->currentconf = vc;
uuid_from_super_ddf(st, this->uuid);
ddf->currentconf = NULL;
if (!subarray)
ddf->currentconf = NULL;
sprintf(this->text_version, "/%s/%d",
st->container_devnm, this->container_member);
@ -4160,6 +4161,88 @@ static void ddf_sync_metadata(struct supertype *st)
dprintf("ddf: sync_metadata\n");
}
static int del_from_conflist(struct vcl **list, const char *guid)
{
struct vcl **p;
int found = 0;
for (p = list; p && *p; p = &((*p)->next))
if (!memcmp((*p)->conf.guid, guid, DDF_GUID_LEN)) {
found = 1;
*p = (*p)->next;
}
return found;
}
static int _kill_subarray_ddf(struct ddf_super *ddf, const char *guid)
{
struct dl *dl;
unsigned int vdnum, i;
vdnum = find_vde_by_guid(ddf, guid);
if (vdnum == DDF_NOTFOUND) {
pr_err("%s: could not find VD %s\n", __func__,
guid_str(guid));
return -1;
}
if (del_from_conflist(&ddf->conflist, guid) == 0) {
pr_err("%s: could not find conf %s\n", __func__,
guid_str(guid));
return -1;
}
for (dl = ddf->dlist; dl; dl = dl->next)
for (i = 0; i < ddf->max_part; i++)
if (dl->vlist[i] != NULL &&
!memcmp(dl->vlist[i]->conf.guid, guid,
DDF_GUID_LEN))
dl->vlist[i] = NULL;
memset(ddf->virt->entries[vdnum].guid, 0xff, DDF_GUID_LEN);
dprintf("%s: deleted %s\n", __func__, guid_str(guid));
return 0;
}
static int kill_subarray_ddf(struct supertype *st)
{
struct ddf_super *ddf = st->sb;
/*
* currentconf is set in container_content_ddf,
* called with subarray arg
*/
struct vcl *victim = ddf->currentconf;
struct vd_config *conf;
ddf->currentconf = NULL;
unsigned int vdnum;
if (!victim) {
pr_err("%s: nothing to kill\n", __func__);
return -1;
}
conf = &victim->conf;
vdnum = find_vde_by_guid(ddf, conf->guid);
if (vdnum == DDF_NOTFOUND) {
pr_err("%s: could not find VD %s\n", __func__,
guid_str(conf->guid));
return -1;
}
if (st->update_tail) {
struct virtual_disk *vd;
int len = sizeof(struct virtual_disk)
+ sizeof(struct virtual_entry);
vd = xmalloc(len);
if (vd == NULL) {
pr_err("%s: failed to allocate %d bytes\n", __func__,
len);
return -1;
}
memset(vd, 0 , len);
vd->magic = DDF_VIRT_RECORDS_MAGIC;
vd->populated_vdes = 0;
memcpy(vd->entries[0].guid, conf->guid, DDF_GUID_LEN);
/* we use DDF_state_deleted as marker */
vd->entries[0].state = DDF_state_deleted;
append_metadata_update(st, vd, len);
} else
_kill_subarray_ddf(ddf, conf->guid);
return 0;
}
static void ddf_process_update(struct supertype *st,
struct metadata_update *update)
{
@ -4262,12 +4345,20 @@ static void ddf_process_update(struct supertype *st,
return;
vd = (struct virtual_disk*)update->buf;
ent = find_unused_vde(ddf);
if (ent == DDF_NOTFOUND)
return;
ddf->virt->entries[ent] = vd->entries[0];
ddf->virt->populated_vdes = __cpu_to_be16(1 +
__be16_to_cpu(ddf->virt->populated_vdes));
if (vd->entries[0].state == DDF_state_deleted) {
if (_kill_subarray_ddf(ddf, vd->entries[0].guid))
return;
} else {
ent = find_unused_vde(ddf);
if (ent == DDF_NOTFOUND)
return;
ddf->virt->entries[ent] = vd->entries[0];
ddf->virt->populated_vdes =
__cpu_to_be16(
1 + __be16_to_cpu(
ddf->virt->populated_vdes));
}
ddf_set_updates_pending(ddf);
break;
@ -4700,6 +4791,7 @@ struct superswitch super_ddf = {
.match_metadata_desc = match_metadata_desc_ddf,
.container_content = container_content_ddf,
.default_geometry = default_geometry_ddf,
.kill_subarray = kill_subarray_ddf,
.external = 1,