#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 */
+ __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 */
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 geo_params {
- int dev_id;
+ char devnm[32];
char *dev_name;
unsigned long long size;
int level;
enum imsm_update_type type;
};
-
static const char *_sys_dev_type[] = {
[SYS_DEV_UNKNOWN] = "Unknown",
[SYS_DEV_SAS] = "SAS",
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 = xcalloc(1, sizeof(*st));
- st->container_dev = NoMdDev;
st->ss = &super_imsm;
st->max_devs = IMSM_MAX_DEVICES;
st->minor_version = 0;
}
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
/*******************************************************************************
* 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)
{
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;
else
result = 0;
}
- free_sys_dev(&list);
return result;
}
if (verbose > 0)
pr_err("no active Intel(R) RAID "
"controller found.\n");
- free_sys_dev(&list);
return 2;
} else if (verbose > 0)
print_found_intel_controllers(list);
pr_err("no active Intel(R) RAID "
"controller found under %s\n",controller_path);
- free_sys_dev(&list);
return result;
}
if (verbose > 0)
pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_INTEL_DEVICES\n");
result = 2;
- free_sys_dev(&list);
return result;
}
* 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.
return update_memory_size;
}
-
static void imsm_update_metadata_locally(struct supertype *st,
void *buf, int len);
struct imsm_map *prev_map = get_imsm_map(dev, MAP_1);
struct imsm_map *map_to_analyse = map;
struct dl *dl;
- char *devname;
int map_disks = info->array.raid_disks;
memset(info, 0, sizeof(*info));
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;
}
-
/* if 'first' is a spare promote it to a populated mpb with sec's
* family number
*/
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 (__le32_to_cpu(mpb->bbm_log_size)) {
ptr = mpb;
ptr += mpb->mpb_size - __le32_to_cpu(mpb->bbm_log_size);
- }
+ }
return ptr;
}
hba = hba->next;
}
- fprintf(stderr, ").\n"
- " Mixing devices attached to multiple 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;
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);
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)
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 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;
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);
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;
char *version;
if (data_offset != INVALID_SECTORS) {
- fprintf(stderr, Name ": data-offset not supported by imsm\n");
+ pr_err("data-offset not supported by imsm\n");
return 0;
}
return 0;
}
-
static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
{
struct intel_super *super = st->sb;
dd->next = super->disk_mgmt_list;
super->disk_mgmt_list = dd;
-
return 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;
return 0;
}
-
static int
active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
int dpa, int verbose)
continue;
}
-
dv = xcalloc(1, sizeof(*dv));
dv->devname = xstrdup(buf);
dv->next = devlist;
return count;
}
-
static int
count_volumes(char *hba, int dpa, int verbose)
{
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,
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,
if (i < current_vol)
continue;
sprintf(subarray, "%u", i);
- if (is_subarray_active(subarray, st->devname)) {
+ 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);
char *ep;
int vol;
- if (is_subarray_active(subarray, st->devname)) {
+ if (is_subarray_active(subarray, st->devnm)) {
pr_err("Unable to update name of active subarray\n");
return 2;
}
sb_errors = 1;
}
-
/* count spare devices, not used in maps
*/
for (d = super->disks; d; d = d->next)
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
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);
__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)
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 = xcalloc(1, sizeof(*di));
* disk_ord_tbl for the array
*/
mu = xmalloc(sizeof(*mu));
- mu->buf = xcalloc(num_spares,
+ mu->buf = xcalloc(num_spares,
sizeof(struct imsm_update_activate_spare));
mu->space = NULL;
mu->space_list = NULL;
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)
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;
* 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
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;
break;
}
default:
- fprintf(stderr, "error: unsuported process update type:"
+ pr_err("error: unsuported process update type:"
"(type: %d)\n", type);
}
}
}
}
-
/*******************************************************************************
* 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);
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,
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 > 0 ||
geo->level != UnSet ||
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)
{
return 0;
}
-
/******************************************************************************
* function: imsm_create_metadata_update_for_size_change()
* Creates update for IMSM array for array size change.
/***************************************************************************
* Function: imsm_analyze_change
* Description: Function analyze change for single volume
-* and validate if transition is supported
+* 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
}
if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
pr_err("Error. The last volume in container "
- "can be expanded only (%i/%i).\n",
- super->current_vol, st->devnum);
+ "can be expanded only (%i/%s).\n",
+ super->current_vol, st->devnm);
goto analyse_change_exit;
}
/* check the maximum available size
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;
*/
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) {
- pr_err("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;
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)
.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",