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; return 1;
} }
if (array.not_persistent == 0) { if (array.not_persistent == 0 || tst->ss->external) {
/* Make sure device is large enough */ /* Make sure device is large enough */
if (tst->ss->avail_size(tst, ldsize/512) < if (tst->ss->avail_size(tst, ldsize/512) <
array_size) { array_size) {
@ -415,9 +414,13 @@ int Manage_subdevs(char *devname, int fd,
} }
/* need to find a sample superblock to copy, and /* 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; char *dev;
int dfd; int dfd;
disc.number = j; disc.number = j;
@ -439,6 +442,7 @@ int Manage_subdevs(char *devname, int fd,
close(dfd); close(dfd);
break; break;
} }
/* FIXME this is a bad test to be using */
if (!tst->sb) { if (!tst->sb) {
fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n"); fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
return 1; return 1;
@ -507,7 +511,7 @@ int Manage_subdevs(char *devname, int fd,
disc.minor = minor(stb.st_rdev); disc.minor = minor(stb.st_rdev);
disc.number =j; disc.number =j;
disc.state = 0; disc.state = 0;
if (array.not_persistent==0) { if (array.not_persistent==0 || tst->ss->external) {
int dfd; int dfd;
if (dv->writemostly) if (dv->writemostly)
disc.state |= 1 << MD_DISK_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, tst->ss->add_to_super(tst, &disc, dfd,
dv->devname); dv->devname);
/* write_init_super will close 'dfd' */ /* 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; return 1;
} else if (dv->re_add) { } else if (dv->re_add) {
/* this had better be raid1. /* this had better be raid1.
@ -548,7 +555,52 @@ int Manage_subdevs(char *devname, int fd,
} }
if (dv->writemostly) if (dv->writemostly)
disc.state |= (1 << MD_DISK_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", fprintf(stderr, Name ": add new device failed for %s as %d: %s\n",
dv->devname, j, strerror(errno)); dv->devname, j, strerror(errno));
return 1; return 1;

View File

@ -218,6 +218,34 @@ static void queue_metadata_update(struct metadata_update *mu)
*qp = 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, static void manage_container(struct mdstat_ent *mdstat,
struct supertype *container) struct supertype *container)
{ {
@ -256,6 +284,16 @@ static void manage_container(struct mdstat_ent *mdstat,
} else } else
cdp = &(*cdp)->next; 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); sysfs_free(mdi);
container->devcnt = mdstat->devcnt; container->devcnt = mdstat->devcnt;
} }

View File

@ -174,7 +174,8 @@ struct intel_super {
struct imsm_disk disk; struct imsm_disk disk;
int fd; int fd;
} *disks; } *disks;
struct bbm_log *bbm_log; struct dl *add; /* list of disks to add while mdmon active */
struct bbm_log *bbm_log;
}; };
struct extent { struct extent {
@ -185,6 +186,7 @@ struct extent {
enum imsm_update_type { enum imsm_update_type {
update_activate_spare, update_activate_spare,
update_create_array, update_create_array,
update_add_disk,
}; };
struct imsm_update_activate_spare { struct imsm_update_activate_spare {
@ -201,6 +203,10 @@ struct imsm_update_create_array {
struct imsm_dev dev; struct imsm_dev dev;
}; };
struct imsm_update_add_disk {
enum imsm_update_type type;
};
static int imsm_env_devname_as_serial(void) static int imsm_env_devname_as_serial(void)
{ {
char *val = getenv("IMSM_DEVNAME_AS_SERIAL"); 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]) 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 #if 0
@ -1264,11 +1276,11 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
} }
*sbp = super; *sbp = super;
st->container_dev = fd2devnum(fd);
if (st->ss == NULL) { if (st->ss == NULL) {
st->ss = &super_imsm; st->ss = &super_imsm;
st->minor_version = 0; st->minor_version = 0;
st->max_devs = IMSM_MAX_DEVICES; st->max_devs = IMSM_MAX_DEVICES;
st->container_dev = fd2devnum(fd);
} }
return 0; 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->minor = minor(stb.st_rdev);
dd->index = -1; dd->index = -1;
dd->devname = devname ? strdup(devname) : NULL; dd->devname = devname ? strdup(devname) : NULL;
dd->next = super->disks;
dd->fd = fd; dd->fd = fd;
rv = imsm_read_serial(fd, devname, dd->serial); rv = imsm_read_serial(fd, devname, dd->serial);
if (rv) { 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); dd->disk.scsi_id = __cpu_to_le32(id);
else else
dd->disk.scsi_id = __cpu_to_le32(0); 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); 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; 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) static int write_init_super_imsm(struct supertype *st)
{ {
if (st->update_tail) { if (st->update_tail) {
/* queue the recently created array as a metadata update */ /* queue the recently created array / added disk
size_t len; * as a metadata update */
struct imsm_update_create_array *u;
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
struct imsm_dev *dev;
struct dl *d; struct dl *d;
int rv;
if (super->current_vol < 0 || /* determine if we are creating a volume or adding a disk */
!(dev = get_imsm_dev(super, super->current_vol))) { if (super->current_vol < 0) {
fprintf(stderr, "%s: could not determine sub-array\n", /* in the add disk case we are running in mdmon
__func__); * context, so don't close fd's
return 1; */
} return add_disk(st);
} else
rv = create_array(st);
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);
for (d = super->disks; d ; d = d->next) { for (d = super->disks; d ; d = d->next) {
close(d->fd); close(d->fd);
d->fd = -1; d->fd = -1;
} }
return 0; return rv;
} else } else
return write_super_imsm(st->sb, 1); return write_super_imsm(st->sb, 1);
} }
@ -2779,6 +2830,36 @@ static void imsm_process_update(struct supertype *st,
} }
break; 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;
} }
} }