#define IMSM_MAX_DEVICES 255
struct imsm_disk {
__u8 serial[MAX_RAID_SERIAL_LEN];/* 0xD8 - 0xE7 ascii serial number */
- __u32 total_blocks; /* 0xE8 - 0xEB total blocks */
+ __u32 total_blocks_lo; /* 0xE8 - 0xEB total blocks lo */
__u32 scsi_id; /* 0xEC - 0xEF scsi ID */
#define SPARE_DISK __cpu_to_le32(0x01) /* Spare */
#define CONFIGURED_DISK __cpu_to_le32(0x02) /* Member of some RaidDev */
#define FAILED_DISK __cpu_to_le32(0x04) /* Permanent failure */
__u32 status; /* 0xF0 - 0xF3 */
- __u32 owner_cfg_num; /* which config 0,1,2... owns this disk */
-#define IMSM_DISK_FILLERS 4
- __u32 filler[IMSM_DISK_FILLERS]; /* 0xF4 - 0x107 MPB_DISK_FILLERS for future expansion */
+ __u32 owner_cfg_num; /* which config 0,1,2... owns this disk */
+ __u32 total_blocks_hi; /* 0xF4 - 0xF5 total blocks hi */
+#define IMSM_DISK_FILLERS 3
+ __u32 filler[IMSM_DISK_FILLERS]; /* 0xF5 - 0x107 MPB_DISK_FILLERS for future expansion */
};
/* map selector for map managment
/* RAID map configuration infos. */
struct imsm_map {
- __u32 pba_of_lba0; /* start address of partition */
- __u32 blocks_per_member;/* blocks per member */
- __u32 num_data_stripes; /* number of data stripes */
+ __u32 pba_of_lba0_lo; /* start address of partition */
+ __u32 blocks_per_member_lo;/* blocks per member */
+ __u32 num_data_stripes_lo; /* number of data stripes */
__u16 blocks_per_strip;
__u8 map_state; /* Normal, Uninitialized, Degraded, Failed */
#define IMSM_T_STATE_NORMAL 0
__u8 num_domains; /* number of parity domains */
__u8 failed_disk_num; /* valid only when state is degraded */
__u8 ddf;
- __u32 filler[7]; /* expansion area */
+ __u32 pba_of_lba0_hi;
+ __u32 blocks_per_member_hi;
+ __u32 num_data_stripes_hi;
+ __u32 filler[4]; /* expansion area */
#define IMSM_ORD_REBUILD (1 << 24)
__u32 disk_ord_tbl[1]; /* disk_ord_tbl[num_members],
* top byte contains some flags
struct bbm_log_entry mapped_block_entries[BBM_LOG_MAX_ENTRIES];
} __attribute__ ((__packed__));
-
#ifndef MDASSEMBLE
static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" };
#endif
* MIGR_REC_BUF_SIZE <= MIGR_REC_POSITION
*/
-
#define UNIT_SRC_NORMAL 0 /* Source data for curr_migr_unit must
* be recovered using srcMap */
#define UNIT_SRC_IN_CP_AREA 1 /* Source data for curr_migr_unit has
struct md_list *next;
};
-#define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
+#define pr_vrb(fmt, arg...) (void) (verbose && pr_err(fmt, ##arg))
static __u8 migr_type(struct imsm_dev *dev)
{
size_t next_len;
int updates_pending; /* count of pending updates for mdmon */
int current_vol; /* index of raid device undergoing creation */
- __u32 create_offset; /* common start for 'current_vol' */
+ unsigned long long create_offset; /* common start for 'current_vol' */
__u32 random; /* random data for seeding new family numbers */
struct intel_dev *devlist;
struct dl {
enum imsm_reshape_type {
CH_TAKEOVER,
CH_MIGRATION,
+ CH_ARRAY_SIZE,
};
/* definition of messages passed to imsm_process_update */
update_reshape_migration,
update_takeover,
update_general_migration_checkpoint,
+ update_size_change,
};
struct imsm_update_activate_spare {
};
struct geo_params {
- int dev_id;
+ char devnm[32];
char *dev_name;
- long long size;
+ unsigned long long size;
int level;
int layout;
int chunksize;
int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
};
+struct imsm_update_size_change {
+ enum imsm_update_type type;
+ int subdev;
+ long long new_size;
+};
+
struct imsm_update_general_migration_checkpoint {
enum imsm_update_type type;
__u32 curr_migr_unit;
enum imsm_update_type type;
};
-
static const char *_sys_dev_type[] = {
[SYS_DEV_UNKNOWN] = "Unknown",
[SYS_DEV_SAS] = "SAS",
static struct intel_hba * alloc_intel_hba(struct sys_dev *device)
{
- struct intel_hba *result = malloc(sizeof(*result));
- if (result) {
- result->type = device->type;
- result->path = strdup(device->path);
- result->next = NULL;
- if (result->path && (result->pci_id = strrchr(result->path, '/')) != NULL)
- result->pci_id++;
- }
+ struct intel_hba *result = xmalloc(sizeof(*result));
+
+ result->type = device->type;
+ result->path = xstrdup(device->path);
+ result->next = NULL;
+ if (result->path && (result->pci_id = strrchr(result->path, '/')) != NULL)
+ result->pci_id++;
+
return result;
}
if (super->hba == NULL) {
super->hba = alloc_intel_hba(device);
return 1;
- }
-
- hba = super->hba;
- /* Intel metadata allows for all disks attached to the same type HBA.
- * Do not sypport odf HBA types mixing
- */
- if (device->type != hba->type)
+ } else
+ /* IMSM metadata disallows to attach disks to multiple
+ * controllers.
+ */
return 2;
-
- while (hba->next)
- hba = hba->next;
-
- hba->next = alloc_intel_hba(device);
- return 1;
}
static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
{
- struct sys_dev *list, *elem, *prev;
+ struct sys_dev *list, *elem;
char *disk_path;
if ((list = find_intel_devices()) == NULL)
else
disk_path = diskfd_to_devpath(fd);
- if (!disk_path) {
- free_sys_dev(&list);
+ if (!disk_path)
return 0;
- }
- for (prev = NULL, elem = list; elem; prev = elem, elem = elem->next) {
- if (path_attached_to_hba(disk_path, elem->path)) {
- if (prev == NULL)
- list = list->next;
- else
- prev->next = elem->next;
- elem->next = NULL;
- if (disk_path != devname)
- free(disk_path);
- free_sys_dev(&list);
+ for (elem = list; elem; elem = elem->next)
+ if (path_attached_to_hba(disk_path, elem->path))
return elem;
- }
- }
+
if (disk_path != devname)
free(disk_path);
- free_sys_dev(&list);
return NULL;
}
-
static int find_intel_hba_capability(int fd, struct intel_super *super,
char *devname);
)
return NULL;
- st = malloc(sizeof(*st));
- if (!st)
- return NULL;
- memset(st, 0, sizeof(*st));
- st->container_dev = NoMdDev;
+ st = xcalloc(1, sizeof(*st));
st->ss = &super_imsm;
st->max_devs = IMSM_MAX_DEVICES;
st->minor_version = 0;
__u32 *p = (__u32 *) mpb;
__u32 sum = 0;
- while (end--) {
- sum += __le32_to_cpu(*p);
+ while (end--) {
+ sum += __le32_to_cpu(*p);
p++;
}
- return sum - __le32_to_cpu(mpb->check_sum);
+ return sum - __le32_to_cpu(mpb->check_sum);
}
static size_t sizeof_imsm_map(struct imsm_map *map)
static __u32 imsm_min_reserved_sectors(struct intel_super *super);
+static int split_ull(unsigned long long n, __u32 *lo, __u32 *hi)
+{
+ if (lo == 0 || hi == 0)
+ return 1;
+ *lo = __le32_to_cpu((unsigned)n);
+ *hi = __le32_to_cpu((unsigned)(n >> 32));
+ return 0;
+}
+
+static unsigned long long join_u32(__u32 lo, __u32 hi)
+{
+ return (unsigned long long)__le32_to_cpu(lo) |
+ (((unsigned long long)__le32_to_cpu(hi)) << 32);
+}
+
+static unsigned long long total_blocks(struct imsm_disk *disk)
+{
+ if (disk == NULL)
+ return 0;
+ return join_u32(disk->total_blocks_lo, disk->total_blocks_hi);
+}
+
+static unsigned long long pba_of_lba0(struct imsm_map *map)
+{
+ if (map == NULL)
+ return 0;
+ return join_u32(map->pba_of_lba0_lo, map->pba_of_lba0_hi);
+}
+
+static unsigned long long blocks_per_member(struct imsm_map *map)
+{
+ if (map == NULL)
+ return 0;
+ return join_u32(map->blocks_per_member_lo, map->blocks_per_member_hi);
+}
+
+#ifndef MDASSEMBLE
+static unsigned long long num_data_stripes(struct imsm_map *map)
+{
+ if (map == NULL)
+ return 0;
+ return join_u32(map->num_data_stripes_lo, map->num_data_stripes_hi);
+}
+
+static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
+{
+ split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
+}
+#endif
+
+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);
+}
+
+static void set_blocks_per_member(struct imsm_map *map, unsigned long long n)
+{
+ split_ull(n, &map->blocks_per_member_lo, &map->blocks_per_member_hi);
+}
+
+static void set_num_data_stripes(struct imsm_map *map, unsigned long long n)
+{
+ split_ull(n, &map->num_data_stripes_lo, &map->num_data_stripes_hi);
+}
+
static struct extent *get_extents(struct intel_super *super, struct dl *dl)
{
/* find a list of used extents on the given physical device */
else
reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
- rv = malloc(sizeof(struct extent) * (memberships + 1));
- if (!rv)
- return NULL;
+ rv = xcalloc(sizeof(struct extent), (memberships + 1));
e = rv;
for (i = 0; i < super->anchor->num_raid_devs; i++) {
struct imsm_map *map = get_imsm_map(dev, MAP_0);
if (get_imsm_disk_slot(map, dl->index) >= 0) {
- e->start = __le32_to_cpu(map->pba_of_lba0);
- e->size = __le32_to_cpu(map->blocks_per_member);
+ e->start = pba_of_lba0(map);
+ e->size = blocks_per_member(map);
e++;
}
}
qsort(rv, memberships, sizeof(*rv), cmp_extent);
- /* determine the start of the metadata
+ /* determine the start of the metadata
* when no raid devices are defined use the default
* ...otherwise allow the metadata to truncate the value
* as is the case with older versions of imsm
*/
if (memberships) {
struct extent *last = &rv[memberships - 1];
- __u32 remainder;
+ unsigned long long remainder;
- remainder = __le32_to_cpu(dl->disk.total_blocks) -
- (last->start + last->size);
+ remainder = total_blocks(&dl->disk) - (last->start + last->size);
/* round down to 1k block to satisfy precision of the kernel
* 'size' interface
*/
if (reservation > remainder)
reservation = remainder;
}
- e->start = __le32_to_cpu(dl->disk.total_blocks) - reservation;
+ e->start = total_blocks(&dl->disk) - reservation;
e->size = 0;
return rv;
}
for (i = 0; e[i].size; i++)
continue;
- rv = __le32_to_cpu(dl->disk.total_blocks) - e[i].start;
+ rv = total_blocks(&dl->disk) - e[i].start;
free(e);
{
struct extent *e;
int i;
- __u32 min_active, remainder;
+ unsigned long long min_active;
+ __u32 remainder;
__u32 rv = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
struct dl *dl, *dl_min = NULL;
for (dl = super->disks; dl; dl = dl->next) {
if (dl->index < 0)
continue;
- if (dl->disk.total_blocks < min_active || min_active == 0) {
+ unsigned long long blocks = total_blocks(&dl->disk);
+ if (blocks < min_active || min_active == 0) {
dl_min = dl;
- min_active = dl->disk.total_blocks;
+ min_active = blocks;
}
}
if (!dl_min)
sz += __le32_to_cpu(dev->size_low);
printf(" Array Size : %llu%s\n", (unsigned long long)sz,
human_size(sz * 512));
- sz = __le32_to_cpu(map->blocks_per_member);
+ sz = blocks_per_member(map);
printf(" Per Dev Size : %llu%s\n", (unsigned long long)sz,
human_size(sz * 512));
- printf(" Sector Offset : %u\n",
- __le32_to_cpu(map->pba_of_lba0));
- printf(" Num Stripes : %u\n",
- __le32_to_cpu(map->num_data_stripes));
+ printf(" Sector Offset : %llu\n",
+ pba_of_lba0(map));
+ printf(" Num Stripes : %llu\n",
+ num_data_stripes(map));
printf(" Chunk Size : %u KiB",
__le16_to_cpu(map->blocks_per_strip) / 2);
if (map2)
is_configured(disk) ? " active" : "",
is_failed(disk) ? " failed" : "");
printf(" Id : %08x\n", __le32_to_cpu(disk->scsi_id));
- sz = __le32_to_cpu(disk->total_blocks) - reserved;
+ sz = total_blocks(disk) - reserved;
printf(" Usable Size : %llu%s\n", (unsigned long long)sz,
human_size(sz * 512));
}
/*******************************************************************************
* function: imsm_check_attributes
* Description: Function checks if features represented by attributes flags
- * are supported by mdadm.
+ * are supported by mdadm.
* Parameters:
* attributes - Attributes read from metadata
* Returns:
- * 0 - passed attributes contains unsupported features flags
- * 1 - all features are supported
+ * 0 - passed attributes contains unsupported features flags
+ * 1 - all features are supported
******************************************************************************/
static int imsm_check_attributes(__u32 attributes)
{
not_supported &= attributes;
if (not_supported) {
- fprintf(stderr, Name "(IMSM): Unsupported attributes : %x\n",
+ pr_err("(IMSM): Unsupported attributes : %x\n",
(unsigned)__le32_to_cpu(not_supported));
if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n");
printf("MD_DEVICES=%u\n", mpb->num_disks);
}
+static int copy_metadata_imsm(struct supertype *st, int from, int to)
+{
+ /* The second last 512byte sector of the device contains
+ * the "struct imsm_super" metadata.
+ * This contains mpb_size which is the size in bytes of the
+ * extended metadata. This is located immediately before
+ * the imsm_super.
+ * We want to read all that, plus the last sector which
+ * may contain a migration record, and write it all
+ * to the target.
+ */
+ void *buf;
+ unsigned long long dsize, offset;
+ int sectors;
+ struct imsm_super *sb;
+ int written = 0;
+
+ if (posix_memalign(&buf, 4096, 4096) != 0)
+ return 1;
+
+ if (!get_dev_size(from, NULL, &dsize))
+ goto err;
+
+ if (lseek64(from, dsize-1024, 0) < 0)
+ goto err;
+ if (read(from, buf, 512) != 512)
+ goto err;
+ sb = buf;
+ if (strncmp((char*)sb->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0)
+ goto err;
+
+ sectors = mpb_sectors(sb) + 2;
+ offset = dsize - sectors * 512;
+ if (lseek64(from, offset, 0) < 0 ||
+ lseek64(to, offset, 0) < 0)
+ goto err;
+ while (written < sectors * 512) {
+ int n = sectors*512 - written;
+ if (n > 4096)
+ n = 4096;
+ if (read(from, buf, n) != n)
+ goto err;
+ if (write(to, buf, n) != n)
+ goto err;
+ written += n;
+ }
+ free(buf);
+ return 0;
+err:
+ free(buf);
+ return 1;
+}
+
static void detail_super_imsm(struct supertype *st, char *homehost)
{
struct mdinfo info;
unsigned long port_mask = (1 << port_count) - 1;
if (port_count > (int)sizeof(port_mask) * 8) {
- if (verbose)
- fprintf(stderr, Name ": port_count %d out of range\n", port_count);
+ if (verbose > 0)
+ pr_err("port_count %d out of range\n", port_count);
return 2;
}
/* retrieve the scsi device type */
if (asprintf(&device, "/sys/dev/block/%d:%d/device/xxxxxxx", major, minor) < 0) {
- if (verbose)
- fprintf(stderr, Name ": failed to allocate 'device'\n");
+ if (verbose > 0)
+ pr_err("failed to allocate 'device'\n");
err = 2;
break;
}
sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor);
if (load_sys(device, buf) != 0) {
- if (verbose)
- fprintf(stderr, Name ": failed to read device type for %s\n",
+ if (verbose > 0)
+ pr_err("failed to read device type for %s\n",
path);
err = 2;
free(device);
/* chop device path to 'host%d' and calculate the port number */
c = strchr(&path[hba_len], '/');
if (!c) {
- if (verbose)
- fprintf(stderr, Name ": %s - invalid path name\n", path + hba_len);
+ if (verbose > 0)
+ pr_err("%s - invalid path name\n", path + hba_len);
err = 2;
break;
}
if (sscanf(&path[hba_len], "host%d", &port) == 1)
port -= host_base;
else {
- if (verbose) {
+ if (verbose > 0) {
*c = '/'; /* repair the full string */
- fprintf(stderr, Name ": failed to determine port number for %s\n",
+ pr_err("failed to determine port number for %s\n",
path);
}
err = 2;
static void print_found_intel_controllers(struct sys_dev *elem)
{
for (; elem; elem = elem->next) {
- fprintf(stderr, Name ": found Intel(R) ");
+ pr_err("found Intel(R) ");
if (elem->type == SYS_DEV_SATA)
fprintf(stderr, "SATA ");
else if (elem->type == SYS_DEV_SAS)
imsm_orom_has_chunk(orom, 1024*16) ? " 16M" : "",
imsm_orom_has_chunk(orom, 1024*32) ? " 32M" : "",
imsm_orom_has_chunk(orom, 1024*64) ? " 64M" : "");
+ printf(" 2TB volumes :%s supported\n",
+ (orom->attr & IMSM_OROM_ATTR_2TB)?"":" not");
+ printf(" 2TB disks :%s supported\n",
+ (orom->attr & IMSM_OROM_ATTR_2TB_DISK)?"":" not");
printf(" Max Disks : %d\n", orom->tds);
- printf(" Max Volumes : %d\n", orom->vpa);
+ printf(" Max Volumes : %d per array, %d per controller\n",
+ orom->vpa, orom->vphba);
return;
}
-static int detail_platform_imsm(int verbose, int enumerate_only)
+static void print_imsm_capability_export(const struct imsm_orom *orom)
+{
+ printf("MD_FIRMWARE_TYPE=imsm\n");
+ printf("IMSM_VERSION=%d.%d.%d.%d\n",orom->major_ver, orom->minor_ver,
+ orom->hotfix_ver, orom->build);
+ printf("IMSM_SUPPORTED_RAID_LEVELS=%s%s%s%s%s\n",
+ imsm_orom_has_raid0(orom) ? "raid0 " : "",
+ imsm_orom_has_raid1(orom) ? "raid1 " : "",
+ imsm_orom_has_raid1e(orom) ? "raid1e " : "",
+ imsm_orom_has_raid5(orom) ? "raid10 " : "",
+ imsm_orom_has_raid10(orom) ? "raid5 " : "");
+ printf("IMSM_SUPPORTED_CHUNK_SIZES=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ imsm_orom_has_chunk(orom, 2) ? "2k " : "",
+ imsm_orom_has_chunk(orom, 4) ? "4k " : "",
+ imsm_orom_has_chunk(orom, 8) ? "8k " : "",
+ imsm_orom_has_chunk(orom, 16) ? "16k " : "",
+ imsm_orom_has_chunk(orom, 32) ? "32k " : "",
+ imsm_orom_has_chunk(orom, 64) ? "64k " : "",
+ imsm_orom_has_chunk(orom, 128) ? "128k " : "",
+ imsm_orom_has_chunk(orom, 256) ? "256k " : "",
+ imsm_orom_has_chunk(orom, 512) ? "512k " : "",
+ imsm_orom_has_chunk(orom, 1024*1) ? "1M " : "",
+ imsm_orom_has_chunk(orom, 1024*2) ? "2M " : "",
+ imsm_orom_has_chunk(orom, 1024*4) ? "4M " : "",
+ imsm_orom_has_chunk(orom, 1024*8) ? "8M " : "",
+ imsm_orom_has_chunk(orom, 1024*16) ? "16M " : "",
+ imsm_orom_has_chunk(orom, 1024*32) ? "32M " : "",
+ imsm_orom_has_chunk(orom, 1024*64) ? "64M " : "");
+ printf("IMSM_2TB_VOLUMES=%s\n",(orom->attr & IMSM_OROM_ATTR_2TB) ? "yes" : "no");
+ printf("IMSM_2TB_DISKS=%s\n",(orom->attr & IMSM_OROM_ATTR_2TB_DISK) ? "yes" : "no");
+ printf("IMSM_MAX_DISKS=%d\n",orom->tds);
+ printf("IMSM_MAX_VOLUMES_PER_ARRAY=%d\n",orom->vpa);
+ printf("IMSM_MAX_VOLUMES_PER_CONTROLLER=%d\n",orom->vphba);
+}
+
+static int detail_platform_imsm(int verbose, int enumerate_only, char *controller_path)
{
/* There are two components to imsm platform support, the ahci SATA
* controller and the option-rom. To find the SATA controller we
struct sys_dev *list, *hba;
int host_base = 0;
int port_count = 0;
- int result=0;
+ int result=1;
if (enumerate_only) {
if (check_env("IMSM_NO_PLATFORM"))
result = 2;
break;
}
+ else
+ result = 0;
}
- free_sys_dev(&list);
return result;
}
list = find_intel_devices();
if (!list) {
- if (verbose)
- fprintf(stderr, Name ": no active Intel(R) RAID "
+ if (verbose > 0)
+ pr_err("no active Intel(R) RAID "
"controller found.\n");
- free_sys_dev(&list);
return 2;
- } else if (verbose)
+ } else if (verbose > 0)
print_found_intel_controllers(list);
for (hba = list; hba; hba = hba->next) {
+ if (controller_path && (compare_paths(hba->path,controller_path) != 0))
+ continue;
orom = find_imsm_capability(hba->type);
if (!orom)
- fprintf(stderr, Name ": imsm capabilities not found for controller: %s (type %s)\n",
+ pr_err("imsm capabilities not found for controller: %s (type %s)\n",
hba->path, get_sys_dev_type(hba->type));
- else
+ else {
+ result = 0;
print_imsm_capability(orom);
+ printf(" I/O Controller : %s (%s)\n",
+ hba->path, get_sys_dev_type(hba->type));
+ if (hba->type == SYS_DEV_SATA) {
+ host_base = ahci_get_port_count(hba->path, &port_count);
+ if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
+ if (verbose > 0)
+ pr_err("failed to enumerate "
+ "ports on SATA controller at %s.\n", hba->pci_id);
+ result |= 2;
+ }
+ }
+ }
+ }
+
+ if (controller_path && result == 1)
+ pr_err("no active Intel(R) RAID "
+ "controller found under %s\n",controller_path);
+
+ return result;
+}
+
+static int export_detail_platform_imsm(int verbose, char *controller_path)
+{
+ const struct imsm_orom *orom;
+ struct sys_dev *list, *hba;
+ int result=1;
+
+ list = find_intel_devices();
+ if (!list) {
+ if (verbose > 0)
+ pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_INTEL_DEVICES\n");
+ result = 2;
+ return result;
}
for (hba = list; hba; hba = hba->next) {
- printf(" I/O Controller : %s (%s)\n",
- hba->path, get_sys_dev_type(hba->type));
-
- if (hba->type == SYS_DEV_SATA) {
- host_base = ahci_get_port_count(hba->path, &port_count);
- if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
- if (verbose)
- fprintf(stderr, Name ": failed to enumerate "
- "ports on SATA controller at %s.", hba->pci_id);
- result |= 2;
- }
+ if (controller_path && (compare_paths(hba->path,controller_path) != 0))
+ continue;
+ orom = find_imsm_capability(hba->type);
+ if (!orom) {
+ if (verbose > 0)
+ pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n",hba->path);
+ }
+ else {
+ print_imsm_capability_export(orom);
+ result = 0;
}
}
- free_sys_dev(&list);
return result;
}
+
#endif
static int match_home_imsm(struct supertype *st, char *homehost)
* not the device-set.
* uuid to recognise same set when adding a missing device back
* to an array. This is a uuid for the device-set.
- *
+ *
* For each of these we can make do with a truncated
* or hashed uuid rather than the original, as long as
* everyone agrees.
switch (get_imsm_raid_level(map)) {
case 0:
+ return map->num_members;
+ break;
case 1:
case 10:
- return map->num_members;
+ return map->num_members/2;
case 5:
return map->num_members - 1;
default:
get_dev_size(fd, NULL, &dsize);
if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) {
- fprintf(stderr,
- Name ": Cannot seek to anchor block: %s\n",
- strerror(errno));
+ pr_err("Cannot seek to anchor block: %s\n",
+ strerror(errno));
goto out;
}
if (read(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) !=
MIGR_REC_BUF_SIZE) {
- fprintf(stderr,
- Name ": Cannot read migr record block: %s\n",
- strerror(errno));
+ pr_err("Cannot read migr record block: %s\n",
+ strerror(errno));
goto out;
}
ret_val = 0;
update_memory_size =
sizeof(struct imsm_update_general_migration_checkpoint);
- *u = calloc(1, update_memory_size);
+ *u = xcalloc(1, update_memory_size);
if (*u == NULL) {
dprintf("error: cannot get memory for "
"imsm_create_metadata_checkpoint_update update\n");
return update_memory_size;
}
-
static void imsm_update_metadata_locally(struct supertype *st,
void *buf, int len);
continue;
get_dev_size(fd, NULL, &dsize);
if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) {
- fprintf(stderr,
- Name ": Cannot seek to anchor block: %s\n",
- strerror(errno));
+ pr_err("Cannot seek to anchor block: %s\n",
+ strerror(errno));
goto out;
}
if (write(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) !=
MIGR_REC_BUF_SIZE) {
- fprintf(stderr,
- Name ": Cannot write migr record block: %s\n",
- strerror(errno));
+ pr_err("Cannot write migr record block: %s\n",
+ strerror(errno));
goto out;
}
close(fd);
}
return rv;
}
+static unsigned long long imsm_component_size_aligment_check(int level,
+ int chunk_size,
+ unsigned long long component_size)
+{
+ unsigned int component_size_alligment;
+
+ /* check component size aligment
+ */
+ component_size_alligment = component_size % (chunk_size/512);
+
+ dprintf("imsm_component_size_aligment_check(Level: %i, "
+ "chunk_size = %i, component_size = %llu), "
+ "component_size_alligment = %u\n",
+ level, chunk_size, component_size,
+ component_size_alligment);
+
+ if (component_size_alligment && (level != 1) && (level != UnSet)) {
+ dprintf("imsm: reported component size alligned from %llu ",
+ component_size);
+ component_size -= component_size_alligment;
+ dprintf("to %llu (%i).\n",
+ component_size, component_size_alligment);
+ }
+
+ return component_size;
+}
static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
{
struct imsm_map *prev_map = get_imsm_map(dev, MAP_1);
struct imsm_map *map_to_analyse = map;
struct dl *dl;
- char *devname;
- unsigned int component_size_alligment;
int map_disks = info->array.raid_disks;
memset(info, 0, sizeof(*info));
dl->index);
}
- info->data_offset = __le32_to_cpu(map_to_analyse->pba_of_lba0);
- info->component_size =
- __le32_to_cpu(map_to_analyse->blocks_per_member);
-
- /* check component size aligment
- */
- component_size_alligment =
- info->component_size % (info->array.chunk_size/512);
+ info->data_offset = pba_of_lba0(map_to_analyse);
+ info->component_size = blocks_per_member(map_to_analyse);
- if (component_size_alligment &&
- (info->array.level != 1) && (info->array.level != UnSet)) {
- dprintf("imsm: reported component size alligned from %llu ",
- info->component_size);
- info->component_size -= component_size_alligment;
- dprintf("to %llu (%i).\n",
- info->component_size, component_size_alligment);
- }
+ info->component_size = imsm_component_size_aligment_check(
+ info->array.level,
+ info->array.chunk_size,
+ info->component_size);
memset(info->uuid, 0, sizeof(info->uuid));
info->recovery_start = MaxSector;
used_disks = imsm_num_data_members(dev, MAP_1);
if (used_disks > 0) {
- array_blocks = map->blocks_per_member *
+ array_blocks = blocks_per_member(map) *
used_disks;
/* round array size down to closest MB
*/
info->array.major_version = -1;
info->array.minor_version = -2;
- devname = devnum2devname(st->container_dev);
- *info->text_version = '\0';
- if (devname)
- sprintf(info->text_version, "/%s/%d", devname, info->container_member);
- free(devname);
+ sprintf(info->text_version, "/%s/%d", st->container_devnm, info->container_member);
info->safe_mode_delay = 4000; /* 4 secs like the Matrix driver */
uuid_from_super_imsm(st, info->uuid);
static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
int look_in_map);
-
#ifndef MDASSEMBLE
static void manage_second_map(struct intel_super *super, struct imsm_dev *dev)
{
info->array.level = LEVEL_CONTAINER;
info->array.layout = 0;
info->array.md_minor = -1;
- info->array.ctime = 0; /* N/A for imsm */
+ info->array.ctime = 0; /* N/A for imsm */
info->array.utime = 0;
info->array.chunk_size = 0;
__u32 reserved = imsm_reserved_sectors(super, super->disks);
disk = &super->disks->disk;
- info->data_offset = __le32_to_cpu(disk->total_blocks) - reserved;
+ info->data_offset = total_blocks(&super->disks->disk) - reserved;
info->component_size = reserved;
info->disk.state = is_configured(disk) ? (1 << MD_DISK_ACTIVE) : 0;
/* we don't change info->disk.raid_disk here because
if (!super || !super->disks)
return NULL;
dl = super->disks;
- mddev = malloc(sizeof(*mddev));
- if (!mddev) {
- fprintf(stderr, Name ": Failed to allocate memory.\n");
- return NULL;
- }
- memset(mddev, 0, sizeof(*mddev));
+ mddev = xcalloc(1, sizeof(*mddev));
while (dl) {
struct mdinfo *tmp;
disk = &dl->disk;
- tmp = malloc(sizeof(*tmp));
- if (!tmp) {
- fprintf(stderr, Name ": Failed to allocate memory.\n");
- if (mddev)
- sysfs_free(mddev);
- return NULL;
- }
- memset(tmp, 0, sizeof(*tmp));
+ tmp = xcalloc(1, sizeof(*tmp));
if (mddev->devs)
tmp->next = mddev->devs;
mddev->devs = tmp;
return size;
}
-static __u64 avail_size_imsm(struct supertype *st, __u64 devsize)
+static __u64 avail_size_imsm(struct supertype *st, __u64 devsize,
+ unsigned long long data_offset)
{
if (devsize < (MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS))
return 0;
struct intel_super *first = st->sb;
struct intel_super *sec = tst->sb;
- if (!first) {
- st->sb = tst->sb;
- tst->sb = NULL;
- return 0;
- }
+ if (!first) {
+ st->sb = 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 (!check_env("IMSM_NO_PLATFORM")) {
- if (!first->hba || !sec->hba ||
- (first->hba->type != sec->hba->type)) {
+ if (first->hba && sec->hba &&
+ strcmp(first->hba->path, sec->hba->path) != 0) {
fprintf(stderr,
"HBAs of devices does not match %s != %s\n",
- first->hba ? get_sys_dev_type(first->hba->type) : NULL,
- sec->hba ? get_sys_dev_type(sec->hba->type) : NULL);
+ first->hba ? first->hba->path : NULL,
+ sec->hba ? sec->hba->path : NULL);
return 3;
}
}
}
-
/* if 'first' is a spare promote it to a populated mpb with sec's
* family number
*/
* fails here we don't associate the spare
*/
for (i = 0; i < sec->anchor->num_raid_devs; i++) {
- dv = malloc(sizeof(*dv));
- if (!dv)
- break;
- dev = malloc(sizeof_imsm_dev(get_imsm_dev(sec, i), 1));
- if (!dev) {
- free(dv);
- break;
- }
+ 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;
if (i < sec->anchor->num_raid_devs) {
/* allocation failure */
free_devlist(first);
- fprintf(stderr, "imsm: failed to associate spare\n");
+ pr_err("imsm: failed to associate spare\n");
return 3;
}
first->anchor->num_raid_devs = sec->anchor->num_raid_devs;
if (rv != 0) {
if (devname)
- fprintf(stderr,
- Name ": Failed to retrieve serial for %s\n",
- devname);
+ pr_err("Failed to retrieve serial for %s\n",
+ devname);
return rv;
}
rsp_len = scsi_serial[3];
if (!rsp_len) {
if (devname)
- fprintf(stderr,
- Name ": Failed to retrieve serial for %s\n",
- devname);
+ pr_err("Failed to retrieve serial for %s\n",
+ devname);
return 2;
}
rsp_buf = (char *) &scsi_serial[4];
if (rv != 0)
return 2;
- dl = calloc(1, sizeof(*dl));
- if (!dl) {
- if (devname)
- fprintf(stderr,
- Name ": failed to allocate disk buffer for %s\n",
- devname);
- return 2;
- }
+ dl = xcalloc(1, sizeof(*dl));
fstat(fd, &stb);
dl->major = major(stb.st_rdev);
dl->e = NULL;
fd2devname(fd, name);
if (devname)
- dl->devname = strdup(devname);
+ dl->devname = xstrdup(devname);
else
- dl->devname = strdup(name);
+ dl->devname = xstrdup(name);
/* look up this disk's index in the current anchor */
disk = __serial_to_disk(dl->serial, super->anchor, &dl->index);
if (len_migr > len)
space_needed += len_migr - len;
- dv = malloc(sizeof(*dv));
- if (!dv)
- return 1;
+ dv = xmalloc(sizeof(*dv));
if (max_len < len_migr)
max_len = len_migr;
if (max_len > len_migr)
space_needed += max_len - len_migr;
- dev_new = malloc(max_len);
- if (!dev_new) {
- free(dv);
- return 1;
- }
+ dev_new = xmalloc(max_len);
imsm_copy_dev(dev_new, dev_iter);
dv->dev = dev_new;
dv->index = i;
if (__le32_to_cpu(mpb->bbm_log_size)) {
ptr = mpb;
ptr += mpb->mpb_size - __le32_to_cpu(mpb->bbm_log_size);
- }
+ }
return ptr;
}
/* This device is migrating */
map0 = get_imsm_map(dev_iter, MAP_0);
map1 = get_imsm_map(dev_iter, MAP_1);
- if (map0->pba_of_lba0 != map1->pba_of_lba0)
+ if (pba_of_lba0(map0) != pba_of_lba0(map1))
/* migration optimization area was used */
return -1;
if (migr_rec->ascending_migr == 0
get_dev_size(fd, NULL, &dsize);
if (dsize < 1024) {
if (devname)
- fprintf(stderr,
- Name ": %s: device to small for imsm\n",
- devname);
+ pr_err("%s: device to small for imsm\n",
+ devname);
return 1;
}
if (lseek64(fd, dsize - (512 * 2), SEEK_SET) < 0) {
if (devname)
- fprintf(stderr, Name
- ": Cannot seek to anchor block on %s: %s\n",
- devname, strerror(errno));
+ pr_err("Cannot seek to anchor block on %s: %s\n",
+ devname, strerror(errno));
return 1;
}
if (posix_memalign((void**)&anchor, 512, 512) != 0) {
if (devname)
- fprintf(stderr,
- Name ": Failed to allocate imsm anchor buffer"
- " on %s\n", devname);
+ pr_err("Failed to allocate imsm anchor buffer"
+ " on %s\n", devname);
return 1;
}
if (read(fd, anchor, 512) != 512) {
if (devname)
- fprintf(stderr,
- Name ": Cannot read anchor block on %s: %s\n",
- devname, strerror(errno));
+ pr_err("Cannot read anchor block on %s: %s\n",
+ devname, strerror(errno));
free(anchor);
return 1;
}
if (strncmp((char *) anchor->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0) {
if (devname)
- fprintf(stderr,
- Name ": no IMSM anchor on %s\n", devname);
+ pr_err("no IMSM anchor on %s\n", devname);
free(anchor);
return 2;
}
super->len = ROUND_UP(anchor->mpb_size, 512);
if (posix_memalign(&super->buf, 512, super->len) != 0) {
if (devname)
- fprintf(stderr,
- Name ": unable to allocate %zu byte mpb buffer\n",
- super->len);
+ pr_err("unable to allocate %zu byte mpb buffer\n",
+ super->len);
free(anchor);
return 2;
}
free(anchor);
if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) {
- fprintf(stderr, Name
- ": %s could not allocate migr_rec buffer\n", __func__);
+ pr_err("%s could not allocate migr_rec buffer\n", __func__);
free(super->buf);
return 2;
}
check_sum = __gen_imsm_checksum(super->anchor);
if (check_sum != __le32_to_cpu(super->anchor->check_sum)) {
if (devname)
- fprintf(stderr,
- Name ": IMSM checksum %x != %x on %s\n",
- check_sum,
- __le32_to_cpu(super->anchor->check_sum),
- devname);
+ pr_err("IMSM checksum %x != %x on %s\n",
+ check_sum,
+ __le32_to_cpu(super->anchor->check_sum),
+ devname);
return 2;
}
/* read the extended mpb */
if (lseek64(fd, dsize - (512 * (2 + sectors)), SEEK_SET) < 0) {
if (devname)
- fprintf(stderr,
- Name ": Cannot seek to extended mpb on %s: %s\n",
- devname, strerror(errno));
+ pr_err("Cannot seek to extended mpb on %s: %s\n",
+ devname, strerror(errno));
return 1;
}
if ((unsigned)read(fd, super->buf + 512, super->len - 512) != super->len - 512) {
if (devname)
- fprintf(stderr,
- Name ": Cannot read extended mpb on %s: %s\n",
- devname, strerror(errno));
+ pr_err("Cannot read extended mpb on %s: %s\n",
+ devname, strerror(errno));
return 2;
}
check_sum = __gen_imsm_checksum(super->anchor);
if (check_sum != __le32_to_cpu(super->anchor->check_sum)) {
if (devname)
- fprintf(stderr,
- Name ": IMSM checksum %x != %x on %s\n",
- check_sum, __le32_to_cpu(super->anchor->check_sum),
- devname);
+ pr_err("IMSM checksum %x != %x on %s\n",
+ check_sum, __le32_to_cpu(super->anchor->check_sum),
+ devname);
return 3;
}
static int read_imsm_migr_rec(int fd, struct intel_super *super);
+/* clears hi bits in metadata if MPB_ATTRIB_2TB_DISK not set */
+static void clear_hi(struct intel_super *super)
+{
+ struct imsm_super *mpb = super->anchor;
+ int i, n;
+ if (mpb->attributes & MPB_ATTRIB_2TB_DISK)
+ return;
+ for (i = 0; i < mpb->num_disks; ++i) {
+ struct imsm_disk *disk = &mpb->disk[i];
+ disk->total_blocks_hi = 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)
+ continue;
+ map->pba_of_lba0_hi = 0;
+ map->blocks_per_member_hi = 0;
+ map->num_data_stripes_hi = 0;
+ }
+ }
+}
+
static int
load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd)
{
if (err)
return err;
err = parse_raid_devices(super);
-
+ clear_hi(super);
return err;
}
static struct intel_super *alloc_super(void)
{
- struct intel_super *super = malloc(sizeof(*super));
+ struct intel_super *super = xcalloc(1, sizeof(*super));
- if (super) {
- memset(super, 0, sizeof(*super));
- super->current_vol = -1;
- super->create_offset = ~((__u32 ) 0);
- }
+ super->current_vol = -1;
+ super->create_offset = ~((unsigned long long) 0);
return super;
}
hba_name = find_disk_attached_hba(fd, NULL);
if (!hba_name) {
if (devname)
- fprintf(stderr,
- Name ": %s is not attached to Intel(R) RAID controller.\n",
- devname);
+ pr_err("%s is not attached to Intel(R) RAID controller.\n",
+ devname);
return 1;
}
rv = attach_hba_to_super(super, hba_name);
if (devname) {
struct intel_hba *hba = super->hba;
- fprintf(stderr, Name ": %s is attached to Intel(R) %s RAID "
+ pr_err("%s is attached to Intel(R) %s RAID "
"controller (%s),\n"
" but the container is assigned to Intel(R) "
"%s RAID controller (",
hba = hba->next;
}
- fprintf(stderr, ").\n"
- " Mixing devices attached to different controllers "
- "is not allowed.\n");
+ fprintf(stderr, ").\n");
+ cont_err("Mixing devices attached to multiple controllers "
+ "is not allowed.\n");
}
- free_sys_dev(&hba_name);
return 2;
}
super->orom = find_imsm_capability(hba_name->type);
- free_sys_dev(&hba_name);
if (!super->orom)
return 3;
return 0;
if (dl)
continue;
- dl = malloc(sizeof(*dl));
- if (!dl)
- return 1;
+ dl = xmalloc(sizeof(*dl));
dl->major = 0;
dl->minor = 0;
dl->fd = -1;
- dl->devname = strdup("missing");
+ dl->devname = xstrdup("missing");
dl->index = i;
serialcpy(dl->serial, disk->serial);
dl->disk = *disk;
is_failed(&idisk->disk))
idisk->disk.status &= ~(SPARE_DISK);
} else {
- idisk = calloc(1, sizeof(*idisk));
- if (!idisk)
- return -1;
+ idisk = xcalloc(1, sizeof(*idisk));
idisk->owner = IMSM_UNKNOWN_OWNER;
idisk->disk = *disk;
idisk->next = *disk_list;
for (s = super_list; s; s = s->next) {
if (family_num != s->anchor->family_num)
continue;
- fprintf(stderr, "Conflict, offlining family %#x on '%s'\n",
+ pr_err("Conflict, offlining family %#x on '%s'\n",
__le32_to_cpu(family_num), s->disks->devname);
}
}
champion = s;
if (conflict)
- fprintf(stderr, "Chose family %#x on '%s', "
+ pr_err("Chose family %#x on '%s', "
"assemble conflicts to new container with '--update=uuid'\n",
__le32_to_cpu(s->anchor->family_num), s->disks->devname);
if (s == champion)
continue;
+ mpb->attributes |= s->anchor->attributes & MPB_ATTRIB_2TB_DISK;
+
for (i = 0; i < mpb->num_disks; i++) {
struct imsm_disk *disk;
return champion;
}
-
static int
get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd);
-static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+static int get_super_block(struct intel_super **super_list, char *devnm, char *devname,
int major, int minor, int keep_fd);
static int
get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list,
int *max, int keep_fd);
-
static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
char *devname, struct md_list *devlist,
int keep_fd)
/* Check migration compatibility */
if ((err == 0) && (check_mpb_migr_compatibility(super) != 0)) {
- fprintf(stderr, Name ": Unsupported migration detected");
+ pr_err("Unsupported migration detected");
if (devname)
fprintf(stderr, " on %s\n", devname);
else
free_imsm(s);
}
-
if (err)
return err;
*sbp = super;
if (fd >= 0)
- st->container_dev = fd2devnum(fd);
+ strcpy(st->container_devnm, fd2devnm(fd));
else
- st->container_dev = NoMdDev;
+ st->container_devnm[0] = 0;
if (err == 0 && st->ss == NULL) {
st->ss = &super_imsm;
st->minor_version = 0;
return 0;
}
-
static int
get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list,
int *max, int keep_fd)
int lmax = 0;
int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL);
if (fd < 0) {
- fprintf(stderr, Name ": cannot open device %s: %s\n",
+ pr_err("cannot open device %s: %s\n",
tmpdev->devname, strerror(errno));
err = 8;
goto error;
int major = major(tmpdev->st_rdev);
int minor = minor(tmpdev->st_rdev);
err = get_super_block(super_list,
- -1,
+ NULL,
tmpdev->devname,
major, minor,
keep_fd);
return err;
}
-static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+static int get_super_block(struct intel_super **super_list, char *devnm, char *devname,
int major, int minor, int keep_fd)
{
struct intel_super*s = NULL;
char nm[32];
int dfd = -1;
- int rv;
int err = 0;
int retry;
goto error;
}
- rv = find_intel_hba_capability(dfd, s, devname);
- /* no orom/efi or non-intel hba of the disk */
- if (rv != 0) {
- err = 4;
- 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 && (devnum != -1) && mdmon_running(devnum))
+ if (err == 3 && devnm && mdmon_running(devnm))
for (retry = 0; retry < 3; retry++) {
usleep(3000);
err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
} else {
if (s)
free(s);
- if (dfd)
+ if (dfd >= 0)
close(dfd);
}
if ((dfd >= 0) && (!keep_fd))
get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd)
{
struct mdinfo *sra;
- int devnum;
+ char *devnm;
struct mdinfo *sd;
int err = 0;
int i = 0;
- sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
+ sra = sysfs_read(fd, NULL, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
if (!sra)
return 1;
goto error;
}
/* load all mpbs */
- devnum = fd2devnum(fd);
+ devnm = fd2devnm(fd);
for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
- if (get_super_block(super_list, devnum, devname,
+ if (get_super_block(super_list, devnm, devname,
sd->disk.major, sd->disk.minor, keep_fd) != 0) {
err = 7;
goto error;
struct intel_super *super;
int rv;
- if (test_partition(fd))
+ if (!st->ignore_hw_compat && test_partition(fd))
/* IMSM not allowed on partitions */
return 1;
free_super_imsm(st);
super = alloc_super();
- if (!super) {
- fprintf(stderr,
- Name ": malloc of %zu failed.\n",
- sizeof(*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.
/* no orom/efi or non-intel hba of the disk */
if ((rv != 0) && (st->ignore_hw_compat == 0)) {
if (devname)
- fprintf(stderr,
- Name ": No OROM/EFI properties for %s\n", devname);
+ pr_err("No OROM/EFI properties for %s\n", devname);
free_imsm(super);
return 2;
}
if (rv) {
if (devname)
- fprintf(stderr,
- Name ": Failed to load all information "
- "sections on %s\n", devname);
+ pr_err("Failed to load all information "
+ "sections on %s\n", devname);
free_imsm(super);
return rv;
}
if (load_imsm_migr_rec(super, NULL) == 0) {
/* Check for unsupported migration features */
if (check_mpb_migr_compatibility(super) != 0) {
- fprintf(stderr,
- Name ": Unsupported migration detected");
+ pr_err("Unsupported migration detected");
if (devname)
fprintf(stderr, " on %s\n", devname);
else
return info->chunk_size >> 9;
}
-static __u32 info_to_num_data_stripes(mdu_array_info_t *info, int num_domains)
-{
- __u32 num_stripes;
-
- num_stripes = (info->size * 2) / info_to_blocks_per_strip(info);
- num_stripes /= num_domains;
-
- return num_stripes;
-}
-
-static __u32 info_to_blocks_per_member(mdu_array_info_t *info)
+static unsigned long long info_to_blocks_per_member(mdu_array_info_t *info,
+ unsigned long long size)
{
if (info->level == 1)
- return info->size * 2;
+ return size * 2;
else
- return (info->size * 2) & ~(info_to_blocks_per_strip(info) - 1);
+ return (size * 2) & ~(info_to_blocks_per_strip(info) - 1);
}
static void imsm_update_version_info(struct intel_super *super)
}
if (reason && !quiet)
- fprintf(stderr, Name ": imsm volume name %s\n", reason);
+ pr_err("imsm volume name %s\n", reason);
return !reason;
}
static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
unsigned long long size, char *name,
- char *homehost, int *uuid)
+ char *homehost, int *uuid,
+ long long data_offset)
{
/* We are creating a volume inside a pre-existing container.
* so st->sb is already set.
int i;
unsigned long long array_blocks;
size_t size_old, size_new;
- __u32 num_data_stripes;
+ unsigned long long num_data_stripes;
if (super->orom && mpb->num_raid_devs >= super->orom->vpa) {
- fprintf(stderr, Name": This imsm-container already has the "
+ pr_err("This imsm-container already has the "
"maximum of %d volumes\n", super->orom->vpa);
return 0;
}
size_t size_round = ROUND_UP(size_new, 512);
if (posix_memalign(&mpb_new, 512, size_round) != 0) {
- fprintf(stderr, Name": could not allocate new mpb\n");
+ pr_err("could not allocate new mpb\n");
return 0;
}
if (posix_memalign(&super->migr_rec_buf, 512,
MIGR_REC_BUF_SIZE) != 0) {
- fprintf(stderr, Name
- ": %s could not allocate migr_rec buffer\n",
- __func__);
+ pr_err("%s could not allocate migr_rec buffer\n",
+ __func__);
free(super->buf);
free(super);
free(mpb_new);
for (d = super->missing; d; d = d->next)
missing++;
if (info->failed_disks > missing) {
- fprintf(stderr, Name": unable to add 'missing' disk to container\n");
+ pr_err("unable to add 'missing' disk to container\n");
return 0;
}
}
if (!check_name(super, name, 0))
return 0;
- dv = malloc(sizeof(*dv));
- if (!dv) {
- fprintf(stderr, Name ": failed to allocate device list entry\n");
- return 0;
- }
- dev = calloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
- if (!dev) {
- free(dv);
- fprintf(stderr, Name": could not allocate raid device\n");
- return 0;
- }
-
+ dv = xmalloc(sizeof(*dv));
+ dev = xcalloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN);
- if (info->level == 1)
- array_blocks = info_to_blocks_per_member(info);
- else
- array_blocks = calc_array_size(info->level, info->raid_disks,
+ array_blocks = calc_array_size(info->level, info->raid_disks,
info->layout, info->chunk_size,
- info->size*2);
+ size * 2);
/* round array size down to closest MB */
array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
vol->dirty = !info->state;
vol->curr_migr_unit = 0;
map = get_imsm_map(dev, MAP_0);
- map->pba_of_lba0 = __cpu_to_le32(super->create_offset);
- map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info));
+ set_pba_of_lba0(map, super->create_offset);
+ set_blocks_per_member(map, info_to_blocks_per_member(info, size));
map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
map->failed_disk_num = ~0;
if (info->level > 0)
- map->map_state = IMSM_T_STATE_UNINITIALIZED;
+ map->map_state = (info->state ? IMSM_T_STATE_NORMAL
+ : IMSM_T_STATE_UNINITIALIZED);
else
map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED :
IMSM_T_STATE_NORMAL;
if (info->level == 1 && info->raid_disks > 2) {
free(dev);
free(dv);
- fprintf(stderr, Name": imsm does not support more than 2 disks"
+ pr_err("imsm does not support more than 2 disks"
"in a raid1 volume\n");
return 0;
}
else
map->num_domains = 1;
- num_data_stripes = info_to_num_data_stripes(info, map->num_domains);
- map->num_data_stripes = __cpu_to_le32(num_data_stripes);
+ /* info->size is only int so use the 'size' parameter instead */
+ num_data_stripes = (size * 2) / info_to_blocks_per_strip(info);
+ num_data_stripes /= map->num_domains;
+ set_num_data_stripes(map, num_data_stripes);
map->num_members = info->raid_disks;
for (i = 0; i < map->num_members; i++) {
static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
unsigned long long size, char *name,
- char *homehost, int *uuid)
+ char *homehost, int *uuid,
+ unsigned long long data_offset)
{
/* This is primarily called by Create when creating a new array.
* We will then get add_to_super called for each component, and then
size_t mpb_size;
char *version;
+ if (data_offset != INVALID_SECTORS) {
+ pr_err("data-offset not supported by imsm\n");
+ return 0;
+ }
+
if (st->sb)
- return init_super_imsm_volume(st, info, size, name, homehost, uuid);
+ return init_super_imsm_volume(st, info, size, name, homehost, uuid,
+ data_offset);
if (info)
mpb_size = disks_to_mpb_size(info->nr_disks);
super = NULL;
}
if (!super) {
- fprintf(stderr, Name
- ": %s could not allocate superblock\n", __func__);
+ pr_err("%s could not allocate superblock\n", __func__);
return 0;
}
if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) {
- fprintf(stderr, Name
- ": %s could not allocate migr_rec buffer\n", __func__);
+ pr_err("%s could not allocate migr_rec buffer\n", __func__);
free(super->buf);
free(super);
return 0;
map = get_imsm_map(dev, MAP_0);
if (! (dk->state & (1<<MD_DISK_SYNC))) {
- fprintf(stderr, Name ": %s: Cannot add spare devices to IMSM volume\n",
+ pr_err("%s: Cannot add spare devices to IMSM volume\n",
devname);
return 1;
}
}
if (!dl) {
- fprintf(stderr, Name ": %s is not a member of the same container\n", devname);
+ pr_err("%s is not a member of the same container\n", devname);
return 1;
}
slot = get_imsm_disk_slot(map, dl->index);
if (slot >= 0 &&
(get_imsm_ord_tbl_ent(dev, slot, MAP_X) & IMSM_ORD_REBUILD) == 0) {
- fprintf(stderr, Name ": %s has been included in this array twice\n",
+ pr_err("%s has been included in this array twice\n",
devname);
return 1;
}
*/
if (super->current_vol == 0) {
for (df = super->missing; df; df = df->next) {
- if (dl->disk.total_blocks > df->disk.total_blocks)
- df->disk.total_blocks = dl->disk.total_blocks;
+ if (total_blocks(&dl->disk) > total_blocks(&df->disk))
+ set_total_blocks(&df->disk, total_blocks(&dl->disk));
_disk = __get_imsm_disk(mpb, df->index);
*_disk = df->disk;
}
_disk = __get_imsm_disk(mpb, dl->index);
if (!_dev || !_disk) {
- fprintf(stderr, Name ": BUG mpb setup error\n");
+ pr_err("BUG mpb setup error\n");
return 1;
}
*_dev = *dev;
}
static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
- int fd, char *devname)
+ int fd, char *devname,
+ unsigned long long data_offset)
{
struct intel_super *super = st->sb;
struct dl *dd;
return add_to_super_imsm_volume(st, dk, fd, devname);
fstat(fd, &stb);
- dd = malloc(sizeof(*dd));
- if (!dd) {
- fprintf(stderr,
- Name ": malloc failed %s:%d.\n", __func__, __LINE__);
- return 1;
- }
- memset(dd, 0, sizeof(*dd));
+ dd = xcalloc(sizeof(*dd), 1);
dd->major = major(stb.st_rdev);
dd->minor = minor(stb.st_rdev);
- dd->devname = devname ? strdup(devname) : NULL;
+ dd->devname = devname ? xstrdup(devname) : NULL;
dd->fd = fd;
dd->e = NULL;
dd->action = DISK_ADD;
rv = imsm_read_serial(fd, devname, dd->serial);
if (rv) {
- fprintf(stderr,
- Name ": failed to retrieve scsi serial, aborting\n");
+ pr_err("failed to retrieve scsi serial, aborting\n");
free(dd);
abort();
}
get_dev_size(fd, NULL, &size);
size /= 512;
serialcpy(dd->disk.serial, dd->serial);
- dd->disk.total_blocks = __cpu_to_le32(size);
+ set_total_blocks(&dd->disk, size);
+ if (__le32_to_cpu(dd->disk.total_blocks_hi) > 0) {
+ struct imsm_super *mpb = super->anchor;
+ mpb->attributes |= MPB_ATTRIB_2TB_DISK;
+ }
mark_spare(dd);
if (sysfs_disk_to_scsi_id(fd, &id) == 0)
dd->disk.scsi_id = __cpu_to_le32(id);
return 0;
}
-
static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
{
struct intel_super *super = st->sb;
* is prepared.
*/
if (!st->update_tail) {
- fprintf(stderr,
- Name ": %s shall be used in mdmon context only"
- "(line %d).\n", __func__, __LINE__);
+ pr_err("%s shall be used in mdmon context only"
+ "(line %d).\n", __func__, __LINE__);
return 1;
}
- dd = malloc(sizeof(*dd));
- if (!dd) {
- fprintf(stderr,
- Name ": malloc failed %s:%d.\n", __func__, __LINE__);
- return 1;
- }
- memset(dd, 0, sizeof(*dd));
+ dd = xcalloc(1, sizeof(*dd));
dd->major = dk->major;
dd->minor = dk->minor;
dd->fd = -1;
dd->next = super->disk_mgmt_list;
super->disk_mgmt_list = dd;
-
return 0;
}
continue;
spare->disk[0] = d->disk;
+ if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
+ spare->attributes |= MPB_ATTRIB_2TB_DISK;
+
sum = __gen_imsm_checksum(spare);
spare->family_num = __cpu_to_le32(sum);
spare->orig_family_num = 0;
spare->check_sum = __cpu_to_le32(sum);
if (store_imsm_mpb(d->fd, spare)) {
- fprintf(stderr, "%s: failed for device %d:%d %s\n",
+ pr_err("%s: failed for device %d:%d %s\n",
__func__, d->major, d->minor, strerror(errno));
return 1;
}
return 0;
}
-
static int create_array(struct supertype *st, int dev_idx)
{
size_t len;
len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0) +
sizeof(*inf) * map->num_members;
- u = malloc(len);
- if (!u) {
- fprintf(stderr, "%s: failed to allocate update buffer\n",
- __func__);
- return 1;
- }
-
+ u = xmalloc(len);
u->type = update_create_array;
u->dev_idx = dev_idx;
imsm_copy_dev(&u->dev, dev);
return 0;
len = sizeof(*u);
- u = malloc(len);
- if (!u) {
- fprintf(stderr, "%s: failed to allocate update buffer\n",
- __func__);
- return 1;
- }
-
+ u = xmalloc(len);
u->type = update_add_remove_disk;
append_metadata_update(st, u, len);
} else {
struct dl *d;
for (d = super->disks; d; d = d->next)
- Kill(d->devname, NULL, 0, 1, 1);
+ Kill(d->devname, NULL, 0, -1, 1);
return write_super_imsm(st, 1);
}
}
#ifndef MDASSEMBLE
static int validate_geometry_imsm_container(struct supertype *st, int level,
int layout, int raiddisks, int chunk,
- unsigned long long size, char *dev,
+ unsigned long long size,
+ unsigned long long data_offset,
+ char *dev,
unsigned long long *freesize,
int verbose)
{
fd = open(dev, O_RDONLY|O_EXCL, 0);
if (fd < 0) {
- if (verbose)
- fprintf(stderr, Name ": imsm: Cannot open %s: %s\n",
+ if (verbose > 0)
+ pr_err("imsm: Cannot open %s: %s\n",
dev, strerror(errno));
return 0;
}
* note that there is no fd for the disks in array.
*/
super = alloc_super();
- if (!super) {
- fprintf(stderr,
- Name ": malloc of %zu failed.\n",
- sizeof(*super));
- close(fd);
- return 0;
- }
-
- rv = find_intel_hba_capability(fd, super, verbose ? dev : NULL);
+ rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL);
if (rv != 0) {
#if DEBUG
char str[256];
return 0;
}
close(fd);
- if (super->orom && raiddisks > super->orom->tds) {
- if (verbose)
- fprintf(stderr, Name ": %d exceeds maximum number of"
- " platform supported disks: %d\n",
- raiddisks, super->orom->tds);
-
- free_imsm(super);
- return 0;
+ 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;
+ }
+ 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;
+ }
}
- *freesize = avail_size_imsm(st, ldsize >> 9);
+ *freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
free_imsm(super);
return 1;
* 'maxsize' given the "all disks in an array must share a common start
* offset" constraint
*/
- struct extent *e = calloc(sum_extents, sizeof(*e));
+ struct extent *e = xcalloc(sum_extents, sizeof(*e));
struct dl *dl;
int i, j;
int start_extent;
unsigned long long maxsize;
unsigned long reserve;
- if (!e)
- return 0;
-
/* coalesce and sort all extents. also, check to see if we need to
* reserve space between member arrays
*/
if (maxsize < reserve)
return 0;
- super->create_offset = ~((__u32) 0);
+ super->create_offset = ~((unsigned long long) 0);
if (start + reserve > super->create_offset)
return 0; /* start overflows create_offset */
super->create_offset = start + reserve;
return 0;
}
-
static int
active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
int dpa, int verbose)
struct dev_member *dev = memb->members;
int fd = -1;
while(dev && (fd < 0)) {
- char *path = malloc(strlen(dev->name) + strlen("/dev/") + 1);
- if (path) {
- num = sprintf(path, "%s%s", "/dev/", dev->name);
- if (num > 0)
- fd = open(path, O_RDONLY, 0);
- if ((num <= 0) || (fd < 0)) {
- pr_vrb(": Cannot open %s: %s\n",
- dev->name, strerror(errno));
- }
- free(path);
+ 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)) {
+ pr_vrb(": Cannot open %s: %s\n",
+ dev->name, strerror(errno));
}
+ free(path);
dev = dev->next;
}
found = 0;
}
}
if (*devlist && (found < dpa)) {
- dv = calloc(1, sizeof(*dv));
- if (dv == NULL)
- fprintf(stderr, Name ": calloc failed\n");
- else {
- dv->devname = malloc(strlen(memb->dev) + strlen("/dev/") + 1);
- if (dv->devname != NULL) {
- sprintf(dv->devname, "%s%s", "/dev/", memb->dev);
- dv->found = found;
- dv->used = 0;
- dv->next = *devlist;
- *devlist = dv;
- } else
- free(dv);
- }
+ dv = xcalloc(1, sizeof(*dv));
+ dv->devname = xmalloc(strlen(memb->dev) + strlen("/dev/") + 1);
+ sprintf(dv->devname, "%s%s", "/dev/", memb->dev);
+ dv->found = found;
+ dv->used = 0;
+ dv->next = *devlist;
+ *devlist = dv;
}
}
if (fd >= 0)
struct md_list *dv = NULL;
for(i = 0; i < 12; i++) {
- dv = calloc(1, sizeof(*dv));
- if (dv == NULL) {
- fprintf(stderr, Name ": calloc failed\n");
- break;
- }
- dv->devname = malloc(40);
- if (dv->devname == NULL) {
- fprintf(stderr, Name ": malloc failed\n");
- free(dv);
- break;
- }
+ dv = xcalloc(1, sizeof(*dv));
+ dv->devname = xmalloc(40);
sprintf(dv->devname, "/dev/loop%d", i);
dv->next = devlist;
devlist = dv;
fd2devname(fd, buf);
close(fd);
} else {
- fprintf(stderr, Name ": cannot open device: %s\n",
+ pr_err("cannot open device: %s\n",
ent->d_name);
continue;
}
-
- dv = calloc(1, sizeof(*dv));
- if (dv == NULL) {
- fprintf(stderr, Name ": malloc failed\n");
- err = 1;
- break;
- }
- dv->devname = strdup(buf);
- if (dv->devname == NULL) {
- fprintf(stderr, Name ": malloc failed\n");
- err = 1;
- free(dv);
- break;
- }
+ dv = xcalloc(1, sizeof(*dv));
+ dv->devname = xstrdup(buf);
dv->next = devlist;
devlist = dv;
}
free(dv);
}
}
+ closedir(dir);
return devlist;
}
return count;
}
-
static int
count_volumes(char *hba, int dpa, int verbose)
{
static int
validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
- int raiddisks, int *chunk, int verbose)
+ int raiddisks, int *chunk, unsigned long long size, int verbose)
{
/* check/set platform and metadata limits/defaults */
if (super->orom && raiddisks > super->orom->dpa) {
return 0;
}
- /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
+ /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
if (!is_raid_level_supported(super->orom, level, raiddisks)) {
pr_vrb(": platform does not support raid%d with %d disk%s\n",
level, raiddisks, raiddisks > 1 ? "s" : "");
layout, level);
return 0;
}
+
+ if (super->orom && (super->orom->attr & IMSM_OROM_ATTR_2TB) == 0 && chunk &&
+ (calc_array_size(level, raiddisks, layout, *chunk, size) >> 32) > 0) {
+ pr_vrb(": platform does not support a volume size over 2TB\n");
+ return 0;
+ }
return 1;
}
-/* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd
+/* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd
* FIX ME add ahci details
*/
static int validate_geometry_imsm_volume(struct supertype *st, int level,
int layout, int raiddisks, int *chunk,
- unsigned long long size, char *dev,
+ unsigned long long size,
+ unsigned long long data_offset,
+ char *dev,
unsigned long long *freesize,
int verbose)
{
mpb = super->anchor;
- if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose)) {
- fprintf(stderr, Name ": RAID gemetry validation failed. "
+ if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, size, verbose)) {
+ pr_err("RAID gemetry validation failed. "
"Cannot proceed with the action(s).\n");
return 0;
}
}
if (dcnt < raiddisks) {
if (verbose)
- fprintf(stderr, Name ": imsm: Not enough "
+ pr_err("imsm: Not enough "
"devices with space for this array "
"(%d < %d)\n",
dcnt, raiddisks);
}
if (!dl) {
if (verbose)
- fprintf(stderr, Name ": %s is not in the "
+ pr_err("%s is not in the "
"same imsm set\n", dev);
return 0;
} else if (super->orom && dl->index < 0 && mpb->num_raid_devs) {
* understand this configuration (all member disks must be
* members of each array in the container).
*/
- fprintf(stderr, Name ": %s is a spare and a volume"
+ pr_err("%s is a spare and a volume"
" is already defined for this container\n", dev);
- fprintf(stderr, Name ": The option-rom requires all member"
+ pr_err("The option-rom requires all member"
" disks to be a member of all volumes\n");
return 0;
} else if (super->orom && mpb->num_raid_devs > 0 &&
mpb->num_disks != raiddisks) {
- fprintf(stderr, Name ": The option-rom requires all member"
+ pr_err("The option-rom requires all member"
" disks to be a member of all volumes\n");
return 0;
}
dl->extent_cnt = i;
} else {
if (verbose)
- fprintf(stderr, Name ": unable to determine free space for: %s\n",
+ pr_err("unable to determine free space for: %s\n",
dev);
return 0;
}
if (maxsize < size) {
if (verbose)
- fprintf(stderr, Name ": %s not enough space (%llu < %llu)\n",
+ pr_err("%s not enough space (%llu < %llu)\n",
dev, maxsize, size);
return 0;
}
if (!check_env("IMSM_NO_PLATFORM") &&
mpb->num_raid_devs > 0 && size && size != maxsize) {
- fprintf(stderr, Name ": attempting to create a second "
+ pr_err("attempting to create a second "
"volume with size less then remaining space. "
"Aborting...\n");
return 0;
if (maxsize < size || maxsize == 0) {
if (verbose) {
if (maxsize == 0)
- fprintf(stderr, Name ": no free space"
+ pr_err("no free space"
" left on device. Aborting...\n");
else
- fprintf(stderr, Name ": not enough space"
+ pr_err("not enough space"
" to create volume of given size"
" (%llu < %llu). Aborting...\n",
maxsize, size);
int count = count_volumes(super->hba->path,
super->orom->dpa, verbose);
if (super->orom->vphba <= count) {
- pr_vrb(": platform does not support more then %d raid volumes.\n",
+ pr_vrb(": platform does not support more than %d raid volumes.\n",
super->orom->vphba);
return 0;
}
return 1;
}
-static int reserve_space(struct supertype *st, int raiddisks,
+static int imsm_get_free_size(struct supertype *st, int raiddisks,
unsigned long long size, int chunk,
unsigned long long *freesize)
{
(super->orom && used && used != raiddisks) ||
maxsize < minsize ||
maxsize == 0) {
- fprintf(stderr, Name ": not enough devices with space to create array.\n");
+ pr_err("not enough devices with space to create array.\n");
return 0; /* No enough free spaces large enough */
}
}
if (!check_env("IMSM_NO_PLATFORM") &&
mpb->num_raid_devs > 0 && size && size != maxsize) {
- fprintf(stderr, Name ": attempting to create a second "
+ pr_err("attempting to create a second "
"volume with size less then remaining space. "
"Aborting...\n");
return 0;
*freesize = size;
+ dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
+
return 1;
}
+static int reserve_space(struct supertype *st, int raiddisks,
+ unsigned long long size, int chunk,
+ unsigned long long *freesize)
+{
+ struct intel_super *super = st->sb;
+ struct dl *dl;
+ int cnt;
+ int rv = 0;
+
+ 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;
+ }
+
+ return rv;
+}
+
static int validate_geometry_imsm(struct supertype *st, int level, int layout,
int raiddisks, int *chunk, unsigned long long size,
+ unsigned long long data_offset,
char *dev, unsigned long long *freesize,
int verbose)
{
/* Must be a fresh device to add to a container */
return validate_geometry_imsm_container(st, level, layout,
raiddisks,
- chunk?*chunk:0, size,
+ chunk?*chunk:0,
+ size, data_offset,
dev, freesize,
verbose);
}
if (st->sb) {
struct intel_super *super = st->sb;
if (!validate_geometry_imsm_orom(st->sb, level, layout,
- raiddisks, chunk,
+ raiddisks, chunk, size,
verbose))
return 0;
/* we are being asked to automatically layout a
super->orom->dpa, verbose);
if (super->orom->vphba <= count) {
pr_vrb(": platform does not support more"
- "then %d raid volumes.\n",
+ " than %d raid volumes.\n",
super->orom->vphba);
return 0;
}
/* creating in a given container */
return validate_geometry_imsm_volume(st, level, layout,
raiddisks, chunk, size,
+ data_offset,
dev, freesize, verbose);
}
fd = open(dev, O_RDONLY|O_EXCL, 0);
if (fd >= 0) {
if (verbose)
- fprintf(stderr,
- Name ": Cannot create this array on device %s\n",
- dev);
+ pr_err("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)
- fprintf(stderr, Name ": Cannot open %s: %s\n",
+ pr_err("Cannot open %s: %s\n",
dev, strerror(errno));
return 0;
}
close(fd);
if (cfd < 0) {
if (verbose)
- fprintf(stderr, Name ": Cannot use %s: It is busy\n",
+ pr_err("Cannot use %s: It is busy\n",
dev);
return 0;
}
- sra = sysfs_read(cfd, 0, GET_VERSION);
+ sra = sysfs_read(cfd, NULL, GET_VERSION);
if (sra && sra->array.major_version == -1 &&
strcmp(sra->text_version, "imsm") == 0)
is_member = 1;
if (load_super_imsm_all(st, cfd, (void **) &super, NULL, NULL, 1) == 0) {
st->sb = super;
- st->container_dev = fd2devnum(cfd);
+ strcpy(st->container_devnm, fd2devnm(cfd));
close(cfd);
return validate_geometry_imsm_volume(st, level, layout,
raiddisks, chunk,
- size, dev,
+ size, data_offset, dev,
freesize, 1)
? 1 : -1;
}
}
if (verbose)
- fprintf(stderr, Name ": failed container membership check\n");
+ pr_err("failed container membership check\n");
close(cfd);
return 0;
if (i < current_vol)
continue;
sprintf(subarray, "%u", i);
- if (is_subarray_active(subarray, st->devname)) {
- fprintf(stderr,
- Name ": deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
- current_vol, i);
+ if (is_subarray_active(subarray, st->devnm)) {
+ pr_err("deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
+ current_vol, i);
return 2;
}
}
if (st->update_tail) {
- struct imsm_update_kill_array *u = malloc(sizeof(*u));
+ struct imsm_update_kill_array *u = xmalloc(sizeof(*u));
- if (!u)
- return 2;
u->type = update_kill_array;
u->dev_idx = current_vol;
append_metadata_update(st, u, sizeof(*u));
char *ep;
int vol;
- if (is_subarray_active(subarray, st->devname)) {
- fprintf(stderr,
- Name ": Unable to update name of active subarray\n");
+ if (is_subarray_active(subarray, st->devnm)) {
+ pr_err("Unable to update name of active subarray\n");
return 2;
}
return 2;
if (st->update_tail) {
- struct imsm_update_rename_array *u = malloc(sizeof(*u));
+ struct imsm_update_rename_array *u = xmalloc(sizeof(*u));
- if (!u)
- return 2;
u->type = update_rename_array;
u->dev_idx = vol;
snprintf((char *) u->name, MAX_RAID_SERIAL_LEN, "%s", name);
/* do not assemble arrays when not all attributes are supported */
if (imsm_check_attributes(mpb->attributes) == 0) {
sb_errors = 1;
- fprintf(stderr, Name ": Unsupported attributes in IMSM metadata."
+ pr_err("Unsupported attributes in IMSM metadata."
"Arrays activation is blocked.\n");
}
/* check for bad blocks */
if (imsm_bbm_log_size(super->anchor)) {
- fprintf(stderr, Name ": BBM log found in IMSM metadata."
- "Arrays activation is blocked.\n");
+ pr_err("BBM log found in IMSM metadata."
+ "Arrays activation is blocked.\n");
sb_errors = 1;
}
-
/* count spare devices, not used in maps
*/
for (d = super->disks; d; d = d->next)
*/
if (dev->vol.migr_state &&
(migr_type(dev) == MIGR_STATE_CHANGE)) {
- fprintf(stderr, Name ": cannot assemble volume '%.16s':"
+ pr_err("cannot assemble volume '%.16s':"
" unsupported migration in progress\n",
dev->volume);
continue;
* OROM/EFI
*/
- this = malloc(sizeof(*this));
- if (!this) {
- fprintf(stderr, Name ": failed to allocate %zu bytes\n",
- sizeof(*this));
- break;
- }
+ this = xmalloc(sizeof(*this));
super->current_vol = i;
getinfo_super_imsm_volume(st, this, NULL);
get_imsm_raid_level(map), /* RAID level */
imsm_level_to_layout(get_imsm_raid_level(map)),
map->num_members, /* raid disks */
- &chunk,
+ &chunk, join_u32(dev->size_low, dev->size_high),
1 /* verbose */)) {
- fprintf(stderr, Name ": IMSM RAID geometry validation"
+ pr_err("IMSM RAID geometry validation"
" failed. Array %s activation is blocked.\n",
dev->volume);
this->array.state |=
if (ord & IMSM_ORD_REBUILD)
recovery_start = 0;
- /*
+ /*
* if we skip some disks the array will be assmebled degraded;
* reset resync start to avoid a dirty-degraded
* situation when performing the intial sync
if (skip)
continue;
- info_d = calloc(1, sizeof(*info_d));
- if (!info_d) {
- fprintf(stderr, Name ": failed to allocate disk"
- " for volume %.16s\n", dev->volume);
- info_d = this->devs;
- while (info_d) {
- struct mdinfo *d = info_d->next;
-
- free(info_d);
- info_d = d;
- }
- free(this);
- this = rest;
- break;
- }
+ info_d = xcalloc(1, sizeof(*info_d));
info_d->next = this->devs;
this->devs = info_d;
this->array.working_disks++;
info_d->events = __le32_to_cpu(mpb->generation_num);
- info_d->data_offset = __le32_to_cpu(map->pba_of_lba0);
- info_d->component_size = __le32_to_cpu(map->blocks_per_member);
+ info_d->data_offset = pba_of_lba0(map);
+ info_d->component_size = blocks_per_member(map);
}
/* now that the disk list is up-to-date fixup recovery_start */
update_recovery_start(super, dev, this);
return rest;
}
-
static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
int failed, int look_in_map)
{
map = get_imsm_map(dev, look_in_map);
if (!failed)
- return map->map_state == IMSM_T_STATE_UNINITIALIZED ?
+ return map->map_state == IMSM_T_STATE_UNINITIALIZED ?
IMSM_T_STATE_UNINITIALIZED : IMSM_T_STATE_NORMAL;
switch (get_imsm_raid_level(map)) {
struct imsm_disk *disk;
/* reset the potential in-sync count on even-numbered
- * slots. num_copies is always 2 for imsm raid10
+ * slots. num_copies is always 2 for imsm raid10
*/
if ((i & 1) == 0)
insync = 2;
struct imsm_super *mpb = super->anchor;
if (atoi(inst) >= mpb->num_raid_devs) {
- fprintf(stderr, "%s: subarry index %d, out of range\n",
+ pr_err("%s: subarry index %d, out of range\n",
__func__, atoi(inst));
return -ENODEV;
}
if (!super->missing)
return;
+ /* When orom adds replacement for missing disk it does
+ * not remove entry of missing disk, but just updates map with
+ * new added disk. So it is not enough just to test if there is
+ * any missing disk, we have to look if there are any failed disks
+ * in map to stop migration */
+
dprintf("imsm: mark missing\n");
/* end process for initialization and rebuild only
*/
failed = imsm_count_failed(super, dev, MAP_0);
map_state = imsm_check_degraded(super, dev, failed, MAP_0);
- end_migration(dev, super, map_state);
+ if (failed)
+ end_migration(dev, super, map_state);
}
for (dl = super->missing; dl; dl = dl->next)
mark_missing(dev, &dl->disk, dl->index);
super->updates_pending++;
}
-static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
+static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
+ long long new_size)
{
int used_disks = imsm_num_data_members(dev, MAP_0);
unsigned long long array_blocks;
/* set array size in metadata
*/
- map = get_imsm_map(dev, MAP_0);
- array_blocks = map->blocks_per_member * used_disks;
+ if (new_size <= 0) {
+ /* OLCE size change is caused by added disks
+ */
+ map = get_imsm_map(dev, MAP_0);
+ array_blocks = blocks_per_member(map) * used_disks;
+ } else {
+ /* Online Volume Size Change
+ * Using available free space
+ */
+ array_blocks = new_size;
+ }
/* round array size down to closest MB
*/
memcpy(map2, map, copy_map_size);
map2->num_members = prev_num_members;
- imsm_set_array_size(dev);
+ imsm_set_array_size(dev, -1);
super->clean_migration_record_by_mdmon = 1;
super->updates_pending++;
}
used_disks = imsm_num_data_members(dev, MAP_0);
if (used_disks > 0) {
array_blocks =
- map->blocks_per_member *
+ blocks_per_member(map) *
used_disks;
/* round array size down to closest MB
*/
struct imsm_dev *dev = get_imsm_dev(super, inst);
struct imsm_map *map = get_imsm_map(dev, MAP_0);
struct imsm_disk *disk;
+ struct mdinfo *mdi;
+ int recovery_not_finished = 0;
int failed;
__u32 ord;
__u8 map_state;
if (n > map->num_members)
- fprintf(stderr, "imsm: set_disk %d out of range 0..%d\n",
+ pr_err("imsm: set_disk %d out of range 0..%d\n",
n, map->num_members - 1);
if (n < 0)
dprintf("normal: ");
if (is_rebuilding(dev)) {
dprintf("while rebuilding");
+ /* check if recovery is really finished */
+ for (mdi = a->info.devs; mdi ; mdi = mdi->next)
+ if (mdi->recovery_start != MaxSector) {
+ recovery_not_finished = 1;
+ break;
+ }
+ if (recovery_not_finished) {
+ dprintf("\nimsm: Rebuild has not finished yet, "
+ "state not changed");
+ if (a->last_checkpoint < mdi->recovery_start) {
+ a->last_checkpoint = mdi->recovery_start;
+ super->updates_pending++;
+ }
+ break;
+ }
end_migration(dev, super, map_state);
map = get_imsm_map(dev, MAP_0);
map->failed_disk_num = ~0;
found = 0;
j = 0;
pos = 0;
- array_start = __le32_to_cpu(map->pba_of_lba0);
+ array_start = pba_of_lba0(map);
array_end = array_start +
- __le32_to_cpu(map->blocks_per_member) - 1;
+ blocks_per_member(map) - 1;
do {
/* check that we can start at pba_of_lba0 with
return dl;
}
-
static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed)
{
struct imsm_dev *dev2;
dl = imsm_add_spare(super, i, a, 1, rv);
if (!dl)
continue;
-
+
/* found a usable disk with enough space */
- di = malloc(sizeof(*di));
- if (!di)
- continue;
- memset(di, 0, sizeof(*di));
+ di = xcalloc(1, sizeof(*di));
/* dl->index will be -1 in the case we are activating a
* pristine spare. imsm_process_update() will create a
di->disk.minor = dl->minor;
di->disk.state = 0;
di->recovery_start = 0;
- di->data_offset = __le32_to_cpu(map->pba_of_lba0);
+ di->data_offset = pba_of_lba0(map);
di->component_size = a->info.component_size;
di->container_member = inst;
super->random = random32();
* Create a metadata_update record to update the
* disk_ord_tbl for the array
*/
- mu = malloc(sizeof(*mu));
- if (mu) {
- mu->buf = malloc(sizeof(struct imsm_update_activate_spare) * num_spares);
- if (mu->buf == NULL) {
- free(mu);
- mu = NULL;
- }
- }
- if (!mu) {
- while (rv) {
- struct mdinfo *n = rv->next;
-
- free(rv);
- rv = n;
- }
- return NULL;
- }
-
+ mu = xmalloc(sizeof(*mu));
+ mu->buf = xcalloc(num_spares,
+ sizeof(struct imsm_update_activate_spare));
mu->space = NULL;
mu->space_list = NULL;
mu->len = sizeof(struct imsm_update_activate_spare) * num_spares;
return 0;
}
-
static struct dl *get_disk_super(struct intel_super *super, int major, int minor)
{
struct dl *dl = NULL;
return check_degraded;
}
-
static int apply_reshape_migration_update(struct imsm_update_reshape_migration *u,
struct intel_super *super,
void ***space_list)
*tofree = *space_list;
/* calculate new size
*/
- imsm_set_array_size(new_dev);
+ imsm_set_array_size(new_dev, -1);
ret_val = 1;
}
return ret_val;
}
+static int apply_size_change_update(struct imsm_update_size_change *u,
+ struct intel_super *super)
+{
+ struct intel_dev *id;
+ int ret_val = 0;
+
+ dprintf("apply_size_change_update()\n");
+ if ((u->subdev < 0) ||
+ (u->subdev > 1)) {
+ dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
+ return ret_val;
+ }
+
+ for (id = super->devlist ; id; id = id->next) {
+ if (id->index == (unsigned)u->subdev) {
+ struct imsm_dev *dev = get_imsm_dev(super, u->subdev);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ int used_disks = imsm_num_data_members(dev, MAP_0);
+ unsigned long long blocks_per_member;
+
+ /* calculate new size
+ */
+ blocks_per_member = u->new_size / used_disks;
+ dprintf("imsm: apply_size_change_update(size: %llu, "
+ "blocks per member: %llu)\n",
+ u->new_size, blocks_per_member);
+ set_blocks_per_member(map, blocks_per_member);
+ imsm_set_array_size(dev, 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)
break;
if (!dl) {
- fprintf(stderr, "error: imsm_activate_spare passed "
+ pr_err("error: imsm_activate_spare passed "
"an unknown disk (index: %d)\n",
u->dl->index);
return 0;
newmap = get_imsm_map(newdev, MAP_1);
memcpy(newmap, oldmap, sizeof_imsm_map(oldmap));
- imsm_set_array_size(newdev);
+ imsm_set_array_size(newdev, -1);
}
sp = (void **)id->dev;
* the arrays for general migration and convert selected spares
* into active devices.
* update_activate_spare - a spare device has replaced a failed
- * device in an array, update the disk_ord_tbl. If this disk is
- * present in all member arrays then also clear the SPARE_DISK
- * flag
+ * device in an array, update the disk_ord_tbl. If this disk is
+ * present in all member arrays then also clear the SPARE_DISK
+ * flag
* update_create_array
* update_kill_array
* update_rename_array
super->updates_pending++;
break;
}
+ case update_size_change: {
+ struct imsm_update_size_change *u = (void *)update->buf;
+ if (apply_size_change_update(u, super))
+ super->updates_pending++;
+ break;
+ }
case update_activate_spare: {
- struct imsm_update_activate_spare *u = (void *) update->buf;
+ struct imsm_update_activate_spare *u = (void *) update->buf;
if (apply_update_activate_spare(u, super, st->arrays))
super->updates_pending++;
break;
}
new_map = get_imsm_map(&u->dev, MAP_0);
- new_start = __le32_to_cpu(new_map->pba_of_lba0);
- new_end = new_start + __le32_to_cpu(new_map->blocks_per_member);
+ new_start = pba_of_lba0(new_map);
+ new_end = new_start + blocks_per_member(new_map);
inf = get_disk_info(u);
/* handle activate_spare versus create race:
for (i = 0; i < mpb->num_raid_devs; i++) {
dev = get_imsm_dev(super, i);
map = get_imsm_map(dev, MAP_0);
- start = __le32_to_cpu(map->pba_of_lba0);
- end = start + __le32_to_cpu(map->blocks_per_member);
+ start = pba_of_lba0(map);
+ end = start + blocks_per_member(map);
if ((new_start >= start && new_start <= end) ||
(start >= new_start && start <= new_end))
/* overlap */;
break;
}
default:
- fprintf(stderr, "error: unsuported process update type:"
+ pr_err("error: unsuported process update type:"
"(type: %d)\n", type);
}
}
int num_members = map->num_members;
void *space;
int size, i;
- int err = 0;
/* allocate memory for added disks */
for (i = 0; i < num_members; i++) {
size = sizeof(struct dl);
- space = malloc(size);
- if (!space) {
- err++;
- break;
- }
+ space = xmalloc(size);
*tail = space;
tail = space;
*tail = NULL;
/* allocate memory for new device */
size = sizeof_imsm_dev(super->devlist->dev, 0) +
(num_members * sizeof(__u32));
- space = malloc(size);
- if (!space)
- err++;
- else {
- *tail = space;
- tail = space;
- *tail = NULL;
- }
- if (!err) {
- len = disks_to_mpb_size(num_members * 2);
- } else {
- /* if allocation didn't success, free buffer */
- while (update->space_list) {
- void **sp = update->space_list;
- update->space_list = *sp;
- free(sp);
- }
- }
+ space = xmalloc(size);
+ *tail = space;
+ tail = space;
+ *tail = NULL;
+ len = disks_to_mpb_size(num_members * 2);
}
break;
if (u->new_raid_disks > u->old_raid_disks)
size += sizeof(__u32)*2*
(u->new_raid_disks - u->old_raid_disks);
- s = malloc(size);
- if (!s)
- break;
+ s = xmalloc(size);
*space_tail = s;
space_tail = s;
*space_tail = NULL;
if (u->new_raid_disks > u->old_raid_disks)
size += sizeof(__u32)*2*
(u->new_raid_disks - u->old_raid_disks);
- s = malloc(size);
- if (!s)
- break;
+ s = xmalloc(size);
*space_tail = s;
space_tail = s;
*space_tail = NULL;
/* add space for disk in update
*/
size = sizeof(struct dl);
- s = malloc(size);
- if (!s) {
- free(update->space_list);
- update->space_list = NULL;
- break;
- }
+ s = xmalloc(size);
*space_tail = s;
space_tail = s;
*space_tail = NULL;
dprintf("New anchor length is %llu\n", (unsigned long long)len);
break;
}
+ case update_size_change: {
+ break;
+ }
case update_create_array: {
struct imsm_update_create_array *u = (void *) update->buf;
struct intel_dev *dv;
inf = get_disk_info(u);
len = sizeof_imsm_dev(dev, 1);
/* allocate a new super->devlist entry */
- dv = malloc(sizeof(*dv));
- if (dv) {
- dv->dev = malloc(len);
- if (dv->dev)
- update->space = dv;
- else {
- free(dv);
- update->space = NULL;
- }
- }
+ dv = xmalloc(sizeof(*dv));
+ dv->dev = xmalloc(len);
+ update->space = dv;
/* count how many spares will be converted to members */
for (i = 0; i < map->num_members; i++) {
}
}
-
/*******************************************************************************
* Function: open_backup_targets
* Description: Function opens file descriptors for all devices given in
sd->disk.minor, 1);
raid_fds[sd->disk.raid_disk] = dev_open(dn, O_RDWR);
if (raid_fds[sd->disk.raid_disk] < 0) {
- fprintf(stderr, "cannot open component\n");
+ pr_err("cannot open component\n");
continue;
}
opened++;
imsm_get_allowed_degradation(info->new_level,
raid_disks,
super, dev)) {
- fprintf(stderr, "Not enough disks can be opened.\n");
+ pr_err("Not enough disks can be opened.\n");
close_targets(raid_fds, raid_disks);
return -2;
}
migr_rec->post_migr_vol_cap = dev->size_low;
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);
unsigned long long start;
int data_disks = imsm_num_data_members(dev, MAP_0);
- targets = malloc(new_disks * sizeof(int));
- if (!targets)
- goto abort;
+ targets = xmalloc(new_disks * sizeof(int));
for (i = 0; i < new_disks; i++)
targets[i] = -1;
- target_offsets = malloc(new_disks * sizeof(unsigned long long));
- if (!target_offsets)
- goto abort;
+ target_offsets = xcalloc(new_disks, sizeof(unsigned long long));
start = info->reshape_progress * 512;
for (i = 0; i < new_disks; i++) {
start,
length,
buf) != 0) {
- fprintf(stderr, Name ": Error restoring stripes\n");
+ pr_err("Error restoring stripes\n");
goto abort;
}
write_offset = ((unsigned long long)
__le32_to_cpu(migr_rec->dest_1st_member_lba) +
- __le32_to_cpu(map_dest->pba_of_lba0)) * 512;
+ pba_of_lba0(map_dest)) * 512;
unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
if (posix_memalign((void **)&buf, 512, unit_len) != 0)
goto abort;
- targets = malloc(new_disks * sizeof(int));
- if (!targets)
- goto abort;
+ targets = xcalloc(new_disks, sizeof(int));
if (open_backup_targets(info, new_disks, targets, super, id->dev)) {
- fprintf(stderr,
- Name ": Cannot open some devices belonging to array.\n");
+ pr_err("Cannot open some devices belonging to array.\n");
goto abort;
}
continue;
}
if (lseek64(targets[i], read_offset, SEEK_SET) < 0) {
- fprintf(stderr,
- Name ": Cannot seek to block: %s\n",
- strerror(errno));
+ pr_err("Cannot seek to block: %s\n",
+ strerror(errno));
skipped_disks++;
continue;
}
if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
- fprintf(stderr,
- Name ": Cannot read copy area block: %s\n",
- strerror(errno));
+ pr_err("Cannot read copy area block: %s\n",
+ strerror(errno));
skipped_disks++;
continue;
}
if (lseek64(targets[i], write_offset, SEEK_SET) < 0) {
- fprintf(stderr,
- Name ": Cannot seek to block: %s\n",
- strerror(errno));
+ pr_err("Cannot seek to block: %s\n",
+ strerror(errno));
skipped_disks++;
continue;
}
if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
- fprintf(stderr,
- Name ": Cannot restore block: %s\n",
- strerror(errno));
+ pr_err("Cannot restore block: %s\n",
+ strerror(errno));
skipped_disks++;
continue;
}
new_disks,
super,
id->dev)) {
- fprintf(stderr,
- Name ": Cannot restore data from backup."
- " Too many failed disks\n");
+ pr_err("Cannot restore data from backup."
+ " Too many failed disks\n");
goto abort;
}
drv = "isci";
else if (hba && hba->type == SYS_DEV_SATA)
drv = "ahci";
- else
+ else
drv = "unknown";
dprintf("path: %s hba: %s attached: %s\n",
path, (hba) ? hba->path : "NULL", drv);
free(path);
- if (hba)
- free_sys_dev(&hba);
}
return drv;
}
-static int imsm_find_array_minor_by_subdev(int subdev, int container, int *minor)
+static char *imsm_find_array_devnm_by_subdev(int subdev, char *container)
{
+ static char devnm[32];
char subdev_name[20];
struct mdstat_ent *mdstat;
sprintf(subdev_name, "%d", subdev);
mdstat = mdstat_by_subdev(subdev_name, container);
if (!mdstat)
- return -1;
+ return NULL;
- *minor = mdstat->devnum;
+ strcpy(devnm, mdstat->devnm);
free_mdstat(mdstat);
- return 0;
+ return devnm;
}
static int imsm_reshape_is_allowed_on_container(struct supertype *st,
struct geo_params *geo,
- int *old_raid_disks)
+ int *old_raid_disks,
+ int direction)
{
/* currently we only support increasing the number of devices
* for a container. This increases the number of device for each
int devices_that_can_grow = 0;
dprintf("imsm: imsm_reshape_is_allowed_on_container(ENTER): "
- "st->devnum = (%i)\n",
- st->devnum);
+ "st->devnm = (%s)\n", st->devnm);
- if (geo->size != -1 ||
+ if (geo->size > 0 ||
geo->level != UnSet ||
geo->layout != UnSet ||
geo->chunksize != 0 ||
return ret_val;
}
+ if (direction == ROLLBACK_METADATA_CHANGES) {
+ dprintf("imsm: Metadata changes rollback is not supported for "
+ "container operation.\n");
+ return ret_val;
+ }
+
info = container_content_imsm(st, NULL);
for (member = info; member; member = member->next) {
- int result;
- int minor;
+ char *result;
dprintf("imsm: checking device_num: %i\n",
member->container_member);
* so they need to be assembled. We have already
* checked that no recovery etc is happening.
*/
- result = imsm_find_array_minor_by_subdev(member->container_member,
- st->container_dev,
- &minor);
- if (result < 0) {
+ result = imsm_find_array_devnm_by_subdev(member->container_member,
+ st->container_devnm);
+ if (result == NULL) {
dprintf("imsm: cannot find array\n");
break;
}
/* Function: get_spares_for_grow
* Description: Allocates memory and creates list of spare devices
- * avaliable in container. Checks if spare drive size is acceptable.
+ * avaliable in container. Checks if spare drive size is acceptable.
* Parameters: Pointer to the supertype structure
* Returns: Pointer to the list of spare devices (mdinfo structure) on success,
- * NULL if fail
+ * NULL if fail
*/
static struct mdinfo *get_spares_for_grow(struct supertype *st)
{
/* now add space for spare disks that we need to add. */
update_memory_size += sizeof(u->new_disks[0]) * (delta_disks - 1);
- u = calloc(1, update_memory_size);
- if (u == NULL) {
- dprintf("error: "
- "cannot get memory for imsm_update_reshape update\n");
- return 0;
- }
+ u = xcalloc(1, update_memory_size);
u->type = update_reshape_container_disks;
u->old_raid_disks = old_raid_disks;
u->new_raid_disks = geo->raid_disks;
if (spares == NULL
|| delta_disks > spares->array.spare_disks) {
- fprintf(stderr, Name ": imsm: ERROR: Cannot get spare devices "
+ pr_err("imsm: ERROR: Cannot get spare devices "
"for %s.\n", geo->dev_name);
i = -1;
goto abort;
return 0;
}
+/******************************************************************************
+ * function: imsm_create_metadata_update_for_size_change()
+ * Creates update for IMSM array for array size change.
+ *
+ ******************************************************************************/
+static int imsm_create_metadata_update_for_size_change(
+ struct supertype *st,
+ struct geo_params *geo,
+ struct imsm_update_size_change **updatep)
+{
+ struct intel_super *super = st->sb;
+ int update_memory_size = 0;
+ struct imsm_update_size_change *u = NULL;
+
+ dprintf("imsm_create_metadata_update_for_size_change(enter)"
+ " New size = %llu\n", geo->size);
+
+ /* size of all update data without anchor */
+ update_memory_size = sizeof(struct imsm_update_size_change);
+
+ u = xcalloc(1, update_memory_size);
+ u->type = update_size_change;
+ u->subdev = super->current_vol;
+ u->new_size = geo->size;
+
+ dprintf("imsm: reshape update preparation : OK\n");
+ *updatep = u;
+
+ return update_memory_size;
+}
+
/******************************************************************************
* function: imsm_create_metadata_update_for_migration()
* Creates update for IMSM array.
/* size of all update data without anchor */
update_memory_size = sizeof(struct imsm_update_reshape_migration);
- u = calloc(1, update_memory_size);
- if (u == NULL) {
- dprintf("error: cannot get memory for "
- "imsm_create_metadata_update_for_migration\n");
- return 0;
- }
+ u = xcalloc(1, update_memory_size);
u->type = update_reshape_migration;
u->subdev = super->current_vol;
u->new_level = geo->level;
/***************************************************************************
* Function: imsm_analyze_change
* Description: Function analyze change for single volume
-* and validate if transition is supported
-* Parameters: Geometry parameters, supertype structure
+* and validate if transition is supported
+* Parameters: Geometry parameters, supertype structure,
+* metadata change direction (apply/rollback)
* Returns: Operation type code on success, -1 if fail
****************************************************************************/
enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
- struct geo_params *geo)
+ struct geo_params *geo,
+ int direction)
{
struct mdinfo info;
int change = -1;
int devNumChange = 0;
/* imsm compatible layout value for array geometry verification */
int imsm_layout = -1;
+ int data_disks;
+ struct imsm_dev *dev;
+ struct intel_super *super;
+ unsigned long long current_size;
+ unsigned long long free_size;
+ unsigned long long max_size;
+ int rv;
getinfo_super_imsm_volume(st, &info, NULL);
if ((geo->level != info.array.level) &&
if (geo->level == 5) {
change = CH_MIGRATION;
if (geo->layout != ALGORITHM_LEFT_ASYMMETRIC) {
- fprintf(stderr,
- Name " Error. Requested Layout "
- "not supported (left-asymmetric layout "
- "is supported only)!\n");
+ pr_err("Error. Requested Layout "
+ "not supported (left-asymmetric layout "
+ "is supported only)!\n");
change = -1;
goto analyse_change_exit;
}
break;
}
if (change == -1) {
- fprintf(stderr,
- Name " Error. Level Migration from %d to %d "
- "not supported!\n",
- info.array.level, geo->level);
+ pr_err("Error. Level Migration from %d to %d "
+ "not supported!\n",
+ info.array.level, geo->level);
goto analyse_change_exit;
}
} else
geo->layout = 0;
geo->level = 5;
} else {
- fprintf(stderr,
- Name " Error. Layout Migration from %d to %d "
- "not supported!\n",
- info.array.layout, geo->layout);
+ pr_err("Error. Layout Migration from %d to %d "
+ "not supported!\n",
+ info.array.layout, geo->layout);
change = -1;
goto analyse_change_exit;
}
geo->chunksize = info.array.chunk_size;
chunk = geo->chunksize / 1024;
+
+ super = st->sb;
+ dev = get_imsm_dev(super, super->current_vol);
+ data_disks = imsm_num_data_members(dev , MAP_0);
+ /* compute current size per disk member
+ */
+ current_size = info.custom_array_size / data_disks;
+
+ if ((geo->size > 0) && (geo->size != MAX_SIZE)) {
+ /* align component size
+ */
+ geo->size = imsm_component_size_aligment_check(
+ get_imsm_raid_level(dev->vol.map),
+ chunk * 1024,
+ geo->size * 2);
+ if (geo->size == 0) {
+ pr_err("Error. Size expansion is " \
+ "supported only (current size is %llu, " \
+ "requested size /rounded/ is 0).\n",
+ current_size);
+ goto analyse_change_exit;
+ }
+ }
+
+ if ((current_size != geo->size) && (geo->size > 0)) {
+ if (change != -1) {
+ pr_err("Error. Size change should be the only "
+ "one at a time.\n");
+ change = -1;
+ goto analyse_change_exit;
+ }
+ if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
+ pr_err("Error. The last volume in container "
+ "can be expanded only (%i/%s).\n",
+ super->current_vol, st->devnm);
+ goto analyse_change_exit;
+ }
+ /* check the maximum available size
+ */
+ rv = imsm_get_free_size(st, dev->vol.map->num_members,
+ 0, chunk, &free_size);
+ if (rv == 0)
+ /* Cannot find maximum available space
+ */
+ max_size = 0;
+ else {
+ max_size = free_size + current_size;
+ /* align component size
+ */
+ max_size = imsm_component_size_aligment_check(
+ get_imsm_raid_level(dev->vol.map),
+ chunk * 1024,
+ max_size);
+ }
+ if (geo->size == MAX_SIZE) {
+ /* requested size change to the maximum available size
+ */
+ if (max_size == 0) {
+ pr_err("Error. Cannot find "
+ "maximum available space.\n");
+ change = -1;
+ goto analyse_change_exit;
+ } else
+ geo->size = max_size;
+ }
+
+ if ((direction == ROLLBACK_METADATA_CHANGES)) {
+ /* accept size for rollback only
+ */
+ } else {
+ /* round size due to metadata compatibility
+ */
+ geo->size = (geo->size >> SECT_PER_MB_SHIFT)
+ << SECT_PER_MB_SHIFT;
+ dprintf("Prepare update for size change to %llu\n",
+ geo->size );
+ if (current_size >= geo->size) {
+ pr_err("Error. Size expansion is "
+ "supported only (current size is %llu, "
+ "requested size /rounded/ is %llu).\n",
+ current_size, geo->size);
+ goto analyse_change_exit;
+ }
+ if (max_size && geo->size > max_size) {
+ pr_err("Error. Requested size is larger "
+ "than maximum available size (maximum "
+ "available size is %llu, "
+ "requested size /rounded/ is %llu).\n",
+ max_size, geo->size);
+ goto analyse_change_exit;
+ }
+ }
+ geo->size *= data_disks;
+ geo->raid_disks = dev->vol.map->num_members;
+ change = CH_ARRAY_SIZE;
+ }
if (!validate_geometry_imsm(st,
geo->level,
imsm_layout,
geo->raid_disks + devNumChange,
&chunk,
- geo->size,
+ geo->size, INVALID_SECTORS,
0, 0, 1))
change = -1;
struct imsm_super *mpb = super->anchor;
if (mpb->num_raid_devs > 1) {
- fprintf(stderr,
- Name " 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;
}
}
analyse_change_exit:
-
+ if ((direction == ROLLBACK_METADATA_CHANGES) &&
+ ((change == CH_MIGRATION) || (change == CH_TAKEOVER))) {
+ dprintf("imsm: Metadata changes rollback is not supported for "
+ "migration and takeover operations.\n");
+ change = -1;
+ }
return change;
}
struct intel_super *super = st->sb;
struct imsm_update_takeover *u;
- u = malloc(sizeof(struct imsm_update_takeover));
- if (u == NULL)
- return 1;
+ u = xmalloc(sizeof(struct imsm_update_takeover));
u->type = update_takeover;
u->subarray = super->current_vol;
return 0;
}
-static int imsm_reshape_super(struct supertype *st, long long size, int level,
+static int imsm_reshape_super(struct supertype *st, unsigned long long size,
+ int level,
int layout, int chunksize, int raid_disks,
int delta_disks, char *backup, char *dev,
- int verbose)
+ int direction, int verbose)
{
int ret_val = 1;
struct geo_params geo;
memset(&geo, 0, sizeof(struct geo_params));
geo.dev_name = dev;
- geo.dev_id = st->devnum;
+ strcpy(geo.devnm, st->devnm);
geo.size = size;
geo.level = level;
geo.layout = layout;
if (experimental() == 0)
return ret_val;
- if (st->container_dev == st->devnum) {
+ if (strcmp(st->container_devnm, st->devnm) == 0) {
/* On container level we can only increase number of devices. */
dprintf("imsm: info: Container operation\n");
int old_raid_disks = 0;
if (imsm_reshape_is_allowed_on_container(
- st, &geo, &old_raid_disks)) {
+ st, &geo, &old_raid_disks, direction)) {
struct imsm_update_reshape *u = NULL;
int len;
free(u);
} else {
- fprintf(stderr, Name ": (imsm) Operation "
+ pr_err("(imsm) Operation "
"is not allowed on this container\n");
}
} else {
*/
struct intel_super *super = st->sb;
struct intel_dev *dev = super->devlist;
- int change, devnum;
+ int change;
dprintf("imsm: info: Volume operation\n");
/* find requested device */
while (dev) {
- if (imsm_find_array_minor_by_subdev(
- dev->index, st->container_dev, &devnum) == 0
- && devnum == geo.dev_id)
+ char *devnm =
+ imsm_find_array_devnm_by_subdev(
+ dev->index, st->container_devnm);
+ if (devnm && strcmp(devnm, geo.devnm) == 0)
break;
dev = dev->next;
}
if (dev == NULL) {
- fprintf(stderr, Name " Cannot find %s (%i) subarray\n",
- geo.dev_name, geo.dev_id);
+ pr_err("Cannot find %s (%s) subarray\n",
+ geo.dev_name, geo.devnm);
goto exit_imsm_reshape_super;
}
super->current_vol = dev->index;
- change = imsm_analyze_change(st, &geo);
+ change = imsm_analyze_change(st, &geo, direction);
switch (change) {
case CH_TAKEOVER:
ret_val = imsm_takeover(st, &geo);
free(u);
}
break;
+ case CH_ARRAY_SIZE: {
+ struct imsm_update_size_change *u = NULL;
+ int len =
+ imsm_create_metadata_update_for_size_change(
+ st, &geo, &u);
+ if (len < 1) {
+ dprintf("imsm: "
+ "Cannot prepare update\n");
+ break;
+ }
+ ret_val = 0;
+ /* update metadata locally */
+ imsm_update_metadata_locally(st, u, len);
+ /* and possibly remotely */
+ if (st->update_tail)
+ append_metadata_update(st, u, len);
+ else
+ free(u);
+ }
+ break;
default:
ret_val = 1;
}
do {
char action[20];
- fd_set rfds;
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
- select(fd+1, &rfds, NULL, NULL, NULL);
+ sysfs_wait(fd, NULL);
if (sysfs_get_str(sra, NULL, "sync_action",
action, 20) > 0 &&
strncmp(action, "reshape", 7) != 0)
int degraded)
{
unsigned long long new_degraded;
- sysfs_get_ll(info, NULL, "degraded", &new_degraded);
- if (new_degraded != (unsigned long long)degraded) {
+ int rv;
+
+ rv = sysfs_get_ll(info, NULL, "degraded", &new_degraded);
+ if ((rv == -1) || (new_degraded != (unsigned long long)degraded)) {
/* check each device to ensure it is still working */
struct mdinfo *sd;
new_degraded = 0;
}
/* Only one volume can migrate at the same time */
if (migr_vol_qan != 1) {
- fprintf(stderr, Name " : %s", migr_vol_qan ?
+ pr_err(": %s", migr_vol_qan ?
"Number of migrating volumes greater than 1\n" :
"There is no volume during migrationg\n");
goto abort;
.add_to_super = add_to_super_imsm,
.remove_from_super = remove_from_super_imsm,
.detail_platform = detail_platform_imsm,
+ .export_detail_platform = export_detail_platform_imsm,
.kill_subarray = kill_subarray_imsm,
.update_subarray = update_subarray_imsm,
.load_container = load_container_imsm,
.reshape_super = imsm_reshape_super,
.manage_reshape = imsm_manage_reshape,
.recover_backup = recover_backup_imsm,
+ .copy_metadata = copy_metadata_imsm,
#endif
.match_home = match_home_imsm,
.uuid_from_super= uuid_from_super_imsm,
.match_metadata_desc = match_metadata_desc_imsm,
.container_content = container_content_imsm,
-
.external = 1,
.name = "imsm",