From: NeilBrown Date: Wed, 21 May 2014 02:20:56 +0000 (+1000) Subject: DDF: split up ddf_process_update X-Git-Tag: mdadm-3.3.1~22 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=commitdiff_plain;h=fea6a6c0bf82849f97c150612291b9b79bf3b0ba DDF: split up ddf_process_update Function was way too big, make several smaller functions. Signed-off-by: NeilBrown --- diff --git a/super-ddf.c b/super-ddf.c index 58d00fdd..e866046d 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -4574,6 +4574,297 @@ static void copy_matching_bvd(struct ddf_super *ddf, conf->sec_elmnt_seq, guid_str(conf->guid)); } +static void ddf_process_phys_update(struct supertype *st, + struct metadata_update *update) +{ + struct ddf_super *ddf = st->sb; + struct phys_disk *pd; + unsigned int ent; + + pd = (struct phys_disk*)update->buf; + ent = be16_to_cpu(pd->used_pdes); + if (ent >= be16_to_cpu(ddf->phys->max_pdes)) + return; + if (be16_and(pd->entries[0].state, cpu_to_be16(DDF_Missing))) { + struct dl **dlp; + /* removing this disk. */ + be16_set(ddf->phys->entries[ent].state, + cpu_to_be16(DDF_Missing)); + for (dlp = &ddf->dlist; *dlp; dlp = &(*dlp)->next) { + struct dl *dl = *dlp; + if (dl->pdnum == (signed)ent) { + close(dl->fd); + dl->fd = -1; + /* FIXME this doesn't free + * dl->devname */ + update->space = dl; + *dlp = dl->next; + break; + } + } + ddf_set_updates_pending(ddf, NULL); + return; + } + if (!all_ff(ddf->phys->entries[ent].guid)) + return; + ddf->phys->entries[ent] = pd->entries[0]; + ddf->phys->used_pdes = cpu_to_be16 + (1 + be16_to_cpu(ddf->phys->used_pdes)); + ddf_set_updates_pending(ddf, NULL); + if (ddf->add_list) { + struct active_array *a; + struct dl *al = ddf->add_list; + ddf->add_list = al->next; + + al->next = ddf->dlist; + ddf->dlist = al; + + /* As a device has been added, we should check + * for any degraded devices that might make + * use of this spare */ + for (a = st->arrays ; a; a=a->next) + a->check_degraded = 1; + } +} + +static void ddf_process_virt_update(struct supertype *st, + struct metadata_update *update) +{ + struct ddf_super *ddf = st->sb; + struct virtual_disk *vd; + unsigned int ent; + + vd = (struct virtual_disk*)update->buf; + + if (vd->entries[0].state == DDF_state_deleted) { + if (_kill_subarray_ddf(ddf, vd->entries[0].guid)) + return; + } else { + ent = find_vde_by_guid(ddf, vd->entries[0].guid); + if (ent != DDF_NOTFOUND) { + dprintf("%s: VD %s exists already in slot %d\n", + __func__, guid_str(vd->entries[0].guid), + ent); + return; + } + 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)); + dprintf("%s: added VD %s in slot %d(s=%02x i=%02x)\n", + __func__, guid_str(vd->entries[0].guid), ent, + ddf->virt->entries[ent].state, + ddf->virt->entries[ent].init_state); + } + ddf_set_updates_pending(ddf, NULL); +} + +static void ddf_remove_failed(struct ddf_super *ddf) +{ + /* Now remove any 'Failed' devices that are not part + * of any VD. They will have the Transition flag set. + * Once done, we need to update all dl->pdnum numbers. + */ + unsigned int pdnum; + unsigned int pd2 = 0; + struct dl *dl; + + for (pdnum = 0; pdnum < be16_to_cpu(ddf->phys->max_pdes); + pdnum++) { + if (be32_to_cpu(ddf->phys->entries[pdnum].refnum) == + 0xFFFFFFFF) + continue; + if (be16_and(ddf->phys->entries[pdnum].state, + cpu_to_be16(DDF_Failed)) + && be16_and(ddf->phys->entries[pdnum].state, + cpu_to_be16(DDF_Transition))) { + /* skip this one unless in dlist*/ + for (dl = ddf->dlist; dl; dl = dl->next) + if (dl->pdnum == (int)pdnum) + break; + if (!dl) + continue; + } + if (pdnum == pd2) + pd2++; + else { + ddf->phys->entries[pd2] = + ddf->phys->entries[pdnum]; + for (dl = ddf->dlist; dl; dl = dl->next) + if (dl->pdnum == (int)pdnum) + dl->pdnum = pd2; + pd2++; + } + } + ddf->phys->used_pdes = cpu_to_be16(pd2); + while (pd2 < pdnum) { + memset(ddf->phys->entries[pd2].guid, 0xff, + DDF_GUID_LEN); + pd2++; + } +} + +static void ddf_update_vlist(struct ddf_super *ddf, struct dl *dl) +{ + struct vcl *vcl; + unsigned int vn = 0; + int in_degraded = 0; + + if (dl->pdnum < 0) + return; + for (vcl = ddf->conflist; vcl ; vcl = vcl->next) { + unsigned int dn, ibvd; + const struct vd_config *conf; + int vstate; + dn = get_pd_index_from_refnum(vcl, + dl->disk.refnum, + ddf->mppe, + &conf, &ibvd); + if (dn == DDF_NOTFOUND) + continue; + dprintf("dev %d/%08x has %s (sec=%u) at %d\n", + dl->pdnum, + be32_to_cpu(dl->disk.refnum), + guid_str(conf->guid), + conf->sec_elmnt_seq, vn); + /* Clear the Transition flag */ + if (be16_and + (ddf->phys->entries[dl->pdnum].state, + cpu_to_be16(DDF_Failed))) + be16_clear(ddf->phys + ->entries[dl->pdnum].state, + cpu_to_be16(DDF_Transition)); + dl->vlist[vn++] = vcl; + vstate = ddf->virt->entries[vcl->vcnum].state + & DDF_state_mask; + if (vstate == DDF_state_degraded || + vstate == DDF_state_part_optimal) + in_degraded = 1; + } + while (vn < ddf->max_part) + dl->vlist[vn++] = NULL; + if (dl->vlist[0]) { + be16_clear(ddf->phys->entries[dl->pdnum].type, + cpu_to_be16(DDF_Global_Spare)); + if (!be16_and(ddf->phys + ->entries[dl->pdnum].type, + cpu_to_be16(DDF_Active_in_VD))) { + be16_set(ddf->phys + ->entries[dl->pdnum].type, + cpu_to_be16(DDF_Active_in_VD)); + if (in_degraded) + be16_set(ddf->phys + ->entries[dl->pdnum] + .state, + cpu_to_be16 + (DDF_Rebuilding)); + } + } + if (dl->spare) { + be16_clear(ddf->phys->entries[dl->pdnum].type, + cpu_to_be16(DDF_Global_Spare)); + be16_set(ddf->phys->entries[dl->pdnum].type, + cpu_to_be16(DDF_Spare)); + } + if (!dl->vlist[0] && !dl->spare) { + be16_set(ddf->phys->entries[dl->pdnum].type, + cpu_to_be16(DDF_Global_Spare)); + be16_clear(ddf->phys->entries[dl->pdnum].type, + cpu_to_be16(DDF_Spare)); + be16_clear(ddf->phys->entries[dl->pdnum].type, + cpu_to_be16(DDF_Active_in_VD)); + } +} + +static void ddf_process_conf_update(struct supertype *st, + struct metadata_update *update) +{ + struct ddf_super *ddf = st->sb; + struct vd_config *vc; + struct vcl *vcl; + struct dl *dl; + unsigned int ent; + unsigned int pdnum, len; + + vc = (struct vd_config*)update->buf; + len = ddf->conf_rec_len * 512; + if ((unsigned int)update->len != len * vc->sec_elmnt_count) { + pr_err("%s: %s: insufficient data (%d) for %u BVDs\n", + __func__, guid_str(vc->guid), update->len, + vc->sec_elmnt_count); + return; + } + for (vcl = ddf->conflist; vcl ; vcl = vcl->next) + if (memcmp(vcl->conf.guid, vc->guid, DDF_GUID_LEN) == 0) + break; + dprintf("%s: conf update for %s (%s)\n", __func__, + guid_str(vc->guid), (vcl ? "old" : "new")); + if (vcl) { + /* An update, just copy the phys_refnum and lba_offset + * fields + */ + unsigned int i; + unsigned int k; + copy_matching_bvd(ddf, &vcl->conf, update); + for (k = 0; k < be16_to_cpu(vc->prim_elmnt_count); k++) + dprintf("BVD %u has %08x at %llu\n", 0, + be32_to_cpu(vcl->conf.phys_refnum[k]), + be64_to_cpu(LBA_OFFSET(ddf, + &vcl->conf)[k])); + for (i = 1; i < vc->sec_elmnt_count; i++) { + copy_matching_bvd(ddf, vcl->other_bvds[i-1], + update); + for (k = 0; k < be16_to_cpu( + vc->prim_elmnt_count); k++) + dprintf("BVD %u has %08x at %llu\n", i, + be32_to_cpu + (vcl->other_bvds[i-1]-> + phys_refnum[k]), + be64_to_cpu + (LBA_OFFSET + (ddf, + vcl->other_bvds[i-1])[k])); + } + } else { + /* A new VD_CONF */ + unsigned int i; + if (!update->space) + return; + vcl = update->space; + update->space = NULL; + vcl->next = ddf->conflist; + memcpy(&vcl->conf, vc, len); + ent = find_vde_by_guid(ddf, vc->guid); + if (ent == DDF_NOTFOUND) + return; + vcl->vcnum = ent; + ddf->conflist = vcl; + for (i = 1; i < vc->sec_elmnt_count; i++) + memcpy(vcl->other_bvds[i-1], + update->buf + len * i, len); + } + /* Set DDF_Transition on all Failed devices - to help + * us detect those that are no longer in use + */ + for (pdnum = 0; pdnum < be16_to_cpu(ddf->phys->max_pdes); + pdnum++) + if (be16_and(ddf->phys->entries[pdnum].state, + cpu_to_be16(DDF_Failed))) + be16_set(ddf->phys->entries[pdnum].state, + cpu_to_be16(DDF_Transition)); + + /* Now make sure vlist is correct for each dl. */ + for (dl = ddf->dlist; dl; dl = dl->next) + ddf_update_vlist(ddf, dl); + ddf_remove_failed(ddf); + + ddf_set_updates_pending(ddf, vc); +} + static void ddf_process_update(struct supertype *st, struct metadata_update *update) { @@ -4604,278 +4895,20 @@ static void ddf_process_update(struct supertype *st, * and offset. This will also mark the spare as active with * a spare-assignment record. */ - struct ddf_super *ddf = st->sb; be32 *magic = (be32 *)update->buf; - struct phys_disk *pd; - struct virtual_disk *vd; - struct vd_config *vc; - struct vcl *vcl; - struct dl *dl; - unsigned int ent; - unsigned int pdnum, pd2, len; dprintf("Process update %x\n", be32_to_cpu(*magic)); if (be32_eq(*magic, DDF_PHYS_RECORDS_MAGIC)) { - if (update->len != (sizeof(struct phys_disk) + + if (update->len == (sizeof(struct phys_disk) + sizeof(struct phys_disk_entry))) - return; - pd = (struct phys_disk*)update->buf; - - ent = be16_to_cpu(pd->used_pdes); - if (ent >= be16_to_cpu(ddf->phys->max_pdes)) - return; - if (be16_and(pd->entries[0].state, cpu_to_be16(DDF_Missing))) { - struct dl **dlp; - /* removing this disk. */ - be16_set(ddf->phys->entries[ent].state, - cpu_to_be16(DDF_Missing)); - for (dlp = &ddf->dlist; *dlp; dlp = &(*dlp)->next) { - struct dl *dl = *dlp; - if (dl->pdnum == (signed)ent) { - close(dl->fd); - dl->fd = -1; - /* FIXME this doesn't free - * dl->devname */ - update->space = dl; - *dlp = dl->next; - break; - } - } - ddf_set_updates_pending(ddf, NULL); - return; - } - if (!all_ff(ddf->phys->entries[ent].guid)) - return; - ddf->phys->entries[ent] = pd->entries[0]; - ddf->phys->used_pdes = cpu_to_be16 - (1 + be16_to_cpu(ddf->phys->used_pdes)); - ddf_set_updates_pending(ddf, NULL); - if (ddf->add_list) { - struct active_array *a; - struct dl *al = ddf->add_list; - ddf->add_list = al->next; - - al->next = ddf->dlist; - ddf->dlist = al; - - /* As a device has been added, we should check - * for any degraded devices that might make - * use of this spare */ - for (a = st->arrays ; a; a=a->next) - a->check_degraded = 1; - } + ddf_process_phys_update(st, update); } else if (be32_eq(*magic, DDF_VIRT_RECORDS_MAGIC)) { - if (update->len != (sizeof(struct virtual_disk) + + if (update->len == (sizeof(struct virtual_disk) + sizeof(struct virtual_entry))) - return; - vd = (struct virtual_disk*)update->buf; - - if (vd->entries[0].state == DDF_state_deleted) { - if (_kill_subarray_ddf(ddf, vd->entries[0].guid)) - return; - } else { - ent = find_vde_by_guid(ddf, vd->entries[0].guid); - if (ent != DDF_NOTFOUND) { - dprintf("%s: VD %s exists already in slot %d\n", - __func__, guid_str(vd->entries[0].guid), - ent); - return; - } - 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)); - dprintf("%s: added VD %s in slot %d(s=%02x i=%02x)\n", - __func__, guid_str(vd->entries[0].guid), ent, - ddf->virt->entries[ent].state, - ddf->virt->entries[ent].init_state); - } - ddf_set_updates_pending(ddf, NULL); - } - - else if (be32_eq(*magic, DDF_VD_CONF_MAGIC)) { - vc = (struct vd_config*)update->buf; - len = ddf->conf_rec_len * 512; - if ((unsigned int)update->len != len * vc->sec_elmnt_count) { - pr_err("%s: %s: insufficient data (%d) for %u BVDs\n", - __func__, guid_str(vc->guid), update->len, - vc->sec_elmnt_count); - return; - } - for (vcl = ddf->conflist; vcl ; vcl = vcl->next) - if (memcmp(vcl->conf.guid, vc->guid, DDF_GUID_LEN) == 0) - break; - dprintf("%s: conf update for %s (%s)\n", __func__, - guid_str(vc->guid), (vcl ? "old" : "new")); - if (vcl) { - /* An update, just copy the phys_refnum and lba_offset - * fields - */ - unsigned int i; - unsigned int k; - copy_matching_bvd(ddf, &vcl->conf, update); - for (k = 0; k < be16_to_cpu(vc->prim_elmnt_count); k++) - dprintf("BVD %u has %08x at %llu\n", 0, - be32_to_cpu(vcl->conf.phys_refnum[k]), - be64_to_cpu(LBA_OFFSET(ddf, - &vcl->conf)[k])); - for (i = 1; i < vc->sec_elmnt_count; i++) { - copy_matching_bvd(ddf, vcl->other_bvds[i-1], - update); - for (k = 0; k < be16_to_cpu( - vc->prim_elmnt_count); k++) - dprintf("BVD %u has %08x at %llu\n", i, - be32_to_cpu - (vcl->other_bvds[i-1]-> - phys_refnum[k]), - be64_to_cpu - (LBA_OFFSET - (ddf, - vcl->other_bvds[i-1])[k])); - } - } else { - /* A new VD_CONF */ - unsigned int i; - if (!update->space) - return; - vcl = update->space; - update->space = NULL; - vcl->next = ddf->conflist; - memcpy(&vcl->conf, vc, len); - ent = find_vde_by_guid(ddf, vc->guid); - if (ent == DDF_NOTFOUND) - return; - vcl->vcnum = ent; - ddf->conflist = vcl; - for (i = 1; i < vc->sec_elmnt_count; i++) - memcpy(vcl->other_bvds[i-1], - update->buf + len * i, len); - } - /* Set DDF_Transition on all Failed devices - to help - * us detect those that are no longer in use - */ - for (pdnum = 0; pdnum < be16_to_cpu(ddf->phys->max_pdes); - pdnum++) - if (be16_and(ddf->phys->entries[pdnum].state, - cpu_to_be16(DDF_Failed))) - be16_set(ddf->phys->entries[pdnum].state, - cpu_to_be16(DDF_Transition)); - /* Now make sure vlist is correct for each dl. */ - for (dl = ddf->dlist; dl; dl = dl->next) { - unsigned int vn = 0; - int in_degraded = 0; - - if (dl->pdnum < 0) - continue; - for (vcl = ddf->conflist; vcl ; vcl = vcl->next) { - unsigned int dn, ibvd; - const struct vd_config *conf; - int vstate; - dn = get_pd_index_from_refnum(vcl, - dl->disk.refnum, - ddf->mppe, - &conf, &ibvd); - if (dn == DDF_NOTFOUND) - continue; - dprintf("dev %d/%08x has %s (sec=%u) at %d\n", - dl->pdnum, - be32_to_cpu(dl->disk.refnum), - guid_str(conf->guid), - conf->sec_elmnt_seq, vn); - /* Clear the Transition flag */ - if (be16_and - (ddf->phys->entries[dl->pdnum].state, - cpu_to_be16(DDF_Failed))) - be16_clear(ddf->phys - ->entries[dl->pdnum].state, - cpu_to_be16(DDF_Transition)); - dl->vlist[vn++] = vcl; - vstate = ddf->virt->entries[vcl->vcnum].state - & DDF_state_mask; - if (vstate == DDF_state_degraded || - vstate == DDF_state_part_optimal) - in_degraded = 1; - } - while (vn < ddf->max_part) - dl->vlist[vn++] = NULL; - if (dl->vlist[0]) { - be16_clear(ddf->phys->entries[dl->pdnum].type, - cpu_to_be16(DDF_Global_Spare)); - if (!be16_and(ddf->phys - ->entries[dl->pdnum].type, - cpu_to_be16(DDF_Active_in_VD))) { - be16_set(ddf->phys - ->entries[dl->pdnum].type, - cpu_to_be16(DDF_Active_in_VD)); - if (in_degraded) - be16_set(ddf->phys - ->entries[dl->pdnum] - .state, - cpu_to_be16 - (DDF_Rebuilding)); - } - } - if (dl->spare) { - be16_clear(ddf->phys->entries[dl->pdnum].type, - cpu_to_be16(DDF_Global_Spare)); - be16_set(ddf->phys->entries[dl->pdnum].type, - cpu_to_be16(DDF_Spare)); - } - if (!dl->vlist[0] && !dl->spare) { - be16_set(ddf->phys->entries[dl->pdnum].type, - cpu_to_be16(DDF_Global_Spare)); - be16_clear(ddf->phys->entries[dl->pdnum].type, - cpu_to_be16(DDF_Spare)); - be16_clear(ddf->phys->entries[dl->pdnum].type, - cpu_to_be16(DDF_Active_in_VD)); - } - } - - /* Now remove any 'Failed' devices that are not part - * of any VD. They will have the Transition flag set. - * Once done, we need to update all dl->pdnum numbers. - */ - pd2 = 0; - for (pdnum = 0; pdnum < be16_to_cpu(ddf->phys->max_pdes); - pdnum++) { - if (be32_to_cpu(ddf->phys->entries[pdnum].refnum) == - 0xFFFFFFFF) - continue; - if (be16_and(ddf->phys->entries[pdnum].state, - cpu_to_be16(DDF_Failed)) - && be16_and(ddf->phys->entries[pdnum].state, - cpu_to_be16(DDF_Transition))) { - /* skip this one unless in dlist*/ - for (dl = ddf->dlist; dl; dl = dl->next) - if (dl->pdnum == (int)pdnum) - break; - if (!dl) - continue; - } - if (pdnum == pd2) - pd2++; - else { - ddf->phys->entries[pd2] = - ddf->phys->entries[pdnum]; - for (dl = ddf->dlist; dl; dl = dl->next) - if (dl->pdnum == (int)pdnum) - dl->pdnum = pd2; - pd2++; - } - } - ddf->phys->used_pdes = cpu_to_be16(pd2); - while (pd2 < pdnum) { - memset(ddf->phys->entries[pd2].guid, 0xff, - DDF_GUID_LEN); - pd2++; - } - - ddf_set_updates_pending(ddf, vc); + ddf_process_virt_update(st, update); + } else if (be32_eq(*magic, DDF_VD_CONF_MAGIC)) { + ddf_process_conf_update(st, update); } /* case DDF_SPARE_ASSIGN_MAGIC */ }