};
ASSERT_SIZE(migr_record, 128)
+/**
+ * enum imsm_status - internal IMSM return values representation.
+ * @STATUS_OK: function succeeded.
+ * @STATUS_ERROR: General error ocurred (not specified).
+ *
+ * Typedefed to imsm_status_t.
+ */
+typedef enum imsm_status {
+ IMSM_STATUS_ERROR = -1,
+ IMSM_STATUS_OK = 0,
+} imsm_status_t;
+
struct md_list {
/* usage marker:
* 1: load metadata
if ((list = find_intel_devices()) == NULL)
return 0;
- if (fd < 0)
+ if (!is_fd_valid(fd))
disk_path = (char *) devname;
else
disk_path = diskfd_to_devpath(fd, 1, NULL);
return inf;
}
+/**
+ * __get_imsm_dev() - Get device with index from imsm_super.
+ * @mpb: &imsm_super pointer, not NULL.
+ * @index: Device index.
+ *
+ * Function works as non-NULL, aborting in such a case,
+ * when NULL would be returned.
+ *
+ * Device index should be in range 0 up to num_raid_devs.
+ * Function assumes the index was already verified.
+ * Index must be valid, otherwise abort() is called.
+ *
+ * Return: Pointer to corresponding imsm_dev.
+ *
+ */
static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index)
{
int offset;
void *_mpb = mpb;
if (index >= mpb->num_raid_devs)
- return NULL;
+ goto error;
/* devices start after all disks */
offset = ((void *) &mpb->disk[mpb->num_disks]) - _mpb;
- for (i = 0; i <= index; i++)
+ for (i = 0; i <= index; i++, offset += sizeof_imsm_dev(_mpb + offset, 0))
if (i == index)
return _mpb + offset;
- else
- offset += sizeof_imsm_dev(_mpb + offset, 0);
-
- return NULL;
+error:
+ pr_err("cannot find imsm_dev with index %u in imsm_super\n", index);
+ abort();
}
+/**
+ * get_imsm_dev() - Get device with index from intel_super.
+ * @super: &intel_super pointer, not NULL.
+ * @index: Device index.
+ *
+ * Function works as non-NULL, aborting in such a case,
+ * when NULL would be returned.
+ *
+ * Device index should be in range 0 up to num_raid_devs.
+ * Function assumes the index was already verified.
+ * Index must be valid, otherwise abort() is called.
+ *
+ * Return: Pointer to corresponding imsm_dev.
+ *
+ */
static struct imsm_dev *get_imsm_dev(struct intel_super *super, __u8 index)
{
struct intel_dev *dv;
if (index >= super->anchor->num_raid_devs)
- return NULL;
+ goto error;
+
for (dv = super->devlist; dv; dv = dv->next)
if (dv->index == index)
return dv->dev;
- return NULL;
+error:
+ pr_err("cannot find imsm_dev with index %u in intel_super\n", index);
+ abort();
}
static inline unsigned long long __le48_to_cpu(const struct bbm_log_block_addr
map->disk_ord_tbl[slot] = __cpu_to_le32(ord);
}
-static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx)
+static int get_imsm_disk_slot(struct imsm_map *map, const unsigned int idx)
{
int slot;
__u32 ord;
return slot;
}
- return -1;
+ return IMSM_STATUS_ERROR;
}
static int get_imsm_raid_level(struct imsm_map *map)
return map->raid_level;
}
+/**
+ * get_disk_slot_in_dev() - retrieve disk slot from &imsm_dev.
+ * @super: &intel_super pointer, not NULL.
+ * @dev_idx: imsm device index.
+ * @idx: disk index.
+ *
+ * Return: Slot on success, IMSM_STATUS_ERROR otherwise.
+ */
+static int get_disk_slot_in_dev(struct intel_super *super, const __u8 dev_idx,
+ const unsigned int idx)
+{
+ struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+
+ return get_imsm_disk_slot(map, idx);
+}
+
static int cmp_extent(const void *av, const void *bv)
{
const struct extent *a = av;
int memberships = 0;
int i;
- for (i = 0; i < super->anchor->num_raid_devs; i++) {
- struct imsm_dev *dev = get_imsm_dev(super, i);
- struct imsm_map *map = get_imsm_map(dev, MAP_0);
-
- if (get_imsm_disk_slot(map, dl->index) >= 0)
+ for (i = 0; i < super->anchor->num_raid_devs; i++)
+ if (get_disk_slot_in_dev(super, i, dl->index) >= 0)
memberships++;
- }
return memberships;
}
return join_u32(disk->total_blocks_lo, disk->total_blocks_hi);
}
+/**
+ * imsm_num_data_members() - get data drives count for an array.
+ * @map: Map to analyze.
+ *
+ * num_data_members value represents minimal count of drives for level.
+ * The name of the property could be misleading for RAID5 with asymmetric layout
+ * because some data required to be calculated from parity.
+ * The property is extracted from level and num_members value.
+ *
+ * Return: num_data_members value on success, zero otherwise.
+ */
+static __u8 imsm_num_data_members(struct imsm_map *map)
+{
+ switch (get_imsm_raid_level(map)) {
+ case 0:
+ return map->num_members;
+ case 1:
+ case 10:
+ return map->num_members / 2;
+ case 5:
+ return map->num_members - 1;
+ default:
+ dprintf("unsupported raid level\n");
+ return 0;
+ }
+}
+
static unsigned long long pba_of_lba0(struct imsm_map *map)
{
if (map == NULL)
split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
}
+/**
+ * set_num_domains() - Set number of domains for an array.
+ * @map: Map to be updated.
+ *
+ * num_domains property represents copies count of each data drive, thus make
+ * it meaningful only for RAID1 and RAID10. IMSM supports two domains for
+ * raid1 and raid10.
+ */
+static void set_num_domains(struct imsm_map *map)
+{
+ int level = get_imsm_raid_level(map);
+
+ if (level == 1 || level == 10)
+ map->num_domains = 2;
+ else
+ map->num_domains = 1;
+}
+
static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n)
{
split_ull(n, &map->pba_of_lba0_lo, &map->pba_of_lba0_hi);
split_ull(n, &map->num_data_stripes_lo, &map->num_data_stripes_hi);
}
+/**
+ * update_num_data_stripes() - Calculate and update num_data_stripes value.
+ * @map: map to be updated.
+ * @dev_size: size of volume.
+ *
+ * num_data_stripes value is addictionally divided by num_domains, therefore for
+ * levels where num_domains is not 1, nds is a part of real value.
+ */
+static void update_num_data_stripes(struct imsm_map *map,
+ unsigned long long dev_size)
+{
+ unsigned long long nds = dev_size / imsm_num_data_members(map);
+
+ nds /= map->num_domains;
+ nds /= map->blocks_per_strip;
+ set_num_data_stripes(map, nds);
+}
+
static void set_vol_curr_migr_unit(struct imsm_dev *dev, unsigned long long n)
{
if (dev == NULL)
return 0;
}
-static int is_gen_migration(struct imsm_dev *dev);
+static bool is_gen_migration(struct imsm_dev *dev);
#define IMSM_4K_DIV 8
struct imsm_map *map;
int slot = -1;
- if (is_gen_migration(dev) == 0)
+ if (is_gen_migration(dev) == false)
continue;
printf("\nMigration Record Information:");
/* first map under migration */
map = get_imsm_map(dev, MAP_0);
+
if (map)
slot = get_imsm_disk_slot(map, super->disks->index);
if (map == NULL || slot > 1 || slot < 0) {
}
fd = dev_open(ent->d_name, O_RDONLY);
- if (fd < 0)
+ if (!is_fd_valid(fd))
printf(" Port%d : - disk info unavailable -\n", port);
else {
fd2devname(fd, buf);
goto skip;
fd = open_dev(ent->d_name);
- if (fd < 0)
+ if (!is_fd_valid(fd))
goto skip;
if (!diskfd_to_devpath(fd, 0, ns_path) ||
printf("()\n");
skip:
- if (fd > -1)
- close(fd);
+ close_fd(&fd);
}
closedir(dir);
return num_stripes_per_unit_resync(dev);
}
-static __u8 imsm_num_data_members(struct imsm_map *map)
-{
- /* named 'imsm_' because raid0, raid1 and raid10
- * counter-intuitively have the same number of data disks
- */
- switch (get_imsm_raid_level(map)) {
- case 0:
- return map->num_members;
- break;
- case 1:
- case 10:
- return map->num_members/2;
- case 5:
- return map->num_members - 1;
- default:
- dprintf("unsupported raid level\n");
- return 0;
- }
-}
-
static unsigned long long calc_component_size(struct imsm_map *map,
struct imsm_dev *dev)
{
if (slot > 1 || slot < 0)
continue;
- if (dl->fd < 0) {
+ if (!is_fd_valid(dl->fd)) {
sprintf(nm, "%d:%d", dl->major, dl->minor);
fd = dev_open(nm, O_RDONLY);
- if (fd >= 0) {
+
+ if (is_fd_valid(fd)) {
keep_fd = 0;
break;
}
}
}
- if (fd < 0)
+ if (!is_fd_valid(fd))
return retval;
retval = read_imsm_migr_rec(fd, super);
if (!keep_fd)
info->recovery_blocked = imsm_reshape_blocks_arrays_changes(st->sb);
if (is_gen_migration(dev)) {
+ /*
+ * device prev_map should be added if it is in the middle
+ * of migration
+ */
+ assert(prev_map);
+
info->reshape_active = 1;
info->new_level = get_imsm_raid_level(map);
info->new_layout = imsm_level_to_layout(info->new_level);
}
static int update_super_imsm(struct supertype *st, struct mdinfo *info,
- char *update, char *devname, int verbose,
- int uuid_set, char *homehost)
+ enum update_opt update, char *devname,
+ int verbose, int uuid_set, char *homehost)
{
/* For 'assemble' and 'force' we need to return non-zero if any
* change was made. For others, the return value is ignored.
mpb = super->anchor;
- if (strcmp(update, "uuid") == 0) {
+ switch (update) {
+ case UOPT_UUID:
/* We take this to mean that the family_num should be updated.
* However that is much smaller than the uuid so we cannot really
* allow an explicit uuid to be given. And it is hard to reliably
}
if (rv == 0)
mpb->orig_family_num = info->uuid[0];
- } else if (strcmp(update, "assemble") == 0)
+ break;
+ case UOPT_SPEC_ASSEMBLE:
rv = 0;
- else
+ break;
+ default:
rv = -1;
+ break;
+ }
/* successful update? recompute checksum */
if (rv == 0)
*
* FIXME add support for raid-level-migration
*/
- if (map_state != map->map_state && (is_gen_migration(dev) == 0) &&
+ if (map_state != map->map_state && (is_gen_migration(dev) == false) &&
prev->map_state != IMSM_T_STATE_UNINITIALIZED) {
/* when final map state is other than expected
* merge maps (not for migration)
for (i = 0; i < super->anchor->num_raid_devs; i++) {
struct imsm_dev *dev_iter = __get_imsm_dev(super->anchor, i);
- if (dev_iter &&
- dev_iter->vol.migr_state == 1 &&
+ if (dev_iter->vol.migr_state == 1 &&
dev_iter->vol.migr_type == MIGR_GEN_MIGR) {
/* This device is migrating */
map0 = get_imsm_map(dev_iter, MAP_0);
}
for (i = 0; i < mpb->num_raid_devs; ++i) {
struct imsm_dev *dev = get_imsm_dev(super, i);
- if (!dev)
- return;
for (n = 0; n < 2; ++n) {
struct imsm_map *map = get_imsm_map(dev, n);
if (!map)
return err;
}
-static void __free_imsm_disk(struct dl *d, int close_fd)
+static void __free_imsm_disk(struct dl *d, int do_close)
{
- if (close_fd && d->fd > -1)
- close(d->fd);
+ if (do_close)
+ close_fd(&d->fd);
if (d->devname)
free(d->devname);
if (d->e)
struct sys_dev *hba_name;
int rv = 0;
- if (fd >= 0 && test_partition(fd)) {
+ if (is_fd_valid(fd) && test_partition(fd)) {
pr_err("imsm: %s is a partition, cannot be used in IMSM\n",
devname);
return 1;
}
- if (fd < 0 || check_env("IMSM_NO_PLATFORM")) {
+ if (!is_fd_valid(fd) || check_env("IMSM_NO_PLATFORM")) {
super->orom = NULL;
super->hba = NULL;
return 0;
int err = 0;
int i = 0;
- if (fd >= 0)
+ if (is_fd_valid(fd))
/* 'fd' is an opened container */
err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd);
else
return err;
*sbp = super;
- if (fd >= 0)
+ if (is_fd_valid(fd))
strcpy(st->container_devnm, fd2devnm(fd));
else
st->container_devnm[0] = 0;
if (tmpdev->container == 1) {
int lmax = 0;
int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL);
- if (fd < 0) {
+ if (!is_fd_valid(fd)) {
pr_err("cannot open device %s: %s\n",
tmpdev->devname, strerror(errno));
err = 8;
sprintf(nm, "%d:%d", major, minor);
dfd = dev_open(nm, O_RDWR);
- if (dfd < 0) {
+ if (!is_fd_valid(dfd)) {
err = 2;
goto error;
}
/* retry the load if we might have raced against mdmon */
if (err == 3 && devnm && mdmon_running(devnm))
for (retry = 0; retry < 3; retry++) {
- usleep(3000);
+ sleep_for(0, MSEC_TO_NSEC(3), true);
err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
if (err != 3)
break;
} else {
if (s)
free_imsm(s);
- if (dfd >= 0)
- close(dfd);
+ close_fd(&dfd);
}
- if (dfd >= 0 && !keep_fd)
- close(dfd);
+ if (!keep_fd)
+ close_fd(&dfd);
return err;
}
if (mdstat && mdmon_running(mdstat->devnm) && getpid() != mdmon_pid(mdstat->devnm)) {
for (retry = 0; retry < 3; retry++) {
- usleep(3000);
+ sleep_for(0, MSEC_TO_NSEC(3), true);
rv = load_and_parse_mpb(fd, super, devname, 0);
if (rv != 3)
break;
int namelen;
unsigned long long array_blocks;
size_t size_old, size_new;
- unsigned long long num_data_stripes;
unsigned int data_disks;
unsigned long long size_per_member;
}
map->raid_level = info->level;
- if (info->level == 10) {
+ if (info->level == 10)
map->raid_level = 1;
- map->num_domains = info->raid_disks / 2;
- } else if (info->level == 1)
- map->num_domains = info->raid_disks;
- else
- map->num_domains = 1;
-
- /* info->size is only int so use the 'size' parameter instead */
- num_data_stripes = size_per_member / info_to_blocks_per_strip(info);
- num_data_stripes /= map->num_domains;
- set_num_data_stripes(map, num_data_stripes);
+ set_num_domains(map);
size_per_member += NUM_BLOCKS_DIRTY_STRIPE_REGION;
set_blocks_per_member(map, info_to_blocks_per_member(info,
BLOCKS_PER_KB));
map->num_members = info->raid_disks;
+ update_num_data_stripes(map, array_blocks);
for (i = 0; i < map->num_members; i++) {
/* initialized in add_to_super */
set_imsm_ord_tbl_ent(map, i, IMSM_ORD_REBUILD);
free(dev);
free(dv);
pr_err("imsm does not support consistency policy %s\n",
- map_num(consistency_policies, s->consistency_policy));
+ map_num_s(consistency_policies, s->consistency_policy));
return 0;
}
{
unsigned int member_sector_size;
- if (dl->fd < 0) {
+ if (!is_fd_valid(dl->fd)) {
pr_err("Invalid file descriptor for %s\n", dl->devname);
return 0;
}
struct imsm_map *map;
struct dl *dl, *df;
int slot;
+ int autolayout = 0;
+
+ if (!is_fd_valid(fd))
+ autolayout = 1;
dev = get_imsm_dev(super, super->current_vol);
map = get_imsm_map(dev, MAP_0);
return 1;
}
- if (fd == -1) {
- /* we're doing autolayout so grab the pre-marked (in
- * validate_geometry) raid_disk
- */
- for (dl = super->disks; dl; dl = dl->next)
+ for (dl = super->disks; dl ; dl = dl->next) {
+ if (autolayout) {
if (dl->raiddisk == dk->raid_disk)
break;
- } else {
- for (dl = super->disks; dl ; dl = dl->next)
- if (dl->major == dk->major &&
- dl->minor == dk->minor)
- break;
+ } else if (dl->major == dk->major && dl->minor == dk->minor)
+ break;
}
if (!dl) {
- pr_err("%s is not a member of the same container\n", devname);
+ if (!autolayout)
+ pr_err("%s is not a member of the same container.\n",
+ devname);
return 1;
}
+ if (!autolayout && super->current_vol > 0) {
+ int _slot = get_disk_slot_in_dev(super, 0, dl->index);
+
+ if (_slot != dk->raid_disk) {
+ pr_err("Member %s is in %d slot for the first volume, but is in %d slot for a new volume.\n",
+ dl->devname, _slot, dk->raid_disk);
+ pr_err("Raid members are in different order than for the first volume, aborting.\n");
+ return 1;
+ }
+ }
+
if (mpb->num_disks == 0)
if (!get_dev_sector_size(dl->fd, dl->devname,
&super->sector_size))
struct imsm_dev *_dev = __get_imsm_dev(mpb, 0);
_disk = __get_imsm_disk(mpb, dl->index);
- if (!_dev || !_disk) {
+ if (!_disk) {
pr_err("BUG mpb setup error\n");
return 1;
}
if (write_super_imsm_spare(super, d))
return 1;
- if (doclose) {
- close(d->fd);
- d->fd = -1;
- }
+ if (doclose)
+ close_fd(&d->fd);
}
return 0;
for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = __get_imsm_dev(mpb, i);
struct imsm_dev *dev2 = get_imsm_dev(super, i);
- if (dev && dev2) {
- imsm_copy_dev(dev, dev2);
- mpb_size += sizeof_imsm_dev(dev, 0);
- }
+
+ imsm_copy_dev(dev, dev2);
+ mpb_size += sizeof_imsm_dev(dev, 0);
+
if (is_gen_migration(dev2))
clear_migration_record = 0;
}
d->major, d->minor,
d->fd, strerror(errno));
- if (doclose) {
- close(d->fd);
- d->fd = -1;
- }
+ if (doclose)
+ close_fd(&d->fd);
}
if (spares)
if (mdmon_running(st->container_devnm))
st->update_tail = &st->updates;
- if (st->ss->update_subarray(st, subarray, "ppl", NULL)) {
+ if (st->ss->update_subarray(st, subarray, UOPT_PPL, NULL)) {
pr_err("Failed to update subarray %s\n",
subarray);
} else {
struct intel_super *super = NULL;
int rv = 0;
- if (level != LEVEL_CONTAINER)
+ if (!is_container(level))
return 0;
if (!dev)
return 1;
fd = dev_open(dev, O_RDONLY|O_EXCL);
- if (fd < 0) {
- if (verbose > 0)
- pr_err("imsm: Cannot open %s: %s\n",
- dev, strerror(errno));
+ if (!is_fd_valid(fd)) {
+ pr_vrb("imsm: Cannot open %s: %s\n", dev, strerror(errno));
return 0;
}
if (!get_dev_size(fd, dev, &ldsize))
memb->members) {
struct dev_member *dev = memb->members;
int fd = -1;
- while(dev && (fd < 0)) {
+ while (dev && !is_fd_valid(fd)) {
char *path = xmalloc(strlen(dev->name) + strlen("/dev/") + 1);
num = sprintf(path, "%s%s", "/dev/", dev->name);
if (num > 0)
fd = open(path, O_RDONLY, 0);
- if (num <= 0 || fd < 0) {
+ if (num <= 0 || !is_fd_valid(fd)) {
pr_vrb("Cannot open %s: %s\n",
dev->name, strerror(errno));
}
dev = dev->next;
}
found = 0;
- if (fd >= 0 && disk_attached_to_hba(fd, hba)) {
+ if (is_fd_valid(fd) && disk_attached_to_hba(fd, hba)) {
struct mdstat_ent *vol;
for (vol = mdstat ; vol ; vol = vol->next) {
if (vol->active > 0 &&
*devlist = dv;
}
}
- if (fd >= 0)
- close(fd);
+ close_fd(&fd);
}
}
free_mdstat(mdstat);
free(path);
path = NULL;
fd = dev_open(ent->d_name, O_RDONLY);
- if (fd >= 0) {
+ if (is_fd_valid(fd)) {
fd2devname(fd, buf);
close(fd);
} else {
}
tmpdev->container = 0;
dfd = dev_open(devname, O_RDONLY|O_EXCL);
- if (dfd < 0) {
+ if (!is_fd_valid(dfd)) {
dprintf("cannot open device %s: %s\n",
devname, strerror(errno));
tmpdev->used = 2;
tmpdev->used = 2;
}
}
- if (dfd >= 0)
- close(dfd);
+ close_fd(&dfd);
+
if (tmpdev->used == 2 || tmpdev->used == 4) {
/* Ignore unrecognised devices during auto-assembly */
goto loop;
return 1;
}
-static int imsm_get_free_size(struct supertype *st, int raiddisks,
- unsigned long long size, int chunk,
- unsigned long long *freesize)
+/**
+ * imsm_get_free_size() - get the biggest, common free space from members.
+ * @super: &intel_super pointer, not NULL.
+ * @raiddisks: number of raid disks.
+ * @size: requested size, could be 0 (means max size).
+ * @chunk: requested chunk.
+ * @freesize: pointer for returned size value.
+ *
+ * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR.
+ *
+ * @freesize is set to meaningful value, this can be @size, or calculated
+ * max free size.
+ * super->create_offset value is modified and set appropriately in
+ * merge_extends() for further creation.
+ */
+static imsm_status_t imsm_get_free_size(struct intel_super *super,
+ const int raiddisks,
+ unsigned long long size,
+ const int chunk,
+ unsigned long long *freesize)
{
- struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor;
struct dl *dl;
int i;
/* chunk is in K */
minsize = chunk * 2;
- if (cnt < raiddisks ||
- (super->orom && used && used != raiddisks) ||
- maxsize < minsize ||
- maxsize == 0) {
+ if (cnt < raiddisks || (super->orom && used && used != raiddisks) ||
+ maxsize < minsize || maxsize == 0) {
pr_err("not enough devices with space to create array.\n");
- return 0; /* No enough free spaces large enough */
+ return IMSM_STATUS_ERROR;
}
if (size == 0) {
}
if (mpb->num_raid_devs > 0 && size && size != maxsize)
pr_err("attempting to create a second volume with size less then remaining space.\n");
- cnt = 0;
- for (dl = super->disks; dl; dl = dl->next)
- if (dl->e)
- dl->raiddisk = cnt++;
-
*freesize = size;
dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
- return 1;
+ return IMSM_STATUS_OK;
}
-static int reserve_space(struct supertype *st, int raiddisks,
- unsigned long long size, int chunk,
- unsigned long long *freesize)
+/**
+ * autolayout_imsm() - automatically layout a new volume.
+ * @super: &intel_super pointer, not NULL.
+ * @raiddisks: number of raid disks.
+ * @size: requested size, could be 0 (means max size).
+ * @chunk: requested chunk.
+ * @freesize: pointer for returned size value.
+ *
+ * We are being asked to automatically layout a new volume based on the current
+ * contents of the container. If the parameters can be satisfied autolayout_imsm
+ * will record the disks, start offset, and will return size of the volume to
+ * be created. See imsm_get_free_size() for details.
+ * add_to_super() and getinfo_super() detect when autolayout is in progress.
+ * If first volume exists, slots are set consistently to it.
+ *
+ * Return: &IMSM_STATUS_OK on success, &IMSM_STATUS_ERROR otherwise.
+ *
+ * Disks are marked for creation via dl->raiddisk.
+ */
+static imsm_status_t autolayout_imsm(struct intel_super *super,
+ const int raiddisks,
+ unsigned long long size, const int chunk,
+ unsigned long long *freesize)
{
- struct intel_super *super = st->sb;
- struct dl *dl;
- int cnt;
- int rv = 0;
+ int curr_slot = 0;
+ struct dl *disk;
+ int vol_cnt = super->anchor->num_raid_devs;
+ imsm_status_t rv;
- rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
- if (rv) {
- cnt = 0;
- for (dl = super->disks; dl; dl = dl->next)
- if (dl->e)
- dl->raiddisk = cnt++;
- rv = 1;
+ rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize);
+ if (rv != IMSM_STATUS_OK)
+ return IMSM_STATUS_ERROR;
+
+ for (disk = super->disks; disk; disk = disk->next) {
+ if (!disk->e)
+ continue;
+
+ if (curr_slot == raiddisks)
+ break;
+
+ if (vol_cnt == 0) {
+ disk->raiddisk = curr_slot;
+ } else {
+ int _slot = get_disk_slot_in_dev(super, 0, disk->index);
+
+ if (_slot == -1) {
+ pr_err("Disk %s is not used in first volume, aborting\n",
+ disk->devname);
+ return IMSM_STATUS_ERROR;
+ }
+ disk->raiddisk = _slot;
+ }
+ curr_slot++;
}
- return rv;
+ return IMSM_STATUS_OK;
}
static int validate_geometry_imsm(struct supertype *st, int level, int layout,
* if given unused devices create a container
* if given given devices in a container create a member volume
*/
- if (level == LEVEL_CONTAINER)
+ if (is_container(level))
/* Must be a fresh device to add to a container */
return validate_geometry_imsm_container(st, level, raiddisks,
data_offset, dev,
}
if (!dev) {
- if (st->sb) {
- struct intel_super *super = st->sb;
- if (!validate_geometry_imsm_orom(st->sb, level, layout,
- raiddisks, chunk, size,
- verbose))
+ struct intel_super *super = st->sb;
+
+ /*
+ * Autolayout mode, st->sb and freesize must be set.
+ */
+ if (!super || !freesize) {
+ pr_vrb("freesize and superblock must be set for autolayout, aborting\n");
+ return 1;
+ }
+
+ if (!validate_geometry_imsm_orom(st->sb, level, layout,
+ raiddisks, chunk, size,
+ verbose))
+ return 0;
+
+ if (super->orom) {
+ imsm_status_t rv;
+ int count = count_volumes(super->hba, super->orom->dpa,
+ verbose);
+ if (super->orom->vphba <= count) {
+ pr_vrb("platform does not support more than %d raid volumes.\n",
+ super->orom->vphba);
return 0;
- /* we are being asked to automatically layout a
- * new volume based on the current contents of
- * the container. If the the parameters can be
- * satisfied reserve_space will record the disks,
- * start offset, and size of the volume to be
- * created. add_to_super and getinfo_super
- * detect when autolayout is in progress.
- */
- /* assuming that freesize is always given when array is
- created */
- if (super->orom && freesize) {
- int count;
- count = count_volumes(super->hba,
- super->orom->dpa, verbose);
- if (super->orom->vphba <= count) {
- pr_vrb("platform does not support more than %d raid volumes.\n",
- super->orom->vphba);
- return 0;
- }
}
- if (freesize)
- return reserve_space(st, raiddisks, size,
- *chunk, freesize);
+
+ rv = autolayout_imsm(super, raiddisks, size, *chunk,
+ freesize);
+ if (rv != IMSM_STATUS_OK)
+ return 0;
}
return 1;
}
/* This device needs to be a device in an 'imsm' container */
fd = open(dev, O_RDONLY|O_EXCL, 0);
- if (fd >= 0) {
- if (verbose)
- pr_err("Cannot create this array on device %s\n",
- dev);
+
+ if (is_fd_valid(fd)) {
+ pr_vrb("Cannot create this array on device %s\n", dev);
close(fd);
return 0;
}
- if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) {
- if (verbose)
- pr_err("Cannot open %s: %s\n",
- dev, strerror(errno));
+ if (errno == EBUSY)
+ fd = open(dev, O_RDONLY, 0);
+
+ if (!is_fd_valid(fd)) {
+ pr_vrb("Cannot open %s: %s\n", dev, strerror(errno));
return 0;
}
+
/* Well, it is in use by someone, maybe an 'imsm' container. */
cfd = open_container(fd);
- close(fd);
- if (cfd < 0) {
- if (verbose)
- pr_err("Cannot use %s: It is busy\n",
- dev);
+ close_fd(&fd);
+
+ if (!is_fd_valid(cfd)) {
+ pr_vrb("Cannot use %s: It is busy\n", dev);
return 0;
}
sra = sysfs_read(cfd, NULL, GET_VERSION);
return 0;
}
-static int get_rwh_policy_from_update(char *update)
+/**
+ * get_rwh_policy_from_update() - Get the rwh policy for update option.
+ * @update: Update option.
+ */
+static int get_rwh_policy_from_update(enum update_opt update)
{
- if (strcmp(update, "ppl") == 0)
+ switch (update) {
+ case UOPT_PPL:
return RWH_MULTIPLE_DISTRIBUTED;
- else if (strcmp(update, "no-ppl") == 0)
+ case UOPT_NO_PPL:
return RWH_MULTIPLE_OFF;
- else if (strcmp(update, "bitmap") == 0)
+ case UOPT_BITMAP:
return RWH_BITMAP;
- else if (strcmp(update, "no-bitmap") == 0)
+ case UOPT_NO_BITMAP:
return RWH_OFF;
- return -1;
+ default:
+ break;
+ }
+ return UOPT_UNDEFINED;
}
static int update_subarray_imsm(struct supertype *st, char *subarray,
- char *update, struct mddev_ident *ident)
+ enum update_opt 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 (strcmp(update, "name") == 0) {
+ if (update == UOPT_NAME) {
char *name = ident->name;
char *ep;
int vol;
- if (is_subarray_active(subarray, st->devnm)) {
- pr_err("Unable to update name of active subarray\n");
- return 2;
- }
-
if (!check_name(super, name, 0))
return 2;
}
super->updates_pending++;
}
- } else if (get_rwh_policy_from_update(update) != -1) {
+ } else if (get_rwh_policy_from_update(update) != UOPT_UNDEFINED) {
int new_policy;
char *ep;
int vol = strtoul(subarray, &ep, 10);
return 0;
}
-static int is_gen_migration(struct imsm_dev *dev)
+static bool is_gen_migration(struct imsm_dev *dev)
{
- if (dev == NULL)
- return 0;
-
- if (!dev->vol.migr_state)
- return 0;
-
- if (migr_type(dev) == MIGR_GEN_MIGR)
- return 1;
+ if (dev && dev->vol.migr_state &&
+ migr_type(dev) == MIGR_GEN_MIGR)
+ return true;
- return 0;
+ return false;
}
static int is_rebuilding(struct imsm_dev *dev)
if ((!able_to_resync(level, missing) ||
recovery_start == 0))
this->resync_start = MaxSector;
- } else {
- /*
- * FIXME handle dirty degraded
- */
}
if (skip)
}
static int imsm_open_new(struct supertype *c, struct active_array *a,
- char *inst)
+ int inst)
{
struct intel_super *super = c->sb;
struct imsm_super *mpb = super->anchor;
struct imsm_update_prealloc_bb_mem u;
- if (atoi(inst) >= mpb->num_raid_devs) {
- pr_err("subarry index %d, out of range\n", atoi(inst));
+ if (inst >= mpb->num_raid_devs) {
+ pr_err("subarry index %d, out of range\n", inst);
return -ENODEV;
}
- dprintf("imsm: open_new %s\n", inst);
- a->info.container_member = atoi(inst);
+ dprintf("imsm: open_new %d\n", inst);
+ a->info.container_member = inst;
u.type = update_prealloc_badblocks_mem;
imsm_update_metadata_locally(c, &u, sizeof(u));
dprintf("imsm: mark missing\n");
/* end process for initialization and rebuild only
*/
- if (is_gen_migration(dev) == 0) {
+ if (is_gen_migration(dev) == false) {
int failed = imsm_count_failed(super, dev, MAP_0);
if (failed) {
for (dl = super->disks; dl; dl = dl->next) {
/* If in this array, skip */
for (d = a->info.devs ; d ; d = d->next)
- if (d->state_fd >= 0 &&
+ if (is_fd_valid(d->state_fd) &&
d->disk.major == dl->major &&
d->disk.minor == dl->minor) {
dprintf("%x:%x already in array\n",
__u8 state;
dev2 = get_imsm_dev(cont->sb, dev_idx);
- if (dev2) {
- state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
- if (state == IMSM_T_STATE_FAILED) {
- map = get_imsm_map(dev2, MAP_0);
- if (!map)
- return 1;
- for (slot = 0; slot < map->num_members; slot++) {
- /*
- * Check if failed disks are deleted from intel
- * disk list or are marked to be deleted
- */
- idx = get_imsm_disk_idx(dev2, slot, MAP_X);
- idisk = get_imsm_dl_disk(cont->sb, idx);
- /*
- * Do not rebuild the array if failed disks
- * from failed sub-array are not removed from
- * container.
- */
- if (idisk &&
- is_failed(&idisk->disk) &&
- (idisk->action != DISK_REMOVE))
- return 0;
- }
+
+ state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
+ if (state == IMSM_T_STATE_FAILED) {
+ map = get_imsm_map(dev2, MAP_0);
+ for (slot = 0; slot < map->num_members; slot++) {
+ /*
+ * Check if failed disks are deleted from intel
+ * disk list or are marked to be deleted
+ */
+ idx = get_imsm_disk_idx(dev2, slot, MAP_X);
+ idisk = get_imsm_dl_disk(cont->sb, idx);
+ /*
+ * Do not rebuild the array if failed disks
+ * from failed sub-array are not removed from
+ * container.
+ */
+ if (idisk &&
+ is_failed(&idisk->disk) &&
+ (idisk->action != DISK_REMOVE))
+ return 0;
}
}
return 1;
int i;
int allowed;
- for (d = a->info.devs ; d ; d = d->next) {
- if ((d->curr_state & DS_FAULTY) &&
- d->state_fd >= 0)
+ for (d = a->info.devs ; d; d = d->next) {
+ if (!is_fd_valid(d->state_fd))
+ continue;
+
+ if (d->curr_state & DS_FAULTY)
/* wait for Removal to happen */
return NULL;
- if (d->state_fd >= 0)
- failed--;
+
+ failed--;
}
dprintf("imsm: activate spare: inst=%d failed=%d (%d) level=%d\n",
if (d->disk.raid_disk == i)
break;
dprintf("found %d: %p %x\n", i, d, d?d->curr_state:0);
- if (d && (d->state_fd >= 0))
+ if (d && is_fd_valid(d->state_fd))
continue;
/*
/* update chunk size
*/
if (u->new_chunksize > 0) {
- unsigned long long num_data_stripes;
struct imsm_map *dest_map =
get_imsm_map(dev, MAP_0);
int used_disks =
map->blocks_per_strip =
__cpu_to_le16(u->new_chunksize * 2);
- num_data_stripes =
- imsm_dev_size(dev) / used_disks;
- num_data_stripes /= map->blocks_per_strip;
- num_data_stripes /= map->num_domains;
- set_num_data_stripes(map, num_data_stripes);
+ update_num_data_stripes(map, imsm_dev_size(dev));
}
/* ensure blocks_per_member has valid value
struct imsm_map *map = get_imsm_map(dev, MAP_0);
int used_disks = imsm_num_data_members(map);
unsigned long long blocks_per_member;
- unsigned long long num_data_stripes;
unsigned long long new_size_per_disk;
if (used_disks == 0)
new_size_per_disk = u->new_size / used_disks;
blocks_per_member = new_size_per_disk +
NUM_BLOCKS_DIRTY_STRIPE_REGION;
- num_data_stripes = new_size_per_disk /
- map->blocks_per_strip;
- num_data_stripes /= map->num_domains;
- dprintf("(size: %llu, blocks per member: %llu, num_data_stipes: %llu)\n",
- u->new_size, new_size_per_disk,
- num_data_stripes);
- set_blocks_per_member(map, blocks_per_member);
- set_num_data_stripes(map, num_data_stripes);
- imsm_set_array_size(dev, u->new_size);
+ imsm_set_array_size(dev, u->new_size);
+ set_blocks_per_member(map, blocks_per_member);
+ update_num_data_stripes(map, u->new_size);
ret_val = 1;
break;
}
/* count arrays using the victim in the metadata */
found = 0;
for (a = active_array; a ; a = a->next) {
- dev = get_imsm_dev(super, a->info.container_member);
- map = get_imsm_map(dev, MAP_0);
+ int dev_idx = a->info.container_member;
- if (get_imsm_disk_slot(map, victim) >= 0)
+ if (get_disk_slot_in_dev(super, dev_idx, victim) >= 0)
found++;
}
map = get_imsm_map(dev, MAP_0);
if (u->direction == R10_TO_R0) {
- unsigned long long num_data_stripes;
-
/* Number of failed disks must be half of initial disk number */
if (imsm_count_failed(super, dev, MAP_0) !=
(map->num_members / 2))
}
}
/* update map */
- map->num_members = map->num_members / 2;
+ map->num_members /= map->num_domains;
map->map_state = IMSM_T_STATE_NORMAL;
- map->num_domains = 1;
map->raid_level = 0;
+ set_num_domains(map);
+ update_num_data_stripes(map, imsm_dev_size(dev));
map->failed_disk_num = -1;
- num_data_stripes = imsm_dev_size(dev) / 2;
- num_data_stripes /= map->blocks_per_strip;
- set_num_data_stripes(map, num_data_stripes);
}
if (u->direction == R0_TO_R10) {
void **space;
- unsigned long long num_data_stripes;
/* update slots in current disk list */
for (dm = super->disks; dm; dm = dm->next) {
memcpy(dev_new, dev, sizeof(*dev));
/* update new map */
map = get_imsm_map(dev_new, MAP_0);
- map->num_members = map->num_members * 2;
+
map->map_state = IMSM_T_STATE_DEGRADED;
- map->num_domains = 2;
map->raid_level = 1;
- num_data_stripes = imsm_dev_size(dev) / 2;
- num_data_stripes /= map->blocks_per_strip;
- num_data_stripes /= map->num_domains;
- set_num_data_stripes(map, num_data_stripes);
+ set_num_domains(map);
+ map->num_members = map->num_members * map->num_domains;
+ update_num_data_stripes(map, imsm_dev_size(dev));
/* replace dev<->dev_new */
dv->dev = dev_new;
int victim = u->dev_idx;
struct active_array *a;
struct intel_dev **dp;
- struct imsm_dev *dev;
/* sanity check that we are not affecting the uuid of
* active arrays, or deleting an active array
* is active in the container, so checking
* mpb->num_raid_devs is just extra paranoia
*/
- dev = get_imsm_dev(super, victim);
- if (a || !dev || mpb->num_raid_devs == 1) {
+ if (a || mpb->num_raid_devs == 1 || victim >= super->anchor->num_raid_devs) {
dprintf("failed to delete subarray-%d\n", victim);
break;
}
if (a->info.container_member == target)
break;
dev = get_imsm_dev(super, u->dev_idx);
- if (a || !dev || !check_name(super, name, 1)) {
+ if (a || !check_name(super, name, 1)) {
dprintf("failed to rename subarray-%d\n", target);
break;
}
struct imsm_update_rwh_policy *u = (void *)update->buf;
int target = u->dev_idx;
struct imsm_dev *dev = get_imsm_dev(super, target);
- if (!dev) {
- dprintf("could not find subarray-%d\n", target);
- break;
- }
if (dev->rwh_policy != u->new_policy) {
dev->rwh_policy = u->new_policy;
{
int rv = -1;
struct intel_super *super = st->sb;
- unsigned long long *target_offsets;
- int *targets;
int i;
struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
int new_disks = map_dest->num_members;
int dest_layout = 0;
- int dest_chunk;
- unsigned long long start;
+ int dest_chunk, targets[new_disks];
+ unsigned long long start, target_offsets[new_disks];
int data_disks = imsm_num_data_members(map_dest);
- targets = xmalloc(new_disks * sizeof(int));
-
for (i = 0; i < new_disks; i++) {
struct dl *dl_disk = get_imsm_dl_disk(super, i);
-
- targets[i] = dl_disk->fd;
+ if (dl_disk && is_fd_valid(dl_disk->fd))
+ targets[i] = dl_disk->fd;
+ else
+ goto abort;
}
- target_offsets = xcalloc(new_disks, sizeof(unsigned long long));
-
start = info->reshape_progress * 512;
for (i = 0; i < new_disks; i++) {
target_offsets[i] = migr_chkp_area_pba(super->migr_rec) * 512;
rv = 0;
abort:
- if (targets) {
- free(targets);
- }
- free(target_offsets);
-
return rv;
}
if (dl_disk->index < 0)
continue;
- if (dl_disk->fd < 0) {
+ if (!is_fd_valid(dl_disk->fd)) {
skipped_disks++;
continue;
}
{
struct intel_super *super = st->sb;
int update_memory_size;
+ int current_chunk_size;
struct imsm_update_reshape_migration *u;
- struct imsm_dev *dev;
+ struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
int previous_level = -1;
dprintf("(enter) New Level = %i\n", geo->level);
u->new_disks[0] = -1;
u->new_chunksize = -1;
- dev = get_imsm_dev(super, u->subdev);
- if (dev) {
- struct imsm_map *map;
+ current_chunk_size = __le16_to_cpu(map->blocks_per_strip) / 2;
- map = get_imsm_map(dev, MAP_0);
- if (map) {
- int current_chunk_size =
- __le16_to_cpu(map->blocks_per_strip) / 2;
-
- if (geo->chunksize != current_chunk_size) {
- u->new_chunksize = geo->chunksize / 1024;
- dprintf("imsm: chunk size change from %i to %i\n",
- current_chunk_size, u->new_chunksize);
- }
- previous_level = map->raid_level;
- }
+ if (geo->chunksize != current_chunk_size) {
+ u->new_chunksize = geo->chunksize / 1024;
+ dprintf("imsm: chunk size change from %i to %i\n",
+ current_chunk_size, u->new_chunksize);
}
+ previous_level = map->raid_level;
+
if (geo->level == 5 && previous_level == 0) {
struct mdinfo *spares = NULL;
unsigned long long current_size;
unsigned long long free_size;
unsigned long long max_size;
- int rv;
+ imsm_status_t rv;
getinfo_super_imsm_volume(st, &info, NULL);
if (geo->level != info.array.level && geo->level >= 0 &&
}
/* check the maximum available size
*/
- rv = imsm_get_free_size(st, dev->vol.map->num_members,
- 0, chunk, &free_size);
- if (rv == 0)
+ rv = imsm_get_free_size(super, dev->vol.map->num_members,
+ 0, chunk, &free_size);
+
+ if (rv != IMSM_STATUS_OK)
/* Cannot find maximum available space
*/
max_size = 0;
struct imsm_super *mpb = super->anchor;
if (mpb->num_raid_devs > 1) {
- pr_err("Error. Cannot perform operation on %s- for this operation it MUST be single array in container\n",
- geo->dev_name);
+ pr_err("Error. Cannot perform operation on %s- for this operation "
+ "it MUST be single array in container\n", geo->dev_name);
change = -1;
}
}
unsigned long long d_size = imsm_dev_size(dev);
int u_size;
- if (calc_size == d_size || dev->vol.migr_type == MIGR_GEN_MIGR)
+ if (calc_size == d_size)
continue;
/* There is a difference, confirm that imsm_dev_size is
geo.size = d_size;
u_size = imsm_create_metadata_update_for_size_change(st, &geo,
&update);
- if (u_size < 1) {
- dprintf("imsm: Cannot prepare size change update\n");
- goto exit;
- }
imsm_update_metadata_locally(st, update, u_size);
if (st->update_tail) {
append_metadata_update(st, update, u_size);
st->update_tail = &st->updates;
} else {
imsm_sync_metadata(st);
+ free(update);
}
}
ret_val = 0;
unsigned long long to_complete = sra->reshape_progress;
unsigned long long position_to_set = to_complete / ndata;
- if (fd < 0) {
+ if (!is_fd_valid(fd)) {
dprintf("cannot open reshape_position\n");
return 1;
}
close(fd);
return 1;
}
- usleep(30000);
+ sleep_for(0, MSEC_TO_NSEC(30), true);
} else
break;
} while (retry--);
continue;
if (sd->disk.state & (1<<MD_DISK_SYNC)) {
char sbuf[100];
+ int raid_disk = sd->disk.raid_disk;
if (sysfs_get_str(info,
sd, "state", sbuf, sizeof(sbuf)) < 0 ||
strstr(sbuf, "in_sync") == NULL) {
/* this device is dead */
sd->disk.state = (1<<MD_DISK_FAULTY);
- if (sd->disk.raid_disk >= 0 &&
- sources[sd->disk.raid_disk] >= 0) {
- close(sources[
- sd->disk.raid_disk]);
- sources[sd->disk.raid_disk] =
- -1;
- }
+ if (raid_disk >= 0)
+ close_fd(&sources[raid_disk]);
new_degraded++;
}
}
return -1;
fd = d->fd;
- if (fd < 0) {
+ if (!is_fd_valid(fd)) {
fd = open(d->devname, O_RDONLY, 0);
- if (fd < 0) {
+
+ if (!is_fd_valid(fd)) {
dprintf("cannot open the device %s\n", d->devname);
goto abort;
}
ret = 0;
abort:
- if ((d->fd < 0) && (fd >= 0))
- close(fd);
+ if (!is_fd_valid(d->fd))
+ close_fd(&fd);
+
if (read_buf)
free(read_buf);
unsigned long long offset;
struct dl *d;
- if (!dev)
- return -1;
-
if (dev->rwh_policy != RWH_BITMAP)
return 0;
return -1;
dev = get_imsm_dev(super, vol_idx);
-
- if (!dev) {
- dprintf("cannot find the device for volume index %d\n",
- vol_idx);
- return -1;
- }
dev->rwh_policy = RWH_BITMAP;
-
*chunkp = calculate_bitmap_chunksize(st, dev);
-
return 0;
}