#define HAVE_STDINT_H 1
#include "mdadm.h"
#include "mdmon.h"
+#include "dlink.h"
#include "sha1.h"
#include "platform-intel.h"
#include <values.h>
* mutliple PPL area
*/
+/*
+ * Internal Write-intent bitmap is stored in the same area where PPL.
+ * Both features are mutually exclusive, so it is not an issue.
+ * The first 8KiB of the area are reserved and shall not be used.
+ */
+#define IMSM_BITMAP_AREA_RESERVED_SIZE 8192
+
+#define IMSM_BITMAP_HEADER_OFFSET (IMSM_BITMAP_AREA_RESERVED_SIZE)
+#define IMSM_BITMAP_HEADER_SIZE MAX_SECTOR_SIZE
+
+#define IMSM_BITMAP_START_OFFSET (IMSM_BITMAP_HEADER_OFFSET + IMSM_BITMAP_HEADER_SIZE)
+#define IMSM_BITMAP_AREA_SIZE (MULTIPLE_PPL_AREA_SIZE_IMSM - IMSM_BITMAP_START_OFFSET)
+#define IMSM_BITMAP_AND_HEADER_SIZE (IMSM_BITMAP_AREA_SIZE + IMSM_BITMAP_HEADER_SIZE)
+
+#define IMSM_DEFAULT_BITMAP_CHUNKSIZE (64 * 1024 * 1024)
+#define IMSM_DEFAULT_BITMAP_DAEMON_SLEEP 5
+
/*
* This macro let's us ensure that no-one accidentally
* changes the size of a struct
ASSERT_SIZE(imsm_map, 52)
struct imsm_vol {
- __u32 curr_migr_unit;
+ __u32 curr_migr_unit_lo;
__u32 checkpoint_id; /* id to access curr_migr_unit */
__u8 migr_state; /* Normal or Migrating */
#define MIGR_INIT 0
__u8 fs_state; /* fast-sync state for CnG (0xff == disabled) */
__u16 verify_errors; /* number of mismatches */
__u16 bad_blocks; /* number of bad blocks during verify */
- __u32 filler[4];
+ __u32 curr_migr_unit_hi;
+ __u32 filler[3];
struct imsm_map map[1];
/* here comes another one if migr_state */
};
#define RWH_MULTIPLE_DISTRIBUTED 3
#define RWH_MULTIPLE_PPLS_JOURNALING_DRIVE 4
#define RWH_MULTIPLE_OFF 5
+#define RWH_BITMAP 6
__u8 rwh_policy; /* Raid Write Hole Policy */
__u8 jd_serial[MAX_RAID_SERIAL_LEN]; /* Journal Drive serial number */
__u8 filler1;
* (starts at 1)
*/
__u16 filler1; /* 0x4E - 0x4F */
-#define IMSM_FILLERS 34
- __u32 filler[IMSM_FILLERS]; /* 0x50 - 0xD7 RAID_MPB_FILLERS */
+ __u64 creation_time; /* 0x50 - 0x57 Array creation time */
+#define IMSM_FILLERS 32
+ __u32 filler[IMSM_FILLERS]; /* 0x58 - 0xD7 RAID_MPB_FILLERS */
struct imsm_disk disk[1]; /* 0xD8 diskTbl[numDisks] */
/* here comes imsm_dev[num_raid_devs] */
/* here comes BBM logs */
* destination - high order 32 bits */
__u32 num_migr_units_hi; /* Total num migration units-of-op
* high order 32 bits */
+ __u32 filler[16];
};
-ASSERT_SIZE(migr_record, 64)
+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:
struct imsm_update_general_migration_checkpoint {
enum imsm_update_type type;
- __u32 curr_migr_unit;
+ __u64 curr_migr_unit;
};
struct disk_info {
[SYS_DEV_VMD] = "VMD"
};
+static int no_platform = -1;
+
+static int check_no_platform(void)
+{
+ static const char search[] = "mdadm.imsm.test=1";
+ FILE *fp;
+
+ if (no_platform >= 0)
+ return no_platform;
+
+ if (check_env("IMSM_NO_PLATFORM")) {
+ no_platform = 1;
+ return 1;
+ }
+ fp = fopen("/proc/cmdline", "r");
+ if (fp) {
+ char *l = conf_line(fp);
+ char *w = l;
+
+ do {
+ if (strcmp(w, search) == 0)
+ no_platform = 1;
+ w = dl_next(w);
+ } while (w != l);
+ free_line(l);
+ fclose(fp);
+ if (no_platform >= 0)
+ return no_platform;
+ }
+ no_platform = 0;
+ return 0;
+}
+
+void imsm_set_no_platform(int v)
+{
+ no_platform = v;
+}
+
const char *get_sys_dev_type(enum sys_dev_type type)
{
if (type >= SYS_DEV_MAX)
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);
+ disk_path = diskfd_to_devpath(fd, 1, NULL);
if (!disk_path)
return 0;
for (elem = list; elem; elem = elem->next)
if (path_attached_to_hba(disk_path, elem->path))
- return elem;
+ break;
if (disk_path != devname)
free(disk_path);
- return NULL;
+ return elem;
}
static int find_intel_hba_capability(int fd, struct intel_super *super,
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)
return join_u32(map->num_data_stripes_lo, map->num_data_stripes_hi);
}
+static unsigned long long vol_curr_migr_unit(struct imsm_dev *dev)
+{
+ if (dev == NULL)
+ return 0;
+
+ return join_u32(dev->vol.curr_migr_unit_lo, dev->vol.curr_migr_unit_hi);
+}
+
static unsigned long long imsm_dev_size(struct imsm_dev *dev)
{
if (dev == 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;
+
+ split_ull(n, &dev->vol.curr_migr_unit_lo, &dev->vol.curr_migr_unit_hi);
+}
+
static void set_imsm_dev_size(struct imsm_dev *dev, unsigned long long n)
{
split_ull(n, &dev->size_low, &dev->size_high);
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
printf("\n");
printf("[%.16s]:\n", dev->volume);
+ printf(" Subarray : %d\n", super->current_vol);
printf(" UUID : %s\n", uuid);
printf(" RAID Level : %d", get_imsm_raid_level(map));
if (map2)
(unsigned long long)sz * 512 / super->sector_size,
human_size(sz * 512));
printf(" Sector Offset : %llu\n",
- pba_of_lba0(map));
+ pba_of_lba0(map) * 512 / super->sector_size);
printf(" Num Stripes : %llu\n",
num_data_stripes(map));
printf(" Chunk Size : %u KiB",
struct imsm_map *map = get_imsm_map(dev, MAP_1);
printf(" <-- %s", map_state_str[map->map_state]);
- printf("\n Checkpoint : %u ",
- __le32_to_cpu(dev->vol.curr_migr_unit));
+ printf("\n Checkpoint : %llu ", vol_curr_migr_unit(dev));
if (is_gen_migration(dev) && (slot > 1 || slot < 0))
printf("(N/A)");
else
printf("Multiple distributed PPLs\n");
else if (dev->rwh_policy == RWH_MULTIPLE_PPLS_JOURNALING_DRIVE)
printf("Multiple PPLs on journaling drive\n");
+ else if (dev->rwh_policy == RWH_BITMAP)
+ printf("Write-intent bitmap\n");
else
printf("<unknown:%d>\n", dev->rwh_policy);
+
+ printf(" Volume ID : %u\n", dev->my_vol_raid_dev_num);
}
static void print_imsm_disk(struct imsm_disk *disk,
struct imsm_map *map = get_imsm_map(dev, MAP_0);
/* dev */
set_imsm_dev_size(dev, imsm_dev_size(dev)/IMSM_4K_DIV);
- dev->vol.curr_migr_unit /= IMSM_4K_DIV;
+ set_vol_curr_migr_unit(dev,
+ vol_curr_migr_unit(dev) / IMSM_4K_DIV);
/* map0 */
set_blocks_per_member(map, blocks_per_member(map)/IMSM_4K_DIV);
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) {
struct imsm_map *map = get_imsm_map(dev, MAP_0);
/* dev */
set_imsm_dev_size(dev, imsm_dev_size(dev)*IMSM_4K_DIV);
- dev->vol.curr_migr_unit *= IMSM_4K_DIV;
+ set_vol_curr_migr_unit(dev,
+ vol_curr_migr_unit(dev) * IMSM_4K_DIV);
/* map0 */
set_blocks_per_member(map, blocks_per_member(map)*IMSM_4K_DIV);
__u32 sum;
__u32 reserved = imsm_reserved_sectors(super, super->disks);
struct dl *dl;
+ time_t creation_time;
strncpy(str, (char *)mpb->sig, MPB_SIG_LEN);
str[MPB_SIG_LEN-1] = '\0';
printf(" Orig Family : %08x\n", __le32_to_cpu(mpb->orig_family_num));
printf(" Family : %08x\n", __le32_to_cpu(mpb->family_num));
printf(" Generation : %08x\n", __le32_to_cpu(mpb->generation_num));
+ creation_time = __le64_to_cpu(mpb->creation_time);
+ printf(" Creation Time : %.24s\n",
+ creation_time ? ctime(&creation_time) : "Unknown");
printf(" Attributes : ");
if (imsm_check_attributes(mpb->attributes))
printf("All supported\n");
/* We just write a generic IMSM ARRAY entry */
struct mdinfo info;
char nbuf[64];
- struct intel_super *super = st->sb;
-
- if (!super->anchor->num_raid_devs) {
- printf("ARRAY metadata=imsm\n");
- return;
- }
getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(st, &info, nbuf, ':');
printf("MD_LEVEL=container\n");
printf("MD_UUID=%s\n", nbuf+5);
printf("MD_DEVICES=%u\n", mpb->num_disks);
+ printf("MD_CREATION_TIME=%llu\n", __le64_to_cpu(mpb->creation_time));
}
static void detail_super_imsm(struct supertype *st, char *homehost,
char vendor[64];
char buf[1024];
int major, minor;
- char *device;
+ char device[PATH_MAX];
char *c;
int port;
int type;
if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2)
continue;
- path = devt_to_devpath(makedev(major, minor));
+ path = devt_to_devpath(makedev(major, minor), 1, NULL);
if (!path)
continue;
if (!path_attached_to_hba(path, hba_path)) {
continue;
}
- /* retrieve the scsi device type */
- if (asprintf(&device, "/sys/dev/block/%d:%d/device/xxxxxxx", major, minor) < 0) {
+ /* retrieve the scsi device */
+ if (!devt_to_devpath(makedev(major, minor), 1, device)) {
if (verbose > 0)
- pr_err("failed to allocate 'device'\n");
+ pr_err("failed to get device\n");
err = 2;
break;
}
- sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor);
- if (load_sys(device, buf, sizeof(buf)) != 0) {
- if (verbose > 0)
- pr_err("failed to read device type for %s\n",
- path);
+ if (devpath_to_char(device, "type", buf, sizeof(buf), 0)) {
err = 2;
- free(device);
break;
}
type = strtoul(buf, NULL, 10);
if (!(type == 0 || type == 7 || type == 14)) {
vendor[0] = '\0';
model[0] = '\0';
- sprintf(device, "/sys/dev/block/%d:%d/device/vendor", major, minor);
- if (load_sys(device, buf, sizeof(buf)) == 0) {
+
+ if (devpath_to_char(device, "vendor", buf,
+ sizeof(buf), 0) == 0) {
strncpy(vendor, buf, sizeof(vendor));
vendor[sizeof(vendor) - 1] = '\0';
c = (char *) &vendor[sizeof(vendor) - 1];
*c-- = '\0';
}
- sprintf(device, "/sys/dev/block/%d:%d/device/model", major, minor);
- if (load_sys(device, buf, sizeof(buf)) == 0) {
+
+ if (devpath_to_char(device, "model", buf,
+ sizeof(buf), 0) == 0) {
strncpy(model, buf, sizeof(model));
model[sizeof(model) - 1] = '\0';
c = (char *) &model[sizeof(model) - 1];
}
} else
buf[0] = '\0';
- free(device);
/* chop device path to 'host%d' and calculate the port number */
c = strchr(&path[hba_len], '/');
}
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);
static int print_nvme_info(struct sys_dev *hba)
{
- char buf[1024];
struct dirent *ent;
DIR *dir;
- char *rp;
- int fd;
dir = opendir("/sys/block/");
if (!dir)
return 1;
for (ent = readdir(dir); ent; ent = readdir(dir)) {
- if (strstr(ent->d_name, "nvme")) {
- sprintf(buf, "/sys/block/%s", ent->d_name);
- rp = realpath(buf, NULL);
- if (!rp)
- continue;
- if (path_attached_to_hba(rp, hba->path)) {
- fd = open_dev(ent->d_name);
- if (fd < 0) {
- free(rp);
- continue;
- }
+ char ns_path[PATH_MAX];
+ char cntrl_path[PATH_MAX];
+ char buf[PATH_MAX];
+ int fd = -1;
- fd2devname(fd, buf);
- if (hba->type == SYS_DEV_VMD)
- printf(" NVMe under VMD : %s", buf);
- else if (hba->type == SYS_DEV_NVME)
- printf(" NVMe Device : %s", buf);
- if (!imsm_read_serial(fd, NULL, (__u8 *)buf,
- sizeof(buf)))
- printf(" (%s)\n", buf);
- else
- printf("()\n");
- close(fd);
- }
- free(rp);
- }
+ if (!strstr(ent->d_name, "nvme"))
+ goto skip;
+
+ fd = open_dev(ent->d_name);
+ if (!is_fd_valid(fd))
+ goto skip;
+
+ if (!diskfd_to_devpath(fd, 0, ns_path) ||
+ !diskfd_to_devpath(fd, 1, cntrl_path))
+ goto skip;
+
+ if (!path_attached_to_hba(cntrl_path, hba->path))
+ goto skip;
+
+ if (!imsm_is_nvme_namespace_supported(fd, 0))
+ goto skip;
+
+ fd2devname(fd, buf);
+ if (hba->type == SYS_DEV_VMD)
+ printf(" NVMe under VMD : %s", buf);
+ else if (hba->type == SYS_DEV_NVME)
+ printf(" NVMe Device : %s", buf);
+
+ if (!imsm_read_serial(fd, NULL, (__u8 *)buf,
+ sizeof(buf)))
+ printf(" (%s)\n", buf);
+ else
+ printf("()\n");
+
+skip:
+ close_fd(&fd);
}
closedir(dir);
int result=1;
if (enumerate_only) {
- if (check_env("IMSM_NO_PLATFORM"))
+ if (check_no_platform())
return 0;
list = find_intel_devices();
if (!list)
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)
{
* sector of disk)
* Parameters:
* super : imsm internal array info
- * info : general array info
* Returns:
* 0 : success
* -1 : fail
* -2 : no migration in progress
******************************************************************************/
-static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
+static int load_imsm_migr_rec(struct intel_super *super)
{
- struct mdinfo *sd;
struct dl *dl;
char nm[30];
int retval = -1;
struct imsm_dev *dev;
struct imsm_map *map;
int slot = -1;
+ int keep_fd = 1;
/* find map under migration */
dev = imsm_get_device_during_migration(super);
if (dev == NULL)
return -2;
- if (info) {
- for (sd = info->devs ; sd ; sd = sd->next) {
- /* read only from one of the first two slots */
- if ((sd->disk.raid_disk < 0) ||
- (sd->disk.raid_disk > 1))
- continue;
+ map = get_imsm_map(dev, MAP_0);
+ if (!map)
+ return -1;
- sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
- fd = dev_open(nm, O_RDONLY);
- if (fd >= 0)
- break;
- }
- }
- if (fd < 0) {
- map = get_imsm_map(dev, MAP_0);
- for (dl = super->disks; dl; dl = dl->next) {
- /* skip spare and failed disks
- */
- if (dl->index < 0)
- continue;
- /* read only from one of the first two slots */
- if (map)
- slot = get_imsm_disk_slot(map, dl->index);
- if (map == NULL || slot > 1 || slot < 0)
- continue;
+ for (dl = super->disks; dl; dl = dl->next) {
+ /* skip spare and failed disks
+ */
+ if (dl->index < 0)
+ continue;
+ /* read only from one of the first two slots
+ */
+ slot = get_imsm_disk_slot(map, dl->index);
+ if (slot > 1 || slot < 0)
+ continue;
+
+ 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;
+ }
+ } else {
+ fd = dl->fd;
+ break;
}
}
- if (fd < 0)
- goto out;
- retval = read_imsm_migr_rec(fd, super);
-out:
- if (fd >= 0)
+ if (!is_fd_valid(fd))
+ return retval;
+ retval = read_imsm_migr_rec(fd, super);
+ if (!keep_fd)
close(fd);
+
return retval;
}
}
(*u)->type = update_general_migration_checkpoint;
(*u)->curr_migr_unit = current_migr_unit(super->migr_rec);
- dprintf("prepared for %u\n", (*u)->curr_migr_unit);
+ dprintf("prepared for %llu\n", (unsigned long long)(*u)->curr_migr_unit);
return update_memory_size;
}
struct intel_super *super = st->sb;
unsigned int sector_size = super->sector_size;
unsigned long long dsize;
- char nm[30];
- int fd = -1;
int retval = -1;
struct dl *sd;
int len;
if (map == NULL || slot > 1 || slot < 0)
continue;
- sprintf(nm, "%d:%d", sd->major, sd->minor);
- fd = dev_open(nm, O_RDWR);
- if (fd < 0)
- continue;
- get_dev_size(fd, NULL, &dsize);
- if (lseek64(fd, dsize - (MIGR_REC_SECTOR_POSITION*sector_size),
+ get_dev_size(sd->fd, NULL, &dsize);
+ if (lseek64(sd->fd, dsize - (MIGR_REC_SECTOR_POSITION *
+ sector_size),
SEEK_SET) < 0) {
pr_err("Cannot seek to anchor block: %s\n",
strerror(errno));
goto out;
}
- if ((unsigned int)write(fd, super->migr_rec_buf,
+ if ((unsigned int)write(sd->fd, super->migr_rec_buf,
MIGR_REC_BUF_SECTORS*sector_size) !=
MIGR_REC_BUF_SECTORS*sector_size) {
pr_err("Cannot write migr record block: %s\n",
strerror(errno));
goto out;
}
- close(fd);
- fd = -1;
}
if (sector_size == 4096)
convert_from_4k_imsm_migr_rec(super);
retval = 0;
out:
- if (fd >= 0)
- close(fd);
return retval;
}
return component_size;
}
+/*******************************************************************************
+ * Function: get_bitmap_header_sector
+ * Description: Returns the sector where the bitmap header is placed.
+ * Parameters:
+ * st : supertype information
+ * dev_idx : index of the device with bitmap
+ *
+ * Returns:
+ * The sector where the bitmap header is placed
+ ******************************************************************************/
+static unsigned long long get_bitmap_header_sector(struct intel_super *super,
+ int dev_idx)
+{
+ struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+
+ if (!super->sector_size) {
+ dprintf("sector size is not set\n");
+ return 0;
+ }
+
+ return pba_of_lba0(map) + calc_component_size(map, dev) +
+ (IMSM_BITMAP_HEADER_OFFSET / super->sector_size);
+}
+
+/*******************************************************************************
+ * Function: get_bitmap_sector
+ * Description: Returns the sector where the bitmap is placed.
+ * Parameters:
+ * st : supertype information
+ * dev_idx : index of the device with bitmap
+ *
+ * Returns:
+ * The sector where the bitmap is placed
+ ******************************************************************************/
+static unsigned long long get_bitmap_sector(struct intel_super *super,
+ int dev_idx)
+{
+ if (!super->sector_size) {
+ dprintf("sector size is not set\n");
+ return 0;
+ }
+
+ return get_bitmap_header_sector(super, dev_idx) +
+ (IMSM_BITMAP_HEADER_SIZE / super->sector_size);
+}
+
static unsigned long long get_ppl_sector(struct intel_super *super, int dev_idx)
{
struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
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);
} else if (info->array.level <= 0) {
info->consistency_policy = CONSISTENCY_POLICY_NONE;
} else {
- info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
+ if (dev->rwh_policy == RWH_BITMAP) {
+ info->bitmap_offset = get_bitmap_sector(super, super->current_vol);
+ info->consistency_policy = CONSISTENCY_POLICY_BITMAP;
+ } else {
+ info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
+ }
}
info->reshape_progress = 0;
case MIGR_INIT: {
__u64 blocks_per_unit = blocks_per_migr_unit(super,
dev);
- __u64 units = __le32_to_cpu(dev->vol.curr_migr_unit);
+ __u64 units = vol_curr_migr_unit(dev);
info->resync_start = blocks_per_unit * units;
break;
__u64 blocks_per_unit = blocks_per_migr_unit(super,
dev);
__u64 units = current_migr_unit(migr_rec);
- unsigned long long array_blocks;
int used_disks;
if (__le32_to_cpu(migr_rec->ascending_migr) &&
used_disks = imsm_num_data_members(prev_map);
if (used_disks > 0) {
- array_blocks = per_dev_array_size(map) *
+ info->custom_array_size = per_dev_array_size(map) *
used_disks;
- info->custom_array_size =
- round_size_to_mb(array_blocks,
- used_disks);
-
}
}
case MIGR_VERIFY:
}
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)
memcpy(dest, src, sizeof_imsm_dev(src, 0));
}
-static int compare_super_imsm(struct supertype *st, struct supertype *tst)
+static int compare_super_imsm(struct supertype *st, struct supertype *tst,
+ int verbose)
{
- /*
- * return:
+ /* return:
* 0 same, or first was empty, and second was copied
- * 1 second had wrong number
- * 2 wrong uuid
- * 3 wrong other info
+ * 1 sb are different
*/
struct intel_super *first = st->sb;
struct intel_super *sec = tst->sb;
tst->sb = NULL;
return 0;
}
+
/* in platform dependent environment test if the disks
* use the same Intel hba
- * If not on Intel hba at all, allow anything.
+ * if not on Intel hba at all, allow anything.
+ * doesn't check HBAs if num_raid_devs is not set, as it means
+ * it is a free floating spare, and all spares regardless of HBA type
+ * will fall into separate container during the assembly
*/
- if (!check_env("IMSM_NO_PLATFORM") && first->hba && sec->hba) {
+ if (first->hba && sec->hba && first->anchor->num_raid_devs != 0) {
if (first->hba->type != sec->hba->type) {
- fprintf(stderr,
- "HBAs of devices do not match %s != %s\n",
- get_sys_dev_type(first->hba->type),
- get_sys_dev_type(sec->hba->type));
- return 3;
+ if (verbose)
+ pr_err("HBAs of devices do not match %s != %s\n",
+ get_sys_dev_type(first->hba->type),
+ get_sys_dev_type(sec->hba->type));
+ return 1;
}
if (first->orom != sec->orom) {
- fprintf(stderr,
- "HBAs of devices do not match %s != %s\n",
- first->hba->pci_id, sec->hba->pci_id);
- return 3;
+ if (verbose)
+ pr_err("HBAs of devices do not match %s != %s\n",
+ first->hba->pci_id, sec->hba->pci_id);
+ return 1;
}
}
- /* if an anchor does not have num_raid_devs set then it is a free
- * floating spare
- */
if (first->anchor->num_raid_devs > 0 &&
sec->anchor->num_raid_devs > 0) {
/* Determine if these disks might ever have been
if (memcmp(first->anchor->sig, sec->anchor->sig,
MAX_SIGNATURE_LENGTH) != 0)
- return 3;
+ return 1;
if (first_family == 0)
first_family = first->anchor->family_num;
sec_family = sec->anchor->family_num;
if (first_family != sec_family)
- return 3;
+ return 1;
}
- /* if 'first' is a spare promote it to a populated mpb with sec's
- * family number
- */
- if (first->anchor->num_raid_devs == 0 &&
- sec->anchor->num_raid_devs > 0) {
- int i;
- struct intel_dev *dv;
- struct imsm_dev *dev;
-
- /* we need to copy raid device info from sec if an allocation
- * fails here we don't associate the spare
- */
- for (i = 0; i < sec->anchor->num_raid_devs; i++) {
- dv = xmalloc(sizeof(*dv));
- dev = xmalloc(sizeof_imsm_dev(get_imsm_dev(sec, i), 1));
- dv->dev = dev;
- dv->index = i;
- dv->next = first->devlist;
- first->devlist = dv;
- }
- if (i < sec->anchor->num_raid_devs) {
- /* allocation failure */
- free_devlist(first);
- pr_err("imsm: failed to associate spare\n");
- return 3;
- }
- first->anchor->num_raid_devs = sec->anchor->num_raid_devs;
- first->anchor->orig_family_num = sec->anchor->orig_family_num;
- first->anchor->family_num = sec->anchor->family_num;
- memcpy(first->anchor->sig, sec->anchor->sig, MAX_SIGNATURE_LENGTH);
- for (i = 0; i < sec->anchor->num_raid_devs; i++)
- imsm_copy_dev(get_imsm_dev(first, i), get_imsm_dev(sec, i));
- }
+ /* if an anchor does not have num_raid_devs set then it is a free
+ * floating spare. don't assosiate spare with any array, as during assembly
+ * spares shall fall into separate container, from which they can be moved
+ * when necessary
+ */
+ if (first->anchor->num_raid_devs ^ sec->anchor->num_raid_devs)
+ return 1;
return 0;
}
static void fd2devname(int fd, char *name)
{
- struct stat st;
- char path[256];
- char dname[PATH_MAX];
char *nm;
- int rv;
-
- name[0] = '\0';
- if (fstat(fd, &st) != 0)
- return;
- sprintf(path, "/sys/dev/block/%d:%d",
- major(st.st_rdev), minor(st.st_rdev));
- rv = readlink(path, dname, sizeof(dname)-1);
- if (rv <= 0)
+ nm = fd2kname(fd);
+ if (!nm)
return;
- dname[rv] = '\0';
- nm = strrchr(dname, '/');
- if (nm) {
- nm++;
- snprintf(name, MAX_RAID_SERIAL_LEN, "/dev/%s", nm);
- }
+ snprintf(name, MAX_RAID_SERIAL_LEN, "/dev/%s", nm);
}
static int nvme_get_serial(int fd, void *buf, size_t buf_len)
{
- char path[60];
+ char path[PATH_MAX];
char *name = fd2kname(fd);
if (!name)
if (strncmp(name, "nvme", 4) != 0)
return 1;
- snprintf(path, sizeof(path) - 1, "/sys/block/%s/device/serial", name);
+ if (!diskfd_to_devpath(fd, 1, path))
+ return 1;
- return load_sys(path, buf, buf_len);
+ return devpath_to_char(path, "serial", buf, buf_len, 0);
}
extern int scsi_get_serial(int fd, void *buf, size_t buf_len);
dev->vol.migr_state = 1;
set_migr_type(dev, migr_type);
- dev->vol.curr_migr_unit = 0;
+ set_vol_curr_migr_unit(dev, 0);
dest = get_imsm_map(dev, MAP_1);
/* duplicate and then set the target end state in map[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)
dev->vol.migr_state = 0;
set_migr_type(dev, 0);
- dev->vol.curr_migr_unit = 0;
+ set_vol_curr_migr_unit(dev, 0);
map->map_state = map_state;
}
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);
MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) {
pr_err("could not allocate migr_rec buffer\n");
free(super->buf);
+ super->buf = NULL;
return 2;
}
super->clean_migration_record_by_mdmon = 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)
+static void __free_imsm_disk(struct dl *d, int do_close)
{
- if (d->fd >= 0)
- close(d->fd);
+ if (do_close)
+ close_fd(&d->fd);
if (d->devname)
free(d->devname);
if (d->e)
while (super->disks) {
d = super->disks;
super->disks = d->next;
- __free_imsm_disk(d);
+ __free_imsm_disk(d, 1);
}
while (super->disk_mgmt_list) {
d = super->disk_mgmt_list;
super->disk_mgmt_list = d->next;
- __free_imsm_disk(d);
+ __free_imsm_disk(d, 1);
}
while (super->missing) {
d = super->missing;
super->missing = d->next;
- __free_imsm_disk(d);
+ __free_imsm_disk(d, 1);
}
}
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_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
}
/* load migration record */
- err = load_imsm_migr_rec(super, NULL);
+ err = load_imsm_migr_rec(super);
if (err == -1) {
/* migration is in progress,
* but migr_rec cannot be loaded,
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;
}
- get_dev_sector_size(dfd, NULL, &s->sector_size);
+ if (!get_dev_sector_size(dfd, NULL, &s->sector_size)) {
+ err = 2;
+ goto error;
+ }
find_intel_hba_capability(dfd, s, devname);
err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
/* 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;
}
free_super_imsm(st);
super = alloc_super();
- get_dev_sector_size(fd, NULL, &super->sector_size);
if (!super)
return 1;
+
+ if (!get_dev_sector_size(fd, NULL, &super->sector_size)) {
+ free_imsm(super);
+ return 1;
+ }
/* Load hba and capabilities if they exist.
* But do not preclude loading metadata in case capabilities or hba are
* non-compliant and ignore_hw_compat is set.
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;
}
/* load migration record */
- if (load_imsm_migr_rec(super, NULL) == 0) {
+ if (load_imsm_migr_rec(super) == 0) {
/* Check for unsupported migration features */
if (check_mpb_migr_compatibility(super) != 0) {
pr_err("Unsupported migration detected");
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;
vol->migr_state = 0;
set_migr_type(dev, MIGR_INIT);
vol->dirty = !info->state;
- vol->curr_migr_unit = 0;
+ set_vol_curr_migr_unit(dev, 0);
map = get_imsm_map(dev, MAP_0);
set_pba_of_lba0(map, super->create_offset);
map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
}
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;
}
sum += __gen_imsm_checksum(mpb);
mpb->family_num = __cpu_to_le32(sum);
mpb->orig_family_num = mpb->family_num;
+ mpb->creation_time = __cpu_to_le64((__u64)time(NULL));
}
super->current_disk = dl;
return 0;
return ret_val;
}
+
+static int write_super_imsm_spare(struct intel_super *super, struct dl *d);
+
static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
int fd, char *devname,
unsigned long long data_offset)
rv = imsm_read_serial(fd, devname, dd->serial, MAX_RAID_SERIAL_LEN);
if (rv) {
pr_err("failed to retrieve scsi serial, aborting\n");
- if (dd->devname)
- free(dd->devname);
- free(dd);
+ __free_imsm_disk(dd, 0);
abort();
}
+
if (super->hba && ((super->hba->type == SYS_DEV_NVME) ||
(super->hba->type == SYS_DEV_VMD))) {
int i;
- char *devpath = diskfd_to_devpath(fd);
- char controller_path[PATH_MAX];
-
- if (!devpath) {
- pr_err("failed to get devpath, aborting\n");
- if (dd->devname)
- free(dd->devname);
- free(dd);
+ char cntrl_path[PATH_MAX];
+ char *cntrl_name;
+ char pci_dev_path[PATH_MAX];
+
+ if (!diskfd_to_devpath(fd, 2, pci_dev_path) ||
+ !diskfd_to_devpath(fd, 1, cntrl_path)) {
+ pr_err("failed to get dev paths, aborting\n");
+ __free_imsm_disk(dd, 0);
return 1;
}
- snprintf(controller_path, PATH_MAX-1, "%s/device", devpath);
- free(devpath);
+ cntrl_name = basename(cntrl_path);
+ if (is_multipath_nvme(fd))
+ pr_err("%s controller supports Multi-Path I/O, Intel (R) VROC does not support multipathing\n",
+ cntrl_name);
- if (devpath_to_vendor(controller_path) == 0x8086) {
+ if (devpath_to_vendor(pci_dev_path) == 0x8086) {
/*
* If Intel's NVMe drive has serial ended with
* "-A","-B","-1" or "-2" it means that this is "x8"
!imsm_orom_has_tpv_support(super->orom)) {
pr_err("\tPlatform configuration does not support non-Intel NVMe drives.\n"
"\tPlease refer to Intel(R) RSTe/VROC user guide.\n");
- free(dd->devname);
- free(dd);
+ __free_imsm_disk(dd, 0);
return 1;
}
}
get_dev_size(fd, NULL, &size);
- get_dev_sector_size(fd, NULL, &member_sector_size);
+ if (!get_dev_sector_size(fd, NULL, &member_sector_size)) {
+ __free_imsm_disk(dd, 0);
+ return 1;
+ }
if (super->sector_size == 0) {
/* this a first device, so sector_size is not set yet */
dd->next = super->disk_mgmt_list;
super->disk_mgmt_list = dd;
} else {
+ /* this is called outside of mdmon
+ * write initial spare metadata
+ * mdmon will overwrite it.
+ */
dd->next = super->disks;
super->disks = dd;
- super->updates_pending++;
+ write_super_imsm_spare(super, dd);
}
return 0;
struct imsm_super anchor;
} spare_record __attribute__ ((aligned(MAX_SECTOR_SIZE)));
-/* spare records have their own family number and do not have any defined raid
- * devices
- */
-static int write_super_imsm_spares(struct intel_super *super, int doclose)
+
+static int write_super_imsm_spare(struct intel_super *super, struct dl *d)
{
struct imsm_super *mpb = super->anchor;
struct imsm_super *spare = &spare_record.anchor;
__u32 sum;
- struct dl *d;
+
+ if (d->index != -1)
+ return 1;
spare->mpb_size = __cpu_to_le32(sizeof(struct imsm_super));
spare->generation_num = __cpu_to_le32(1UL);
snprintf((char *) spare->sig, MAX_SIGNATURE_LENGTH,
MPB_SIGNATURE MPB_VERSION_RAID0);
- for (d = super->disks; d; d = d->next) {
- if (d->index != -1)
- continue;
+ spare->disk[0] = d->disk;
+ if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
+ spare->attributes |= MPB_ATTRIB_2TB_DISK;
- spare->disk[0] = d->disk;
- if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
- spare->attributes |= MPB_ATTRIB_2TB_DISK;
+ if (super->sector_size == 4096)
+ convert_to_4k_imsm_disk(&spare->disk[0]);
+
+ sum = __gen_imsm_checksum(spare);
+ spare->family_num = __cpu_to_le32(sum);
+ spare->orig_family_num = 0;
+ sum = __gen_imsm_checksum(spare);
+ spare->check_sum = __cpu_to_le32(sum);
+
+ if (store_imsm_mpb(d->fd, spare)) {
+ pr_err("failed for device %d:%d %s\n",
+ d->major, d->minor, strerror(errno));
+ return 1;
+ }
- if (super->sector_size == 4096)
- convert_to_4k_imsm_disk(&spare->disk[0]);
+ return 0;
+}
+/* spare records have their own family number and do not have any defined raid
+ * devices
+ */
+static int write_super_imsm_spares(struct intel_super *super, int doclose)
+{
+ struct dl *d;
- sum = __gen_imsm_checksum(spare);
- spare->family_num = __cpu_to_le32(sum);
- spare->orig_family_num = 0;
- sum = __gen_imsm_checksum(spare);
- spare->check_sum = __cpu_to_le32(sum);
+ for (d = super->disks; d; d = d->next) {
+ if (d->index != -1)
+ continue;
- if (store_imsm_mpb(d->fd, spare)) {
- pr_err("failed for device %d:%d %s\n",
- d->major, d->minor, strerror(errno));
+ 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 {
(map->map_state == IMSM_T_STATE_NORMAL &&
!(dev->vol.dirty & RAIDVOL_DIRTY)) ||
(is_rebuilding(dev) &&
- dev->vol.curr_migr_unit == 0 &&
+ vol_curr_migr_unit(dev) == 0 &&
get_imsm_disk_idx(dev, disk->disk.raid_disk, MAP_1) != idx))
ret = st->ss->write_init_ppl(st, info, d->fd);
else
return ret;
}
+/*******************************************************************************
+ * Function: write_init_bitmap_imsm_vol
+ * Description: Write a bitmap header and prepares the area for the bitmap.
+ * Parameters:
+ * st : supertype information
+ * vol_idx : the volume index to use
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int write_init_bitmap_imsm_vol(struct supertype *st, int vol_idx)
+{
+ struct intel_super *super = st->sb;
+ int prev_current_vol = super->current_vol;
+ struct dl *d;
+ int ret = 0;
+
+ super->current_vol = vol_idx;
+ for (d = super->disks; d; d = d->next) {
+ if (d->index < 0 || is_failed(&d->disk))
+ continue;
+ ret = st->ss->write_bitmap(st, d->fd, NoUpdate);
+ if (ret)
+ break;
+ }
+ super->current_vol = prev_current_vol;
+ return ret;
+}
+
+/*******************************************************************************
+ * Function: write_init_bitmap_imsm_all
+ * Description: Write a bitmap header and prepares the area for the bitmap.
+ * Operation is executed for volumes with CONSISTENCY_POLICY_BITMAP.
+ * Parameters:
+ * st : supertype information
+ * info : info about the volume where the bitmap should be written
+ * vol_idx : the volume index to use
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int write_init_bitmap_imsm_all(struct supertype *st, struct mdinfo *info,
+ int vol_idx)
+{
+ int ret = 0;
+
+ if (info && (info->consistency_policy == CONSISTENCY_POLICY_BITMAP))
+ ret = write_init_bitmap_imsm_vol(st, vol_idx);
+
+ return ret;
+}
+
static int write_init_super_imsm(struct supertype *st)
{
struct intel_super *super = st->sb;
*/
rv = mgmt_disk(st);
} else {
+ /* adding the second volume to the array */
rv = write_init_ppl_imsm_all(st, &info);
+ if (!rv)
+ rv = write_init_bitmap_imsm_all(st, &info, current_vol);
if (!rv)
rv = create_array(st, current_vol);
}
struct dl *d;
for (d = super->disks; d; d = d->next)
Kill(d->devname, NULL, 0, -1, 1);
- if (current_vol >= 0)
+ if (current_vol >= 0) {
rv = write_init_ppl_imsm_all(st, &info);
+ if (!rv)
+ rv = write_init_bitmap_imsm_all(st, &info, current_vol);
+ }
+
if (!rv)
rv = write_super_imsm(st, 1);
}
}
static int validate_geometry_imsm_container(struct supertype *st, int level,
- int layout, int raiddisks, int chunk,
- unsigned long long size,
+ int raiddisks,
unsigned long long data_offset,
char *dev,
unsigned long long *freesize,
{
int fd;
unsigned long long ldsize;
- struct intel_super *super;
+ struct intel_super *super = NULL;
int rv = 0;
- if (level != LEVEL_CONTAINER)
+ if (!is_container(level))
return 0;
if (!dev)
return 1;
- fd = open(dev, O_RDONLY|O_EXCL, 0);
- if (fd < 0) {
- if (verbose > 0)
- pr_err("imsm: Cannot open %s: %s\n",
- dev, strerror(errno));
- return 0;
- }
- if (!get_dev_size(fd, dev, &ldsize)) {
- close(fd);
+ fd = dev_open(dev, O_RDONLY|O_EXCL);
+ 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))
+ goto exit;
/* capabilities retrieve could be possible
* note that there is no fd for the disks in array.
*/
super = alloc_super();
- if (!super) {
- close(fd);
- return 0;
- }
- if (!get_dev_sector_size(fd, NULL, &super->sector_size)) {
- close(fd);
- free_imsm(super);
- return 0;
- }
+ if (!super)
+ goto exit;
+
+ if (!get_dev_sector_size(fd, NULL, &super->sector_size))
+ goto exit;
rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL);
if (rv != 0) {
fd, str, super->orom, rv, raiddisks);
#endif
/* no orom/efi or non-intel hba of the disk */
- close(fd);
- free_imsm(super);
- return 0;
+ rv = 0;
+ goto exit;
}
- close(fd);
if (super->orom) {
if (raiddisks > super->orom->tds) {
if (verbose)
pr_err("%d exceeds maximum number of platform supported disks: %d\n",
raiddisks, super->orom->tds);
- free_imsm(super);
- return 0;
+ goto exit;
}
if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 &&
(ldsize >> 9) >> 32 > 0) {
if (verbose)
pr_err("%s exceeds maximum platform supported size\n", dev);
- free_imsm(super);
- return 0;
+ goto exit;
}
- }
- *freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
- free_imsm(super);
+ if (super->hba->type == SYS_DEV_VMD ||
+ super->hba->type == SYS_DEV_NVME) {
+ if (!imsm_is_nvme_namespace_supported(fd, 1)) {
+ if (verbose)
+ pr_err("NVMe namespace %s is not supported by IMSM\n",
+ basename(dev));
+ goto exit;
+ }
+ }
+ }
+ if (freesize)
+ *freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
+ rv = 1;
+exit:
+ if (super)
+ free_imsm(super);
+ close(fd);
- return 1;
+ return rv;
}
static unsigned long long find_size(struct extent *e, int *idx, int num_extents)
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);
char *path = NULL;
if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2)
continue;
- path = devt_to_devpath(makedev(major, minor));
+ path = devt_to_devpath(makedev(major, minor), 1, NULL);
if (!path)
continue;
if (!path_attached_to_hba(path, hba_path)) {
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;
if (st->ss != tst->ss ||
st->minor_version != tst->minor_version ||
- st->ss->compare_super(st, tst) != 0) {
+ st->ss->compare_super(st, tst, 1) != 0) {
/* Some mismatch. If exactly one array matches this host,
* we can resolve on that one.
* Or, if we are auto assembling, we just ignore the second
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, layout,
- raiddisks,
- *chunk,
- size, data_offset,
- dev, freesize,
- verbose);
- }
+ return validate_geometry_imsm_container(st, level, raiddisks,
+ data_offset, dev,
+ freesize, verbose);
/*
* Size is given in sectors.
}
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 must be set.
+ */
+ if (!super) {
+ pr_vrb("superblock must be set for autolayout, aborting\n");
+ return 0;
+ }
+
+ if (!validate_geometry_imsm_orom(st->sb, level, layout,
+ raiddisks, chunk, size,
+ verbose))
+ return 0;
+
+ if (super->orom && freesize) {
+ 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;
}
+/**
+ * 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)
+{
+ switch (update) {
+ case UOPT_PPL:
+ return RWH_MULTIPLE_DISTRIBUTED;
+ case UOPT_NO_PPL:
+ return RWH_MULTIPLE_OFF;
+ case UOPT_BITMAP:
+ return RWH_BITMAP;
+ case UOPT_NO_BITMAP:
+ return RWH_OFF;
+ 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 (strcmp(update, "ppl") == 0 ||
- strcmp(update, "no-ppl") == 0) {
+ } else if (get_rwh_policy_from_update(update) != UOPT_UNDEFINED) {
int new_policy;
char *ep;
int vol = strtoul(subarray, &ep, 10);
if (*ep != '\0' || vol >= super->anchor->num_raid_devs)
return 2;
- if (strcmp(update, "ppl") == 0)
- new_policy = RWH_MULTIPLE_DISTRIBUTED;
- else
- new_policy = RWH_MULTIPLE_OFF;
+ new_policy = get_rwh_policy_from_update(update);
if (st->update_tail) {
struct imsm_update_rwh_policy *u = xmalloc(sizeof(*u));
dev->rwh_policy = new_policy;
super->updates_pending++;
}
+ if (new_policy == RWH_BITMAP)
+ return write_init_bitmap_imsm_vol(st, vol);
} else
return 2;
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 (dev && dev->vol.migr_state &&
+ migr_type(dev) == MIGR_GEN_MIGR)
+ return true;
- if (migr_type(dev) == MIGR_GEN_MIGR)
- return 1;
-
- return 0;
+ return false;
}
static int is_rebuilding(struct imsm_dev *dev)
return;
}
- units = __le32_to_cpu(dev->vol.curr_migr_unit);
+ units = vol_curr_migr_unit(dev);
rebuild->recovery_start = units * blocks_per_migr_unit(super, 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) {
prev_num_members = map->num_members;
map->num_members = prev_disks;
dev->vol.migr_state = 1;
- dev->vol.curr_migr_unit = 0;
+ set_vol_curr_migr_unit(dev, 0);
set_migr_type(dev, MIGR_GEN_MIGR);
for (i = prev_num_members;
i < map->num_members; i++)
* We might need to
* - abort the reshape (if last_checkpoint is 0 and action!= reshape)
* - finish the reshape (if last_checkpoint is big and action != reshape)
- * - update curr_migr_unit
+ * - update vol_curr_migr_unit
*/
if (a->curr_action == reshape) {
- /* still reshaping, maybe update curr_migr_unit */
+ /* still reshaping, maybe update vol_curr_migr_unit */
goto mark_checkpoint;
} else {
if (a->last_checkpoint == 0 && a->prev_action == reshape) {
get_imsm_map(dev, MAP_1);
dev->vol.migr_state = 0;
set_migr_type(dev, 0);
- dev->vol.curr_migr_unit = 0;
+ set_vol_curr_migr_unit(dev, 0);
memcpy(map, map2,
sizeof_imsm_map(map2));
super->updates_pending++;
if (is_gen_migration(dev))
goto skip_mark_checkpoint;
- /* check if we can update curr_migr_unit from resync_start, recovery_start */
+ /* check if we can update vol_curr_migr_unit from resync_start,
+ * recovery_start
+ */
blocks_per_unit = blocks_per_migr_unit(super, dev);
if (blocks_per_unit) {
- __u32 units32;
- __u64 units;
-
- units = a->last_checkpoint / blocks_per_unit;
- units32 = units;
-
- /* check that we did not overflow 32-bits, and that
- * curr_migr_unit needs updating
- */
- if (units32 == units &&
- units32 != 0 &&
- __le32_to_cpu(dev->vol.curr_migr_unit) != units32) {
- dprintf("imsm: mark checkpoint (%u)\n", units32);
- dev->vol.curr_migr_unit = __cpu_to_le32(units32);
- super->updates_pending++;
- }
+ set_vol_curr_migr_unit(dev,
+ a->last_checkpoint / blocks_per_unit);
+ dprintf("imsm: mark checkpoint (%llu)\n",
+ vol_curr_migr_unit(dev));
+ super->updates_pending++;
}
skip_mark_checkpoint:
break;
}
end_migration(dev, super, map_state);
- map = get_imsm_map(dev, MAP_0);
map->failed_disk_num = ~0;
super->updates_pending++;
a->last_checkpoint = 0;
end_migration(dev, super, map_state);
else
map->map_state = map_state;
- map = get_imsm_map(dev, MAP_0);
map->failed_disk_num = ~0;
super->updates_pending++;
break;
unsigned long long sectors;
unsigned int sector_size;
- get_dev_sector_size(fd, NULL, §or_size);
+ if (!get_dev_sector_size(fd, NULL, §or_size))
+ return 1;
get_dev_size(fd, NULL, &dsize);
if (mpb_size > sector_size) {
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;
/*
else
super->disks = dl->next;
dl->next = NULL;
- __free_imsm_disk(dl);
+ __free_imsm_disk(dl, 1);
dprintf("removed %x:%x\n", major, minor);
break;
}
}
}
/* release allocate disk structure */
- __free_imsm_disk(disk_cfg);
+ __free_imsm_disk(disk_cfg, 1);
}
}
return check_degraded;
/* 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;
}
return ret_val;
}
-static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
- struct intel_super *super,
- struct active_array *active_array)
+static int prepare_spare_to_activate(struct supertype *st,
+ struct imsm_update_activate_spare *u)
{
- struct imsm_super *mpb = super->anchor;
- struct imsm_dev *dev = get_imsm_dev(super, u->array);
- struct imsm_map *map = get_imsm_map(dev, MAP_0);
- struct imsm_map *migr_map;
+ struct intel_super *super = st->sb;
+ int prev_current_vol = super->current_vol;
struct active_array *a;
- struct imsm_disk *disk;
- __u8 to_state;
+ int ret = 1;
+
+ for (a = st->arrays; a; a = a->next)
+ /*
+ * Additional initialization (adding bitmap header, filling
+ * the bitmap area with '1's to force initial rebuild for a whole
+ * data-area) is required when adding the spare to the volume
+ * with write-intent bitmap.
+ */
+ if (a->info.container_member == u->array &&
+ a->info.consistency_policy == CONSISTENCY_POLICY_BITMAP) {
+ struct dl *dl;
+
+ for (dl = super->disks; dl; dl = dl->next)
+ if (dl == u->dl)
+ break;
+ if (!dl)
+ break;
+
+ super->current_vol = u->array;
+ if (st->ss->write_bitmap(st, dl->fd, NoUpdate))
+ ret = 0;
+ super->current_vol = prev_current_vol;
+ }
+ return ret;
+}
+
+static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
+ struct intel_super *super,
+ struct active_array *active_array)
+{
+ struct imsm_super *mpb = super->anchor;
+ struct imsm_dev *dev = get_imsm_dev(super, u->array);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ struct imsm_map *migr_map;
+ struct active_array *a;
+ struct imsm_disk *disk;
+ __u8 to_state;
struct dl *dl;
unsigned int found;
int failed;
/* 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++;
}
id->index);
devices_to_reshape--;
newdev->vol.migr_state = 1;
- newdev->vol.curr_migr_unit = 0;
+ set_vol_curr_migr_unit(newdev, 0);
set_migr_type(newdev, MIGR_GEN_MIGR);
newmap->num_members = u->new_raid_disks;
for (i = 0; i < delta_disks; i++) {
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;
/* find device under general migration */
for (id = super->devlist ; id; id = id->next) {
if (is_gen_migration(id->dev)) {
- id->dev->vol.curr_migr_unit =
- __cpu_to_le32(u->curr_migr_unit);
+ set_vol_curr_migr_unit(id->dev,
+ u->curr_migr_unit);
super->updates_pending++;
}
}
}
case update_activate_spare: {
struct imsm_update_activate_spare *u = (void *) update->buf;
- if (apply_update_activate_spare(u, super, st->arrays))
+
+ if (prepare_spare_to_activate(st, u) &&
+ apply_update_activate_spare(u, super, st->arrays))
super->updates_pending++;
break;
}
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;
struct dl *dl = *dlp;
*dlp = (*dlp)->next;
- __free_imsm_disk(dl);
- }
-}
-
-static void close_targets(int *targets, int new_disks)
-{
- int i;
-
- if (!targets)
- return;
-
- for (i = 0; i < new_disks; i++) {
- if (targets[i] >= 0) {
- close(targets[i]);
- targets[i] = -1;
- }
+ __free_imsm_disk(dl, 1);
}
}
}
}
-/*******************************************************************************
- * Function: open_backup_targets
- * Description: Function opens file descriptors for all devices given in
- * info->devs
- * Parameters:
- * info : general array info
- * raid_disks : number of disks
- * raid_fds : table of device's file descriptors
- * super : intel super for raid10 degradation check
- * dev : intel device for raid10 degradation check
- * Returns:
- * 0 : success
- * -1 : fail
- ******************************************************************************/
-int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
- struct intel_super *super, struct imsm_dev *dev)
-{
- struct mdinfo *sd;
- int i;
- int opened = 0;
-
- for (i = 0; i < raid_disks; i++)
- raid_fds[i] = -1;
-
- for (sd = info->devs ; sd ; sd = sd->next) {
- char *dn;
-
- if (sd->disk.state & (1<<MD_DISK_FAULTY)) {
- dprintf("disk is faulty!!\n");
- continue;
- }
-
- if (sd->disk.raid_disk >= raid_disks || sd->disk.raid_disk < 0)
- continue;
-
- dn = map_dev(sd->disk.major,
- sd->disk.minor, 1);
- raid_fds[sd->disk.raid_disk] = dev_open(dn, O_RDWR);
- if (raid_fds[sd->disk.raid_disk] < 0) {
- pr_err("cannot open component\n");
- continue;
- }
- opened++;
- }
- /* check if maximum array degradation level is not exceeded
- */
- if ((raid_disks - opened) >
- imsm_get_allowed_degradation(info->new_level, raid_disks,
- super, dev)) {
- pr_err("Not enough disks can be opened.\n");
- close_targets(raid_fds, raid_disks);
- return -2;
- }
- return 0;
-}
-
/*******************************************************************************
* Function: validate_container_imsm
* Description: This routine validates container after assemble,
******************************************************************************/
int validate_container_imsm(struct mdinfo *info)
{
- if (check_env("IMSM_NO_PLATFORM"))
+ if (check_no_platform())
return 0;
struct sys_dev *idev;
struct sys_dev *hba = NULL;
struct sys_dev *intel_devices = find_intel_devices();
char *dev_path = devt_to_devpath(makedev(info->disk.major,
- info->disk.minor));
+ info->disk.minor), 1, NULL);
for (idev = intel_devices; idev; idev = idev->next) {
if (dev_path && strstr(dev_path, idev->path)) {
struct mdinfo *dev;
for (dev = info->next; dev; dev = dev->next) {
- dev_path = devt_to_devpath(makedev(dev->disk.major, dev->disk.minor));
+ dev_path = devt_to_devpath(makedev(dev->disk.major,
+ dev->disk.minor), 1, NULL);
struct sys_dev *hba2 = NULL;
for (idev = intel_devices; idev; idev = idev->next) {
int new_data_disks;
unsigned long long dsize, dev_sectors;
long long unsigned min_dev_sectors = -1LLU;
- struct mdinfo *sd;
- char nm[30];
- int fd;
struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
struct imsm_map *map_src = get_imsm_map(dev, MAP_1);
unsigned long long num_migr_units;
unsigned long long array_blocks;
+ struct dl *dl_disk = NULL;
memset(migr_rec, 0, sizeof(struct migr_record));
migr_rec->family_num = __cpu_to_le32(super->anchor->family_num);
migr_rec->post_migr_vol_cap_hi = dev->size_high;
/* Find the smallest dev */
- for (sd = info->devs ; sd ; sd = sd->next) {
- sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
- fd = dev_open(nm, O_RDONLY);
- if (fd < 0)
+ for (dl_disk = super->disks; dl_disk ; dl_disk = dl_disk->next) {
+ /* ignore spares in container */
+ if (dl_disk->index < 0)
continue;
- get_dev_size(fd, NULL, &dsize);
+ get_dev_size(dl_disk->fd, NULL, &dsize);
dev_sectors = dsize / 512;
if (dev_sectors < min_dev_sectors)
min_dev_sectors = dev_sectors;
- close(fd);
}
set_migr_chkp_area_pba(migr_rec, min_dev_sectors -
RAID_DISK_RESERVED_BLOCKS_IMSM_HI);
{
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++)
- targets[i] = -1;
-
- target_offsets = xcalloc(new_disks, sizeof(unsigned long long));
+ for (i = 0; i < new_disks; i++) {
+ struct dl *dl_disk = get_imsm_dl_disk(super, i);
+ if (dl_disk && is_fd_valid(dl_disk->fd))
+ targets[i] = dl_disk->fd;
+ else
+ goto abort;
+ }
start = info->reshape_progress * 512;
for (i = 0; i < new_disks; i++) {
target_offsets[i] -= start/data_disks;
}
- if (open_backup_targets(info, new_disks, targets,
- super, dev))
- goto abort;
-
dest_layout = imsm_level_to_layout(map_dest->raid_level);
dest_chunk = __le16_to_cpu(map_dest->blocks_per_strip) * 512;
rv = 0;
abort:
- if (targets) {
- close_targets(targets, new_disks);
- free(targets);
- }
- free(target_offsets);
-
return rv;
}
unsigned long long blocks_per_unit;
unsigned long long curr_migr_unit;
- if (load_imsm_migr_rec(super, info) != 0) {
+ if (load_imsm_migr_rec(super) != 0) {
dprintf("imsm: ERROR: Cannot read migration record for checkpoint save.\n");
return 1;
}
unsigned long long read_offset;
unsigned long long write_offset;
unsigned unit_len;
- int *targets = NULL;
- int new_disks, i, err;
+ int new_disks, err;
char *buf = NULL;
int retval = 1;
unsigned int sector_size = super->sector_size;
- unsigned long curr_migr_unit = current_migr_unit(migr_rec);
- unsigned long num_migr_units = get_num_migr_units(migr_rec);
+ unsigned long long curr_migr_unit = current_migr_unit(migr_rec);
+ unsigned long long num_migr_units = get_num_migr_units(migr_rec);
char buffer[20];
int skipped_disks = 0;
+ struct dl *dl_disk;
err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, 20);
if (err < 1)
unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
if (posix_memalign((void **)&buf, sector_size, unit_len) != 0)
goto abort;
- targets = xcalloc(new_disks, sizeof(int));
- if (open_backup_targets(info, new_disks, targets, super, id->dev)) {
- pr_err("Cannot open some devices belonging to array.\n");
- goto abort;
- }
+ for (dl_disk = super->disks; dl_disk; dl_disk = dl_disk->next) {
+ if (dl_disk->index < 0)
+ continue;
- for (i = 0; i < new_disks; i++) {
- if (targets[i] < 0) {
+ if (!is_fd_valid(dl_disk->fd)) {
skipped_disks++;
continue;
}
- if (lseek64(targets[i], read_offset, SEEK_SET) < 0) {
+ if (lseek64(dl_disk->fd, read_offset, SEEK_SET) < 0) {
pr_err("Cannot seek to block: %s\n",
strerror(errno));
skipped_disks++;
continue;
}
- if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
+ if (read(dl_disk->fd, buf, unit_len) != (ssize_t)unit_len) {
pr_err("Cannot read copy area block: %s\n",
strerror(errno));
skipped_disks++;
continue;
}
- if (lseek64(targets[i], write_offset, SEEK_SET) < 0) {
+ if (lseek64(dl_disk->fd, write_offset, SEEK_SET) < 0) {
pr_err("Cannot seek to block: %s\n",
strerror(errno));
skipped_disks++;
continue;
}
- if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
+ if (write(dl_disk->fd, buf, unit_len) != (ssize_t)unit_len) {
pr_err("Cannot restore block: %s\n",
strerror(errno));
skipped_disks++;
retval = 0;
abort:
- if (targets) {
- for (i = 0; i < new_disks; i++)
- if (targets[i])
- close(targets[i]);
- free(targets);
- }
free(buf);
return retval;
}
struct sys_dev* hba;
char *path;
- path = devt_to_devpath(st.st_rdev);
+ path = devt_to_devpath(st.st_rdev, 1, NULL);
if (path == NULL)
return "unknown";
hba = find_disk_attached_hba(-1, path);
{
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;
}
}
return 0;
}
+/* Flush size update if size calculated by num_data_stripes is higher than
+ * imsm_dev_size to eliminate differences during reshape.
+ * Mdmon will recalculate them correctly.
+ * If subarray index is not set then check whole container.
+ * Returns:
+ * 0 - no error occurred
+ * 1 - error detected
+ */
+static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
+{
+ struct intel_super *super = st->sb;
+ int tmp = super->current_vol;
+ int ret_val = 1;
+ int i;
+
+ for (i = 0; i < super->anchor->num_raid_devs; i++) {
+ if (subarray_index >= 0 && i != subarray_index)
+ continue;
+ super->current_vol = i;
+ struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ unsigned int disc_count = imsm_num_data_members(map);
+ struct geo_params geo;
+ struct imsm_update_size_change *update;
+ unsigned long long calc_size = per_dev_array_size(map) * disc_count;
+ unsigned long long d_size = imsm_dev_size(dev);
+ int u_size;
+
+ if (calc_size == d_size)
+ continue;
+
+ /* There is a difference, confirm that imsm_dev_size is
+ * smaller and push update.
+ */
+ if (d_size > calc_size) {
+ pr_err("imsm: dev size of subarray %d is incorrect\n",
+ i);
+ goto exit;
+ }
+ memset(&geo, 0, sizeof(struct geo_params));
+ geo.size = d_size;
+ u_size = imsm_create_metadata_update_for_size_change(st, &geo,
+ &update);
+ imsm_update_metadata_locally(st, update, u_size);
+ if (st->update_tail) {
+ append_metadata_update(st, update, u_size);
+ flush_metadata_updates(st);
+ st->update_tail = &st->updates;
+ } else {
+ imsm_sync_metadata(st);
+ free(update);
+ }
+ }
+ ret_val = 0;
+exit:
+ super->current_vol = tmp;
+ return ret_val;
+}
+
static int imsm_reshape_super(struct supertype *st, unsigned long long size,
int level,
int layout, int chunksize, int raid_disks,
struct imsm_update_reshape *u = NULL;
int len;
+ if (imsm_fix_size_mismatch(st, -1)) {
+ dprintf("imsm: Cannot fix size mismatch\n");
+ goto exit_imsm_reshape_super;
+ }
+
len = imsm_create_metadata_update_for_reshape(
st, &geo, old_raid_disks, &u);
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++;
}
}
unsigned long long start_buf_shift; /* [bytes] */
int degraded = 0;
int source_layout = 0;
+ int subarray_index = -1;
if (!sra)
return ret_val;
dv->dev->vol.migr_state == 1) {
dev = dv->dev;
migr_vol_qan++;
+ subarray_index = dv->index;
}
}
/* Only one volume can migrate at the same time */
/* return '1' if done */
ret_val = 1;
+
+ /* After the reshape eliminate size mismatch in metadata.
+ * Don't update md/component_size here, volume hasn't
+ * to take whole space. It is allowed by kernel.
+ * md/component_size will be set propoperly after next assembly.
+ */
+ imsm_fix_size_mismatch(st, subarray_index);
+
abort:
free(buf);
/* See Grow.c: abort_reshape() for further explanation */
return ret_val;
}
+/*******************************************************************************
+ * Function: calculate_bitmap_min_chunksize
+ * Description: Calculates the minimal valid bitmap chunk size
+ * Parameters:
+ * max_bits : indicate how many bits can be used for the bitmap
+ * data_area_size : the size of the data area covered by the bitmap
+ *
+ * Returns:
+ * The bitmap chunk size
+ ******************************************************************************/
+static unsigned long long
+calculate_bitmap_min_chunksize(unsigned long long max_bits,
+ unsigned long long data_area_size)
+{
+ unsigned long long min_chunk =
+ 4096; /* sub-page chunks don't work yet.. */
+ unsigned long long bits = data_area_size / min_chunk + 1;
+
+ while (bits > max_bits) {
+ min_chunk *= 2;
+ bits = (bits + 1) / 2;
+ }
+ return min_chunk;
+}
+
+/*******************************************************************************
+ * Function: calculate_bitmap_chunksize
+ * Description: Calculates the bitmap chunk size for the given device
+ * Parameters:
+ * st : supertype information
+ * dev : device for the bitmap
+ *
+ * Returns:
+ * The bitmap chunk size
+ ******************************************************************************/
+static unsigned long long calculate_bitmap_chunksize(struct supertype *st,
+ struct imsm_dev *dev)
+{
+ struct intel_super *super = st->sb;
+ unsigned long long min_chunksize;
+ unsigned long long result = IMSM_DEFAULT_BITMAP_CHUNKSIZE;
+ size_t dev_size = imsm_dev_size(dev);
+
+ min_chunksize = calculate_bitmap_min_chunksize(
+ IMSM_BITMAP_AREA_SIZE * super->sector_size, dev_size);
+
+ if (result < min_chunksize)
+ result = min_chunksize;
+
+ return result;
+}
+
+/*******************************************************************************
+ * Function: init_bitmap_header
+ * Description: Initialize the bitmap header structure
+ * Parameters:
+ * st : supertype information
+ * bms : bitmap header struct to initialize
+ * dev : device for the bitmap
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int init_bitmap_header(struct supertype *st, struct bitmap_super_s *bms,
+ struct imsm_dev *dev)
+{
+ int vol_uuid[4];
+
+ if (!bms || !dev)
+ return -1;
+
+ bms->magic = __cpu_to_le32(BITMAP_MAGIC);
+ bms->version = __cpu_to_le32(BITMAP_MAJOR_HI);
+ bms->daemon_sleep = __cpu_to_le32(IMSM_DEFAULT_BITMAP_DAEMON_SLEEP);
+ bms->sync_size = __cpu_to_le64(IMSM_BITMAP_AREA_SIZE);
+ bms->write_behind = __cpu_to_le32(0);
+
+ uuid_from_super_imsm(st, vol_uuid);
+ memcpy(bms->uuid, vol_uuid, 16);
+
+ bms->chunksize = calculate_bitmap_chunksize(st, dev);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Function: validate_internal_bitmap_for_drive
+ * Description: Verify if the bitmap header for a given drive.
+ * Parameters:
+ * st : supertype information
+ * offset : The offset from the beginning of the drive where to look for
+ * the bitmap header.
+ * d : the drive info
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int validate_internal_bitmap_for_drive(struct supertype *st,
+ unsigned long long offset,
+ struct dl *d)
+{
+ struct intel_super *super = st->sb;
+ int ret = -1;
+ int vol_uuid[4];
+ bitmap_super_t *bms;
+ int fd;
+
+ if (!d)
+ return -1;
+
+ void *read_buf;
+
+ if (posix_memalign(&read_buf, MAX_SECTOR_SIZE, IMSM_BITMAP_HEADER_SIZE))
+ return -1;
+
+ fd = d->fd;
+ if (!is_fd_valid(fd)) {
+ fd = open(d->devname, O_RDONLY, 0);
+
+ if (!is_fd_valid(fd)) {
+ dprintf("cannot open the device %s\n", d->devname);
+ goto abort;
+ }
+ }
+
+ if (lseek64(fd, offset * super->sector_size, SEEK_SET) < 0)
+ goto abort;
+ if (read(fd, read_buf, IMSM_BITMAP_HEADER_SIZE) !=
+ IMSM_BITMAP_HEADER_SIZE)
+ goto abort;
+
+ uuid_from_super_imsm(st, vol_uuid);
+
+ bms = read_buf;
+ if ((bms->magic != __cpu_to_le32(BITMAP_MAGIC)) ||
+ (bms->version != __cpu_to_le32(BITMAP_MAJOR_HI)) ||
+ (!same_uuid((int *)bms->uuid, vol_uuid, st->ss->swapuuid))) {
+ dprintf("wrong bitmap header detected\n");
+ goto abort;
+ }
+
+ ret = 0;
+abort:
+ if (!is_fd_valid(d->fd))
+ close_fd(&fd);
+
+ if (read_buf)
+ free(read_buf);
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Function: validate_internal_bitmap_imsm
+ * Description: Verify if the bitmap header is in place and with proper data.
+ * Parameters:
+ * st : supertype information
+ *
+ * Returns:
+ * 0 : success or device w/o RWH_BITMAP
+ * -1 : fail
+ ******************************************************************************/
+static int validate_internal_bitmap_imsm(struct supertype *st)
+{
+ struct intel_super *super = st->sb;
+ struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+ unsigned long long offset;
+ struct dl *d;
+
+ if (dev->rwh_policy != RWH_BITMAP)
+ return 0;
+
+ offset = get_bitmap_header_sector(super, super->current_vol);
+ for (d = super->disks; d; d = d->next) {
+ if (d->index < 0 || is_failed(&d->disk))
+ continue;
+
+ if (validate_internal_bitmap_for_drive(st, offset, d)) {
+ pr_err("imsm: bitmap validation failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ * Function: add_internal_bitmap_imsm
+ * Description: Mark the volume to use the bitmap and updates the chunk size value.
+ * Parameters:
+ * st : supertype information
+ * chunkp : bitmap chunk size
+ * delay : not used for imsm
+ * write_behind : not used for imsm
+ * size : not used for imsm
+ * may_change : not used for imsm
+ * amajor : not used for imsm
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int add_internal_bitmap_imsm(struct supertype *st, int *chunkp,
+ int delay, int write_behind,
+ unsigned long long size, int may_change,
+ int amajor)
+{
+ struct intel_super *super = st->sb;
+ int vol_idx = super->current_vol;
+ struct imsm_dev *dev;
+
+ if (!super->devlist || vol_idx == -1 || !chunkp)
+ return -1;
+
+ dev = get_imsm_dev(super, vol_idx);
+ dev->rwh_policy = RWH_BITMAP;
+ *chunkp = calculate_bitmap_chunksize(st, dev);
+ return 0;
+}
+
+/*******************************************************************************
+ * Function: locate_bitmap_imsm
+ * Description: Seek 'fd' to start of write-intent-bitmap.
+ * Parameters:
+ * st : supertype information
+ * fd : file descriptor for the device
+ * node_num : not used for imsm
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int locate_bitmap_imsm(struct supertype *st, int fd, int node_num)
+{
+ struct intel_super *super = st->sb;
+ unsigned long long offset;
+ int vol_idx = super->current_vol;
+
+ if (!super->devlist || vol_idx == -1)
+ return -1;
+
+ offset = get_bitmap_header_sector(super, super->current_vol);
+ dprintf("bitmap header offset is %llu\n", offset);
+
+ lseek64(fd, offset << 9, 0);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Function: write_init_bitmap_imsm
+ * Description: Write a bitmap header and prepares the area for the bitmap.
+ * Parameters:
+ * st : supertype information
+ * fd : file descriptor for the device
+ * update : not used for imsm
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int write_init_bitmap_imsm(struct supertype *st, int fd,
+ enum bitmap_update update)
+{
+ struct intel_super *super = st->sb;
+ int vol_idx = super->current_vol;
+ int ret = 0;
+ unsigned long long offset;
+ bitmap_super_t bms = { 0 };
+ size_t written = 0;
+ size_t to_write;
+ ssize_t rv_num;
+ void *buf;
+
+ if (!super->devlist || !super->sector_size || vol_idx == -1)
+ return -1;
+
+ struct imsm_dev *dev = get_imsm_dev(super, vol_idx);
+
+ /* first clear the space for bitmap header */
+ unsigned long long bitmap_area_start =
+ get_bitmap_header_sector(super, vol_idx);
+
+ dprintf("zeroing area start (%llu) and size (%u)\n", bitmap_area_start,
+ IMSM_BITMAP_AND_HEADER_SIZE / super->sector_size);
+ if (zero_disk_range(fd, bitmap_area_start,
+ IMSM_BITMAP_HEADER_SIZE / super->sector_size)) {
+ pr_err("imsm: cannot zeroing the space for the bitmap\n");
+ return -1;
+ }
+
+ /* The bitmap area should be filled with "1"s to perform initial
+ * synchronization.
+ */
+ if (posix_memalign(&buf, MAX_SECTOR_SIZE, MAX_SECTOR_SIZE))
+ return -1;
+ memset(buf, 0xFF, MAX_SECTOR_SIZE);
+ offset = get_bitmap_sector(super, vol_idx);
+ lseek64(fd, offset << 9, 0);
+ while (written < IMSM_BITMAP_AREA_SIZE) {
+ to_write = IMSM_BITMAP_AREA_SIZE - written;
+ if (to_write > MAX_SECTOR_SIZE)
+ to_write = MAX_SECTOR_SIZE;
+ rv_num = write(fd, buf, MAX_SECTOR_SIZE);
+ if (rv_num != MAX_SECTOR_SIZE) {
+ ret = -1;
+ dprintf("cannot initialize bitmap area\n");
+ goto abort;
+ }
+ written += rv_num;
+ }
+
+ /* write a bitmap header */
+ init_bitmap_header(st, &bms, dev);
+ memset(buf, 0, MAX_SECTOR_SIZE);
+ memcpy(buf, &bms, sizeof(bitmap_super_t));
+ if (locate_bitmap_imsm(st, fd, 0)) {
+ ret = -1;
+ dprintf("cannot locate the bitmap\n");
+ goto abort;
+ }
+ if (write(fd, buf, MAX_SECTOR_SIZE) != MAX_SECTOR_SIZE) {
+ ret = -1;
+ dprintf("cannot write the bitmap header\n");
+ goto abort;
+ }
+ fsync(fd);
+
+abort:
+ free(buf);
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Function: is_vol_to_setup_bitmap
+ * Description: Checks if a bitmap should be activated on the dev.
+ * Parameters:
+ * info : info about the volume to setup the bitmap
+ * dev : the device to check against bitmap creation
+ *
+ * Returns:
+ * 0 : bitmap should be set up on the device
+ * -1 : otherwise
+ ******************************************************************************/
+static int is_vol_to_setup_bitmap(struct mdinfo *info, struct imsm_dev *dev)
+{
+ if (!dev || !info)
+ return -1;
+
+ if ((strcmp((char *)dev->volume, info->name) == 0) &&
+ (dev->rwh_policy == RWH_BITMAP))
+ return -1;
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Function: set_bitmap_sysfs
+ * Description: Set the sysfs atributes of a given volume to activate the bitmap.
+ * Parameters:
+ * info : info about the volume where the bitmap should be setup
+ * chunksize : bitmap chunk size
+ * location : location of the bitmap
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int set_bitmap_sysfs(struct mdinfo *info, unsigned long long chunksize,
+ char *location)
+{
+ /* The bitmap/metadata is set to external to allow changing of value for
+ * bitmap/location. When external is used, the kernel will treat an offset
+ * related to the device's first lba (in opposition to the "internal" case
+ * when this value is related to the beginning of the superblock).
+ */
+ if (sysfs_set_str(info, NULL, "bitmap/metadata", "external")) {
+ dprintf("failed to set bitmap/metadata\n");
+ return -1;
+ }
+
+ /* It can only be changed when no bitmap is active.
+ * Should be bigger than 512 and must be power of 2.
+ * It is expecting the value in bytes.
+ */
+ if (sysfs_set_num(info, NULL, "bitmap/chunksize",
+ __cpu_to_le32(chunksize))) {
+ dprintf("failed to set bitmap/chunksize\n");
+ return -1;
+ }
+
+ /* It is expecting the value in sectors. */
+ if (sysfs_set_num(info, NULL, "bitmap/space",
+ __cpu_to_le64(IMSM_BITMAP_AREA_SIZE))) {
+ dprintf("failed to set bitmap/space\n");
+ return -1;
+ }
+
+ /* Determines the delay between the bitmap updates.
+ * It is expecting the value in seconds.
+ */
+ if (sysfs_set_num(info, NULL, "bitmap/time_base",
+ __cpu_to_le64(IMSM_DEFAULT_BITMAP_DAEMON_SLEEP))) {
+ dprintf("failed to set bitmap/time_base\n");
+ return -1;
+ }
+
+ /* It is expecting the value in sectors with a sign at the beginning. */
+ if (sysfs_set_str(info, NULL, "bitmap/location", location)) {
+ dprintf("failed to set bitmap/location\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Function: set_bitmap_imsm
+ * Description: Setup the bitmap for the given volume
+ * Parameters:
+ * st : supertype information
+ * info : info about the volume where the bitmap should be setup
+ *
+ * Returns:
+ * 0 : success
+ * -1 : fail
+ ******************************************************************************/
+static int set_bitmap_imsm(struct supertype *st, struct mdinfo *info)
+{
+ struct intel_super *super = st->sb;
+ int prev_current_vol = super->current_vol;
+ struct imsm_dev *dev;
+ int ret = -1;
+ char location[16] = "";
+ unsigned long long chunksize;
+ struct intel_dev *dev_it;
+
+ for (dev_it = super->devlist; dev_it; dev_it = dev_it->next) {
+ super->current_vol = dev_it->index;
+ dev = get_imsm_dev(super, super->current_vol);
+
+ if (is_vol_to_setup_bitmap(info, dev)) {
+ if (validate_internal_bitmap_imsm(st)) {
+ dprintf("bitmap header validation failed\n");
+ goto abort;
+ }
+
+ chunksize = calculate_bitmap_chunksize(st, dev);
+ dprintf("chunk size is %llu\n", chunksize);
+
+ snprintf(location, sizeof(location), "+%llu",
+ get_bitmap_sector(super, super->current_vol));
+ dprintf("bitmap offset is %s\n", location);
+
+ if (set_bitmap_sysfs(info, chunksize, location)) {
+ dprintf("cannot setup the bitmap\n");
+ goto abort;
+ }
+ }
+ }
+ ret = 0;
+abort:
+ super->current_vol = prev_current_vol;
+ return ret;
+}
+
struct superswitch super_imsm = {
.examine_super = examine_super_imsm,
.brief_examine_super = brief_examine_super_imsm,
.container_content = container_content_imsm,
.validate_container = validate_container_imsm,
+ .add_internal_bitmap = add_internal_bitmap_imsm,
+ .locate_bitmap = locate_bitmap_imsm,
+ .write_bitmap = write_init_bitmap_imsm,
+ .set_bitmap = set_bitmap_imsm,
+
.write_init_ppl = write_init_ppl_imsm,
.validate_ppl = validate_ppl_imsm,