Add reconfiguration support for adding and removing devices from RAID1 arrays. Signed-off-by: Adam DiCarlo <bikko@xxxxxxxxxx> Signed-off-by: James Simshaw <simshawj@xxxxxxxxxx> Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
--- ORIGINAL/lib/reconfig/reconfig.c 1969-12-31 16:00:00.000000000 -0800 +++ PATCHED/lib/reconfig/reconfig.c 2006-08-29 13:55:33.000000000 -0700 @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2006 IBM, all rights reserved. + * Written by Darrick Wong <djwong@xxxxxxxxxx>, + * James Simshaw <simshawj@xxxxxxxxxx>, and + * Adam DiCarlo <bikko@xxxxxxxxxx> + * + * See file LICENSE at the top of this source tree for license information. + */ +#include "internal.h" +#include <errno.h> + +/* Add a device to a RAID1 set and start the resync */ +static int add_dev_to_raid1(struct lib_context *lc, struct raid_set *rs, struct raid_dev *rd) +{ + struct raid_dev *tmp; + struct list_head log; + struct change *entry; + int ret; + + /* Init playback log */ + INIT_LIST_HEAD(&log); + + /* Add device to the raid set */ + if (!(entry = dbg_malloc(sizeof (*entry)))) { + ret = -ENOMEM; + goto err; + } + entry->type = ADD_TO_SET; + entry->rs = rs; + entry->rd = rd; + list_add_tail(&entry->changes, &log); + list_add_tail(&rd->devs, &rs->devs); + rd->type = t_raid1; + + /* Check that this is a sane configuration */ + list_for_each_entry(tmp, &rs->devs, devs) + if (!tmp->fmt->check(lc, rs)) { + ret = -ENXIO; + goto err; + } + + /* Write the metadata of the drive we're adding _first_ */ + if (!(entry = dbg_malloc(sizeof (*entry)))) { + ret = -ENOMEM; + goto err; + } + entry->type = WRITE_METADATA; + entry->rd = rd; + list_add_tail(&entry->changes, &log); + ret = rd->fmt->write(lc, rd, 0); + if (!ret) + goto err; + + /* Write metadatas of every device in the set */ + list_for_each_entry(tmp, &rs->devs, devs) { + if (tmp == rd) + continue; + if (!(entry = dbg_malloc(sizeof (*entry)))) { + ret = -ENOMEM; + goto err; + } + entry->type = WRITE_METADATA; + entry->rd = tmp; + list_add_tail(&entry->changes, &log); + ret = tmp->fmt->write(lc, tmp, 0); + if (!ret) + goto err; + } + + /* Reconfigure device mapper */ + // FIXME: is nosync enough? rs->status |= s_inconsistent; + rs->status |= s_nosync; + change_set(lc, A_ACTIVATE, rs); + ret = change_set(lc, A_RELOAD, rs); + // FIXME: might need this later: change_set(lc, A_DEACTIVATE,rs); + if (!ret) + goto err; + + /* End transaction */ + end_log(lc, &log); + return 0; + +err: + revert_log(lc, &log); + return ret; +} + +int nuke_spare(struct lib_context *lc, struct raid_dev *rd) +{ + printf("Nuking Spare\n"); + list_del(&rd->devs); + return 0; +} + +/* Add a disk to an array. */ +int add_dev_to_set(struct lib_context *lc, struct raid_set *rs, struct raid_dev *rd) +{ + struct { + enum change_type type; + int (*func) (struct lib_context *lc, struct raid_set *rs, struct raid_dev *rd); + } handlers[] = { + {t_raid1, add_dev_to_raid1}, + {t_undef, NULL}, + }, *h = handlers; + + if(rd->type == t_spare) + nuke_spare(lc, rd); + + if (rd->type != t_spare && rd->devs.next) + LOG_ERR(lc, -EBUSY, "Disk already in another set!"); + + if (rd->type == t_group) + LOG_ERR(lc, -EISDIR, "Can't add a group raid_dev to a raid_set."); + + do { + if (h->type == rs->type) + return h->func(lc, rs, rd); + } while ((++h)->type != t_undef); + + return 0; +} + +/* Remove a disk from a raid1 */ +static int del_dev_in_raid1(struct lib_context *lc, struct raid_set *rs, struct raid_dev *rd) +{ + struct raid_dev *tmp; + struct list_head log; + struct change *entry; + int ret; + + /* Init playback log */ + INIT_LIST_HEAD(&log); + + /* Remove device from the raid set */ + if (!(entry = dbg_malloc(sizeof (*entry)))) { + ret = -ENOMEM; + goto err; + } + entry->type = DELETE_FROM_SET; + entry->rs = rs; + entry->rd = rd; + list_add_tail(&entry->changes, &log); + list_del(&rd->devs); + rd->type = t_spare; + + /* Check that this is a sane configuration */ + list_for_each_entry(tmp, &rs->devs, devs) + if (!tmp->fmt->check(lc, rs)) { + ret = -ENXIO; + goto err; + } + + /* Write the metadata of the drive we're removing _first_ */ + if (!(entry = dbg_malloc(sizeof (*entry)))) { + ret = -ENOMEM; + goto err; + } + entry->type = WRITE_METADATA; + entry->rd = rd; + list_add_tail(&entry->changes, &log); + ret = rd->fmt->write(lc, rd, 0); + if (!ret) + goto err; + + /* Write metadatas of every device in the set */ + list_for_each_entry(tmp, &rs->devs, devs) { + if (tmp == rd) + continue; + if (!(entry = dbg_malloc(sizeof (*entry)))) { + ret = -ENOMEM; + goto err; + } + entry->type = WRITE_METADATA; + entry->rd = tmp; + list_add_tail(&entry->changes, &log); + ret = tmp->fmt->write(lc, tmp, 0); + if (!ret) + goto err; + } + + /* Reconfigure device mapper */ + rs->status |= s_inconsistent; + rs->status |= s_nosync; + ret = change_set(lc, A_RELOAD, rs); + if (!ret) + goto err; + + /* End transaction */ + end_log(lc, &log); + return 0; + +err: + revert_log(lc, &log); + return ret; + + return 0; +} + + + +/* Remove a disk from an array */ +int del_dev_in_set(struct lib_context *lc, struct raid_set *rs, struct raid_dev *rd) +{ + struct { + enum change_type type; + int (*func) (struct lib_context *lc, struct raid_set *rs, struct raid_dev *rd); + } handlers[] = { + {t_raid1, del_dev_in_raid1}, + {t_undef, NULL}, + }, *h = handlers; + + if (!(rd->devs.next)) + LOG_ERR(lc, -EBUSY, "Disk is not in a set!"); + + /* FIXME: Not sure if this is true. */ + if (rd->type == t_group) + LOG_ERR(lc, -EISDIR, "Can't remove a group raid_dev from a raid_set."); + + do { + if (h->type == rs->type) + return h->func(lc, rs, rd); + } while ((++h)->type != t_undef); + + return 0; +} --- ORIGINAL/include/dmraid/reconfig.h 1969-12-31 16:00:00.000000000 -0800 +++ PATCHED/include/dmraid/reconfig.h 2006-08-03 14:46:23.000000000 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Darrick Wong, IBM. + * All rights reserved. + * + * See the file LICENSE at the top of this source tree for license information. + */ + +#ifndef _RECONFIG_H_ +#define _RECONFIG_H_ + +#include <dmraid/metadata.h> +#include <dmraid/list.h> + +/* Type of change that a log entry describes */ +enum change_type { + ADD_TO_SET, + DELETE_FROM_SET, + WRITE_METADATA, + CREATE_CHILD_RD, + CREATE_RD, + DELETE_RD, + CREATE_RS, + DELETE_RS, + END_TRANSACTION +}; + +/* Change log entry */ +struct change { + struct list_head changes; /* Chain of log entries */ + enum change_type type; + + /* All of these items may be listed as parameters */ + struct raid_set *rs; + struct raid_dev *rd; + + uint64_t offset; + uint64_t length; + + struct dev_info *di; + + char *name; +}; + +extern int add_dev_to_set(struct lib_context *lc, struct raid_set *rs, struct raid_dev *rd); +extern int del_dev_in_set(struct lib_context *lc, struct raid_set *rs, struct raid_dev *rd); +extern void end_log(struct lib_context *lc, struct list_head *log); +extern int revert_log(struct lib_context *lc, struct list_head *log); + +#endif --- ORIGINAL/lib/reconfig/log_ops.c 1969-12-31 16:00:00.000000000 -0800 +++ PATCHED/lib/reconfig/log_ops.c 2006-08-03 14:46:26.000000000 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006 Darrick Wong, IBM + * All rights reserved. + * + * See file LICENSE at the top of this source tree for license information. + */ +#include "internal.h" + +void end_log(struct lib_context *lc, struct list_head *log) +{ + struct list_head *a, *b; + + list_for_each_safe(a, b, log) + list_del(a); +} + +int revert_log(struct lib_context *lc, struct list_head *log) +{ + struct change *entry; + struct raid_dev *rd; + int ret; + int writes_started = 0; + + list_for_each_entry(entry, log, changes) { + if (writes_started && entry->type != WRITE_METADATA) + LOG_ERR(lc, 1, "State change after metadata write?"); + if (entry->type == ADD_TO_SET) { + rd->type = t_spare; + list_del(&entry->rd->devs); + } else if (entry->type == WRITE_METADATA) { + writes_started = 1; + rd = entry->rd; + ret = rd->fmt->write(lc, rd, 0); + if (ret) + LOG_ERR(lc, ret, "Error while reverting metadata."); + } + } + + return 0; +} --- ORIGINAL/lib/Makefile.in 2006-07-25 06:17:02.000000000 -0700 +++ PATCHED/lib/Makefile.in 2006-08-24 11:57:29.000000000 -0700 @@ -41,7 +41,9 @@ SOURCES=\ format/ddf/ddf1_crc.c \ format/ddf/ddf1_cvt.c \ format/ddf/ddf1_dump.c \ - format/partition/dos.c + format/partition/dos.c \ + reconfig/log_ops.c \ + reconfig/reconfig.c OBJECTS=$(SOURCES:%.c=%.o)
_______________________________________________ Ataraid-list mailing list Ataraid-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/ataraid-list