if (!st)
return NULL;
memset(st, 0, sizeof(*st));
+ st->container_dev = NoMdDev;
st->ss = &super_imsm;
st->max_devs = IMSM_MAX_DEVICES;
st->minor_version = 0;
return (disk->status & FAILED_DISK) == FAILED_DISK;
}
+/* Return minimum size of a spare that can be used in this array*/
+static unsigned long long min_acceptable_spare_size_imsm(struct supertype *st)
+{
+ struct intel_super *super = st->sb;
+ struct dl *dl;
+ struct extent *e;
+ int i;
+ unsigned long long rv = 0;
+
+ if (!super)
+ return rv;
+ /* find first active disk in array */
+ dl = super->disks;
+ while (dl && (is_failed(&dl->disk) || dl->index == -1))
+ dl = dl->next;
+ if (!dl)
+ return rv;
+ /* find last lba used by subarrays */
+ e = get_extents(super, dl);
+ if (!e)
+ return rv;
+ for (i = 0; e[i].size; i++)
+ continue;
+ if (i > 0)
+ rv = e[i-1].start + e[i-1].size;
+ free(e);
+ /* add the amount of space needed for metadata */
+ rv = rv + MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
+ return rv * 512;
+}
+
#ifndef MDASSEMBLE
static __u64 blocks_per_migr_unit(struct imsm_dev *dev);
/* check the config file to see if we can return a real uuid for this spare */
static void fixup_container_spare_uuid(struct mdinfo *inf)
{
- struct mddev_ident_s *array_list;
+ struct mddev_ident *array_list;
if (inf->array.level != LEVEL_CONTAINER ||
memcmp(inf->uuid, uuid_match_any, sizeof(int[4])) != 0)
struct intel_super *super = st->sb;
struct imsm_disk *disk;
int map_disks = info->array.raid_disks;
+ int max_enough = -1;
+ int i;
+ struct imsm_super *mpb;
if (super->current_vol >= 0) {
getinfo_super_imsm_volume(st, info, map);
info->recovery_start = MaxSector;
/* do we have the all the insync disks that we expect? */
- if (st->loaded_container) {
- struct imsm_super *mpb = super->anchor;
- int max_enough = -1, i;
+ mpb = super->anchor;
- for (i = 0; i < mpb->num_raid_devs; i++) {
- struct imsm_dev *dev = get_imsm_dev(super, i);
- int failed, enough, j, missing = 0;
- struct imsm_map *map;
- __u8 state;
+ for (i = 0; i < mpb->num_raid_devs; i++) {
+ struct imsm_dev *dev = get_imsm_dev(super, i);
+ int failed, enough, j, missing = 0;
+ struct imsm_map *map;
+ __u8 state;
- failed = imsm_count_failed(super, dev);
- state = imsm_check_degraded(super, dev, failed);
- map = get_imsm_map(dev, dev->vol.migr_state);
+ failed = imsm_count_failed(super, dev);
+ state = imsm_check_degraded(super, dev, failed);
+ map = get_imsm_map(dev, dev->vol.migr_state);
- /* any newly missing disks?
- * (catches single-degraded vs double-degraded)
- */
- for (j = 0; j < map->num_members; j++) {
- __u32 ord = get_imsm_ord_tbl_ent(dev, i);
- __u32 idx = ord_to_idx(ord);
+ /* any newly missing disks?
+ * (catches single-degraded vs double-degraded)
+ */
+ for (j = 0; j < map->num_members; j++) {
+ __u32 ord = get_imsm_ord_tbl_ent(dev, i);
+ __u32 idx = ord_to_idx(ord);
- if (!(ord & IMSM_ORD_REBUILD) &&
- get_imsm_missing(super, idx)) {
- missing = 1;
- break;
- }
+ if (!(ord & IMSM_ORD_REBUILD) &&
+ get_imsm_missing(super, idx)) {
+ missing = 1;
+ break;
}
+ }
- if (state == IMSM_T_STATE_FAILED)
- enough = -1;
- else if (state == IMSM_T_STATE_DEGRADED &&
- (state != map->map_state || missing))
- enough = 0;
- else /* we're normal, or already degraded */
- enough = 1;
+ if (state == IMSM_T_STATE_FAILED)
+ enough = -1;
+ else if (state == IMSM_T_STATE_DEGRADED &&
+ (state != map->map_state || missing))
+ enough = 0;
+ else /* we're normal, or already degraded */
+ enough = 1;
- /* in the missing/failed disk case check to see
- * if at least one array is runnable
- */
- max_enough = max(max_enough, enough);
- }
- dprintf("%s: enough: %d\n", __func__, max_enough);
- info->container_enough = max_enough;
- } else
- info->container_enough = -1;
+ /* in the missing/failed disk case check to see
+ * if at least one array is runnable
+ */
+ max_enough = max(max_enough, enough);
+ }
+ dprintf("%s: enough: %d\n", __func__, max_enough);
+ info->container_enough = max_enough;
if (super->disks) {
__u32 reserved = imsm_reserved_sectors(super, super->disks);
}
+/* allocates memory and fills disk in mdinfo structure
+ * for each disk in array */
+struct mdinfo *getinfo_super_disks_imsm(struct supertype *st)
+{
+ struct mdinfo *mddev = NULL;
+ struct intel_super *super = st->sb;
+ struct imsm_disk *disk;
+ int count = 0;
+ struct dl *dl;
+ if (!super || !super->disks)
+ return NULL;
+ dl = super->disks;
+ mddev = malloc(sizeof(*mddev));
+ if (!mddev) {
+ fprintf(stderr, Name ": Failed to allocate memory.\n");
+ return NULL;
+ }
+ memset(mddev, 0, sizeof(*mddev));
+ while (dl) {
+ struct mdinfo *tmp;
+ disk = &dl->disk;
+ tmp = malloc(sizeof(*tmp));
+ if (!tmp) {
+ fprintf(stderr, Name ": Failed to allocate memory.\n");
+ if (mddev)
+ sysfs_free(mddev);
+ return NULL;
+ }
+ memset(tmp, 0, sizeof(*tmp));
+ if (mddev->devs)
+ tmp->next = mddev->devs;
+ mddev->devs = tmp;
+ tmp->disk.number = count++;
+ tmp->disk.major = dl->major;
+ tmp->disk.minor = dl->minor;
+ tmp->disk.state = is_configured(disk) ?
+ (1 << MD_DISK_ACTIVE) : 0;
+ tmp->disk.state |= is_failed(disk) ? (1 << MD_DISK_FAULTY) : 0;
+ tmp->disk.state |= is_spare(disk) ? 0 : (1 << MD_DISK_SYNC);
+ tmp->disk.raid_disk = -1;
+ dl = dl->next;
+ }
+ return mddev;
+}
+
static int update_super_imsm(struct supertype *st, struct mdinfo *info,
char *update, char *devname, int verbose,
int uuid_set, char *homehost)
}
static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
- char *devname, int keep_fd)
+ char *devname)
{
struct mdinfo *sra;
struct intel_super *super_list = NULL;
err = 2;
sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
- dfd = dev_open(nm, keep_fd ? O_RDWR : O_RDONLY);
+ dfd = dev_open(nm, O_RDWR);
if (dfd < 0)
goto error;
- err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
+ err = load_and_parse_mpb(dfd, s, NULL, 1);
/* retry the load if we might have raced against mdmon */
if (err == 3 && mdmon_running(devnum))
for (retry = 0; retry < 3; retry++) {
usleep(3000);
- err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
+ err = load_and_parse_mpb(dfd, s, NULL, 1);
if (err != 3)
break;
}
- if (!keep_fd)
- close(dfd);
if (err)
goto error;
}
err = 2;
goto error;
}
-
- if (st->subarray[0]) {
- unsigned long val;
- char *ep;
-
- err = 1;
- val = strtoul(st->subarray, &ep, 10);
- if (*ep != '\0') {
- free_imsm(super);
- goto error;
- }
-
- if (val < super->anchor->num_raid_devs)
- super->current_vol = val;
- else {
- free_imsm(super);
- goto error;
- }
- }
err = 0;
error:
st->minor_version = 0;
st->max_devs = IMSM_MAX_DEVICES;
}
- st->loaded_container = 1;
-
return 0;
}
+
+static int load_container_imsm(struct supertype *st, int fd, char *devname)
+{
+ return load_super_imsm_all(st, fd, &st->sb, devname);
+}
#endif
static int load_super_imsm(struct supertype *st, int fd, char *devname)
int rv;
#ifndef MDASSEMBLE
- if (load_super_imsm_all(st, fd, &st->sb, devname, 1) == 0)
+ if (load_super_imsm_all(st, fd, &st->sb, devname) == 0)
return 0;
#endif
return rv;
}
- if (st->subarray[0]) {
- unsigned long val;
- char *ep;
-
- val = strtoul(st->subarray, &ep, 10);
- if (*ep != '\0') {
- free_imsm(super);
- return 1;
- }
-
- if (val < super->anchor->num_raid_devs)
- super->current_vol = val;
- else {
- free_imsm(super);
- return 1;
- }
- }
-
st->sb = super;
if (st->ss == NULL) {
st->ss = &super_imsm;
st->minor_version = 0;
st->max_devs = IMSM_MAX_DEVICES;
}
- st->loaded_container = 0;
-
return 0;
}
if (!check_name(super, name, 0))
return 0;
- sprintf(st->subarray, "%d", idx);
dv = malloc(sizeof(*dv));
if (!dv) {
fprintf(stderr, Name ": failed to allocate device list entry\n");
*/
struct intel_super *super;
- if (load_super_imsm_all(st, cfd, (void **) &super, NULL, 1) == 0) {
+ if (load_super_imsm_all(st, cfd, (void **) &super, NULL) == 0) {
st->sb = super;
st->container_dev = fd2devnum(cfd);
close(cfd);
return 0;
}
-static int update_subarray_imsm(struct supertype *st, char *update, mddev_ident_t ident)
+static int update_subarray_imsm(struct supertype *st, char *subarray,
+ char *update, struct mddev_ident *ident)
{
/* update the subarray currently referenced by ->current_vol */
struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor;
- if (super->current_vol < 0)
- return 2;
-
if (strcmp(update, "name") == 0) {
char *name = ident->name;
+ char *ep;
+ int vol;
- if (is_subarray_active(st->subarray, st->devname)) {
+ if (is_subarray_active(subarray, st->devname)) {
fprintf(stderr,
Name ": Unable to update name of active subarray\n");
return 2;
if (!check_name(super, name, 0))
return 2;
+ vol = strtoul(subarray, &ep, 10);
+ if (*ep != '\0' || vol >= super->anchor->num_raid_devs)
+ return 2;
+
if (st->update_tail) {
struct imsm_update_rename_array *u = malloc(sizeof(*u));
if (!u)
return 2;
u->type = update_rename_array;
- u->dev_idx = super->current_vol;
+ u->dev_idx = vol;
snprintf((char *) u->name, MAX_RAID_SERIAL_LEN, "%s", name);
append_metadata_update(st, u, sizeof(*u));
} else {
struct imsm_dev *dev;
int i;
- dev = get_imsm_dev(super, super->current_vol);
+ dev = get_imsm_dev(super, vol);
snprintf((char *) dev->volume, MAX_RAID_SERIAL_LEN, "%s", name);
for (i = 0; i < mpb->num_raid_devs; i++) {
dev = get_imsm_dev(super, i);
}
-static struct mdinfo *container_content_imsm(struct supertype *st)
+static struct mdinfo *container_content_imsm(struct supertype *st, char *subarray)
{
/* Given a container loaded by load_super_imsm_all,
* extract information about all the arrays into
* an mdinfo tree.
+ * If 'subarray' is given, just extract info about that array.
*
* For each imsm_dev create an mdinfo, fill it in,
* then look for matching devices in super->disks
struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor;
struct mdinfo *rest = NULL;
- int i;
+ unsigned int i;
/* do not assemble arrays that might have bad blocks */
if (imsm_bbm_log_size(super->anchor)) {
}
for (i = 0; i < mpb->num_raid_devs; i++) {
- struct imsm_dev *dev = get_imsm_dev(super, i);
- struct imsm_map *map = get_imsm_map(dev, 0);
+ struct imsm_dev *dev;
+ struct imsm_map *map;
struct mdinfo *this;
int slot;
+ char *ep;
+
+ if (subarray &&
+ (i != strtoul(subarray, &ep, 10) || *ep != '\0'))
+ continue;
+
+ dev = get_imsm_dev(super, i);
+ map = get_imsm_map(dev, 0);
/* do not publish arrays that are in the middle of an
* unsupported migration
}
#endif /* MDASSEMBLE */
+static char disk_by_path[] = "/dev/disk/by-path/";
+
+static const char *imsm_get_disk_controller_domain(const char *path)
+{
+ struct sys_dev *list, *hba = NULL;
+ char disk_path[PATH_MAX];
+ int ahci = 0;
+ char *dpath = NULL;
+
+ list = find_driver_devices("pci", "ahci");
+ for (hba = list; hba; hba = hba->next)
+ if (devpath_to_vendor(hba->path) == 0x8086)
+ break;
+
+ if (hba) {
+ struct stat st;
+
+ strncpy(disk_path, disk_by_path, PATH_MAX - 1);
+ strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1);
+ if (stat(disk_path, &st) == 0) {
+ dpath = devt_to_devpath(st.st_rdev);
+ if (dpath)
+ ahci = path_attached_to_hba(dpath, hba->path);
+ }
+ }
+ dprintf("path: %s(%s) hba: %s attached: %d\n",
+ path, dpath, (hba) ? hba->path : "NULL", ahci);
+ free_sys_dev(&list);
+ if (ahci)
+ return "ahci";
+ else
+ return NULL;
+}
+
+
struct superswitch super_imsm = {
#ifndef MDASSEMBLE
.examine_super = examine_super_imsm,
.detail_platform = detail_platform_imsm,
.kill_subarray = kill_subarray_imsm,
.update_subarray = update_subarray_imsm,
+ .load_container = load_container_imsm,
#endif
.match_home = match_home_imsm,
.uuid_from_super= uuid_from_super_imsm,
.getinfo_super = getinfo_super_imsm,
+ .getinfo_super_disks = getinfo_super_disks_imsm,
.update_super = update_super_imsm,
.avail_size = avail_size_imsm,
+ .min_acceptable_spare_size = min_acceptable_spare_size_imsm,
.compare_super = compare_super_imsm,
.match_metadata_desc = match_metadata_desc_imsm,
.container_content = container_content_imsm,
.default_layout = imsm_level_to_layout,
+ .get_disk_controller_domain = imsm_get_disk_controller_domain,
.external = 1,
.name = "imsm",