mdadm: add device to a container

Adding a device updates the container and then mdmon takes action upon
noticing a change in devices.  This reuses the container version of
add_to_super to create a new record for the device.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
Dan Williams 2008-08-19 17:19:51 +10:00 committed by NeilBrown
parent 7bc1962f8c
commit 43dad3d6fb
3 changed files with 208 additions and 37 deletions

View File

@ -404,8 +404,7 @@ int Manage_subdevs(char *devname, int fd,
return 1;
}
if (array.not_persistent == 0) {
if (array.not_persistent == 0 || tst->ss->external) {
/* Make sure device is large enough */
if (tst->ss->avail_size(tst, ldsize/512) <
array_size) {
@ -415,9 +414,13 @@ int Manage_subdevs(char *devname, int fd,
}
/* need to find a sample superblock to copy, and
* a spare slot to use
* a spare slot to use.
* For 'external' array (well, container based),
* We can just load the metadata for the array.
*/
for (j = 0; j < tst->max_devs; j++) {
if (tst->ss->external) {
tst->ss->load_super(tst, fd, NULL);
} else for (j = 0; j < tst->max_devs; j++) {
char *dev;
int dfd;
disc.number = j;
@ -439,6 +442,7 @@ int Manage_subdevs(char *devname, int fd,
close(dfd);
break;
}
/* FIXME this is a bad test to be using */
if (!tst->sb) {
fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
return 1;
@ -507,7 +511,7 @@ int Manage_subdevs(char *devname, int fd,
disc.minor = minor(stb.st_rdev);
disc.number =j;
disc.state = 0;
if (array.not_persistent==0) {
if (array.not_persistent==0 || tst->ss->external) {
int dfd;
if (dv->writemostly)
disc.state |= 1 << MD_DISK_WRITEMOSTLY;
@ -515,7 +519,10 @@ int Manage_subdevs(char *devname, int fd,
tst->ss->add_to_super(tst, &disc, dfd,
dv->devname);
/* write_init_super will close 'dfd' */
if (tst->ss->write_init_super(tst))
if (tst->ss->external)
/* mdmon will write the metadata */
close(dfd);
else if (tst->ss->write_init_super(tst))
return 1;
} else if (dv->re_add) {
/* this had better be raid1.
@ -548,7 +555,52 @@ int Manage_subdevs(char *devname, int fd,
}
if (dv->writemostly)
disc.state |= (1 << MD_DISK_WRITEMOSTLY);
if (ioctl(fd,ADD_NEW_DISK, &disc)) {
if (tst->ss->external) {
/* add a disk to an external metadata container
* only if mdmon is around to see it
*/
struct mdinfo new_mdi;
struct mdinfo *sra;
int container_fd;
int devnum = fd2devnum(fd);
container_fd = open_dev_excl(devnum);
if (container_fd < 0) {
fprintf(stderr, Name ": add failed for %s:"
" could not get exclusive access to container\n",
dv->devname);
return 1;
}
if (!mdmon_running(devnum)) {
fprintf(stderr, Name ": add failed for %s: mdmon not running\n",
dv->devname);
close(container_fd);
return 1;
}
sra = sysfs_read(container_fd, -1, 0);
if (!sra) {
fprintf(stderr, Name ": add failed for %s: sysfs_read failed\n",
dv->devname);
close(container_fd);
return 1;
}
sra->array.level = LEVEL_CONTAINER;
/* Need to set data_offset and component_size */
tst->ss->getinfo_super(tst, &new_mdi);
new_mdi.disk.major = disc.major;
new_mdi.disk.minor = disc.minor;
if (sysfs_add_disk(sra, &new_mdi) != 0) {
fprintf(stderr, Name ": add new device to external metadata"
" failed for %s\n", dv->devname);
close(container_fd);
return 1;
}
ping_monitor(devnum2devname(devnum));
sysfs_free(sra);
close(container_fd);
} else if (ioctl(fd, ADD_NEW_DISK, &disc)) {
fprintf(stderr, Name ": add new device failed for %s as %d: %s\n",
dv->devname, j, strerror(errno));
return 1;

View File

@ -218,6 +218,34 @@ static void queue_metadata_update(struct metadata_update *mu)
*qp = mu;
}
static void add_disk_to_container(struct supertype *st, struct mdinfo *sd)
{
int dfd;
char nm[20];
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,
};
dprintf("%s: add %d:%d to container\n",
__func__, sd->disk.major, sd->disk.minor);
sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
dfd = dev_open(nm, O_RDWR);
if (dfd < 0)
return;
st->update_tail = &update;
st->ss->add_to_super(st, &dk, dfd, NULL);
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)
{
@ -256,6 +284,16 @@ static void manage_container(struct mdstat_ent *mdstat,
} else
cdp = &(*cdp)->next;
}
/* check for additions */
for (di = mdi->devs; di; di = di->next) {
for (cd = container->devs; cd; cd = cd->next)
if (di->disk.major == cd->disk.major &&
di->disk.minor == cd->disk.minor)
break;
if (!cd)
add_disk_to_container(container, di);
}
sysfs_free(mdi);
container->devcnt = mdstat->devcnt;
}

View File

@ -174,7 +174,8 @@ struct intel_super {
struct imsm_disk disk;
int fd;
} *disks;
struct bbm_log *bbm_log;
struct dl *add; /* list of disks to add while mdmon active */
struct bbm_log *bbm_log;
};
struct extent {
@ -185,6 +186,7 @@ struct extent {
enum imsm_update_type {
update_activate_spare,
update_create_array,
update_add_disk,
};
struct imsm_update_activate_spare {
@ -201,6 +203,10 @@ struct imsm_update_create_array {
struct imsm_dev dev;
};
struct imsm_update_add_disk {
enum imsm_update_type type;
};
static int imsm_env_devname_as_serial(void)
{
char *val = getenv("IMSM_DEVNAME_AS_SERIAL");
@ -564,7 +570,13 @@ static int match_home_imsm(struct supertype *st, char *homehost)
static void uuid_from_super_imsm(struct supertype *st, int uuid[4])
{
printf("%s\n", __FUNCTION__);
/* imsm does not track uuid's so just make sure we never return
* the same value twice to break uuid matching in Manage_subdevs
* FIXME what about the use of uuid's with bitmap's?
*/
static int dummy_id = 0;
uuid[0] = dummy_id++;
}
#if 0
@ -1264,11 +1276,11 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
}
*sbp = super;
st->container_dev = fd2devnum(fd);
if (st->ss == NULL) {
st->ss = &super_imsm;
st->minor_version = 0;
st->max_devs = IMSM_MAX_DEVICES;
st->container_dev = fd2devnum(fd);
}
return 0;
@ -1556,7 +1568,6 @@ static void add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
dd->minor = minor(stb.st_rdev);
dd->index = -1;
dd->devname = devname ? strdup(devname) : NULL;
dd->next = super->disks;
dd->fd = fd;
rv = imsm_read_serial(fd, devname, dd->serial);
if (rv) {
@ -1576,7 +1587,14 @@ static void add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
dd->disk.scsi_id = __cpu_to_le32(id);
else
dd->disk.scsi_id = __cpu_to_le32(0);
super->disks = dd;
if (st->update_tail) {
dd->next = super->add;
super->add = dd;
} else {
dd->next = super->disks;
super->disks = dd;
}
}
static int store_imsm_mpb(int fd, struct intel_super *super);
@ -1688,43 +1706,76 @@ static int write_super_imsm(struct intel_super *super, int doclose)
return 0;
}
static int create_array(struct supertype *st)
{
size_t len;
struct imsm_update_create_array *u;
struct intel_super *super = st->sb;
struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0);
u = malloc(len);
if (!u) {
fprintf(stderr, "%s: failed to allocate update buffer\n",
__func__);
return 1;
}
u->type = update_create_array;
u->dev_idx = super->current_vol;
imsm_copy_dev(&u->dev, dev);
append_metadata_update(st, u, len);
return 0;
}
static int add_disk(struct supertype *st)
{
struct intel_super *super = st->sb;
size_t len;
struct imsm_update_add_disk *u;
if (!super->add)
return 0;
len = sizeof(*u);
u = malloc(len);
if (!u) {
fprintf(stderr, "%s: failed to allocate update buffer\n",
__func__);
return 1;
}
u->type = update_add_disk;
append_metadata_update(st, u, len);
return 0;
}
static int write_init_super_imsm(struct supertype *st)
{
if (st->update_tail) {
/* queue the recently created array as a metadata update */
size_t len;
struct imsm_update_create_array *u;
/* queue the recently created array / added disk
* as a metadata update */
struct intel_super *super = st->sb;
struct imsm_dev *dev;
struct dl *d;
int rv;
if (super->current_vol < 0 ||
!(dev = get_imsm_dev(super, super->current_vol))) {
fprintf(stderr, "%s: could not determine sub-array\n",
__func__);
return 1;
}
len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0);
u = malloc(len);
if (!u) {
fprintf(stderr, "%s: failed to allocate update buffer\n",
__func__);
return 1;
}
u->type = update_create_array;
u->dev_idx = super->current_vol;
imsm_copy_dev(&u->dev, dev);
append_metadata_update(st, u, len);
/* determine if we are creating a volume or adding a disk */
if (super->current_vol < 0) {
/* in the add disk case we are running in mdmon
* context, so don't close fd's
*/
return add_disk(st);
} else
rv = create_array(st);
for (d = super->disks; d ; d = d->next) {
close(d->fd);
d->fd = -1;
}
return 0;
return rv;
} else
return write_super_imsm(st->sb, 1);
}
@ -2779,6 +2830,36 @@ static void imsm_process_update(struct supertype *st,
}
break;
}
case update_add_disk:
/* we may be able to repair some arrays if disks are
* being added */
if (super->add) {
struct active_array *a;
for (a = st->arrays; a; a = a->next)
a->check_degraded = 1;
}
/* check if we can add / replace some disks in the
* metadata */
while (super->add) {
struct dl **dlp, *dl, *al;
al = super->add;
super->add = al->next;
for (dlp = &super->disks; *dlp ; ) {
if (memcmp(al->serial, (*dlp)->serial,
MAX_RAID_SERIAL_LEN) == 0) {
dl = *dlp;
*dlp = (*dlp)->next;
__free_imsm_disk(dl);
break;
} else
dlp = &(*dlp)->next;
}
al->next = super->disks;
super->disks = al;
}
break;
}
}