From: Dan Williams References: bnc#587925 Subject: Create: cleanup after failed create in duplicated array member case mdadm prevents creation when device names are duplicated on the command line, but leaves the partially created array intact. Detect this case in the error code from add_to_super() and cleanup the partially created array. The imsm handler is updated to report this conflict in add_to_super_imsm_volume(). Note that since neither mdmon, nor userspace for that matter, ever saw an active array we only need to perform a subset of the cleanup actions. So call ioctl(STOP_ARRAY) directly and arrange for Create() to cleanup the map file rather than calling Manage_runstop(). Reported-by: Krzysztof Wojcik Signed-off-by: Dan Williams --- Create.c | 10 ++++++++-- Manage.c | 8 +++----- mapfile.c | 10 ++++++++++ mdadm.h | 1 + super-intel.c | 11 ++++++++++- 5 files changed, 32 insertions(+), 8 deletions(-) --- mdadm-3.0.3.orig/Create.c +++ mdadm-3.0.3/Create.c @@ -755,8 +755,10 @@ int Create(struct supertype *st, char *m if (fd >= 0) remove_partitions(fd); if (st->ss->add_to_super(st, &inf->disk, - fd, dv->devname)) + fd, dv->devname)) { + ioctl(mdfd, STOP_ARRAY, NULL); goto abort; + } st->ss->getinfo_super(st, inf); safe_mode_delay = inf->safe_mode_delay; @@ -860,7 +862,7 @@ int Create(struct supertype *st, char *m if (ioctl(mdfd, RUN_ARRAY, ¶m)) { fprintf(stderr, Name ": RUN_ARRAY failed: %s\n", strerror(errno)); - Manage_runstop(mddev, mdfd, -1, 0); + ioctl(mdfd, STOP_ARRAY, NULL); goto abort; } } @@ -881,6 +883,10 @@ int Create(struct supertype *st, char *m return 0; abort: + map_lock(&map); + map_remove(&map, fd2devnum(mdfd)); + map_unlock(&map); + if (mdfd >= 0) close(mdfd); return 1; --- mdadm-3.0.3.orig/Manage.c +++ mdadm-3.0.3/Manage.c @@ -277,11 +277,9 @@ int Manage_runstop(char *devname, int fd if (quiet <= 0) fprintf(stderr, Name ": stopped %s\n", devname); - if (devnum != NoMdDev) { - map_delete(&map, devnum); - map_write(map); - map_free(map); - } + map_lock(&map); + map_remove(&map, devnum); + map_unlock(&map); } return 0; } --- mdadm-3.0.3.orig/mapfile.c +++ mdadm-3.0.3/mapfile.c @@ -239,6 +239,16 @@ void map_delete(struct map_ent **mapp, i } } +void map_remove(struct map_ent **mapp, int devnum) +{ + if (devnum == NoMdDev) + return; + + map_delete(mapp, devnum); + map_write(*mapp); + map_free(*mapp); +} + struct map_ent *map_by_uuid(struct map_ent **map, int uuid[4]) { struct map_ent *mp; --- mdadm-3.0.3.orig/mdadm.h +++ mdadm-3.0.3/mdadm.h @@ -324,6 +324,7 @@ struct map_ent { }; extern int map_update(struct map_ent **mpp, int devnum, char *metadata, int uuid[4], char *path); +extern void map_remove(struct map_ent **map, int devnum); extern struct map_ent *map_by_uuid(struct map_ent **map, int uuid[4]); extern struct map_ent *map_by_devnum(struct map_ent **map, int devnum); extern struct map_ent *map_by_name(struct map_ent **map, char *name); --- mdadm-3.0.3.orig/super-intel.c +++ mdadm-3.0.3/super-intel.c @@ -2817,7 +2817,7 @@ static int init_super_imsm_volume(struct map->num_members = info->raid_disks; for (i = 0; i < map->num_members; i++) { /* initialized in add_to_super */ - set_imsm_ord_tbl_ent(map, i, 0); + set_imsm_ord_tbl_ent(map, i, IMSM_ORD_REBUILD); } mpb->num_raid_devs++; @@ -2895,6 +2895,7 @@ static int add_to_super_imsm_volume(stru struct dl *dl; struct imsm_dev *dev; struct imsm_map *map; + int slot; dev = get_imsm_dev(super, super->current_vol); map = get_imsm_map(dev, 0); @@ -2929,6 +2930,14 @@ static int add_to_super_imsm_volume(stru dl->index = super->anchor->num_disks; super->anchor->num_disks++; } + /* Check the device has not already been added */ + slot = get_imsm_disk_slot(map, dl->index); + if (slot >= 0 && + (get_imsm_ord_tbl_ent(dev, slot) & IMSM_ORD_REBUILD) == 0) { + fprintf(stderr, Name ": %s has been included in this array twice\n", + devname); + return 1; + } set_imsm_ord_tbl_ent(map, dk->number, dl->index); dl->disk.status = CONFIGURED_DISK;