"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "super-intel.c" between
mdadm-4.1.tar.gz and mdadm-4.2.tar.gz

About: mdadm is a tool for creating, managing and monitoring device arrays using the "md" driver in Linux, also known as Software RAID arrays.

super-intel.c  (mdadm-4.1):super-intel.c  (mdadm-4.2)
skipping to change at line 99 skipping to change at line 99
#define MPB_SECTOR_CNT 2210 #define MPB_SECTOR_CNT 2210
#define IMSM_RESERVED_SECTORS 8192 #define IMSM_RESERVED_SECTORS 8192
#define NUM_BLOCKS_DIRTY_STRIPE_REGION 2048 #define NUM_BLOCKS_DIRTY_STRIPE_REGION 2048
#define SECT_PER_MB_SHIFT 11 #define SECT_PER_MB_SHIFT 11
#define MAX_SECTOR_SIZE 4096 #define MAX_SECTOR_SIZE 4096
#define MULTIPLE_PPL_AREA_SIZE_IMSM (1024 * 1024) /* Size of the whole #define MULTIPLE_PPL_AREA_SIZE_IMSM (1024 * 1024) /* Size of the whole
* mutliple PPL area * mutliple PPL area
*/ */
/*
* Internal Write-intent bitmap is stored in the same area where PPL.
* Both features are mutually exclusive, so it is not an issue.
* The first 8KiB of the area are reserved and shall not be used.
*/
#define IMSM_BITMAP_AREA_RESERVED_SIZE 8192
#define IMSM_BITMAP_HEADER_OFFSET (IMSM_BITMAP_AREA_RESERVED_SIZE)
#define IMSM_BITMAP_HEADER_SIZE MAX_SECTOR_SIZE
#define IMSM_BITMAP_START_OFFSET (IMSM_BITMAP_HEADER_OFFSET + IMSM_BITMAP_HEADER
_SIZE)
#define IMSM_BITMAP_AREA_SIZE (MULTIPLE_PPL_AREA_SIZE_IMSM - IMSM_BITMAP_START_O
FFSET)
#define IMSM_BITMAP_AND_HEADER_SIZE (IMSM_BITMAP_AREA_SIZE + IMSM_BITMAP_HEADER_
SIZE)
#define IMSM_DEFAULT_BITMAP_CHUNKSIZE (64 * 1024 * 1024)
#define IMSM_DEFAULT_BITMAP_DAEMON_SLEEP 5
/*
* This macro let's us ensure that no-one accidentally
* changes the size of a struct
*/
#define ASSERT_SIZE(_struct, size) \
static inline void __assert_size_##_struct(void) \
{ \
switch (0) { \
case 0: break; \
case (sizeof(struct _struct) == size): break; \
} \
}
/* Disk configuration info. */ /* Disk configuration info. */
#define IMSM_MAX_DEVICES 255 #define IMSM_MAX_DEVICES 255
struct imsm_disk { struct imsm_disk {
__u8 serial[MAX_RAID_SERIAL_LEN];/* 0xD8 - 0xE7 ascii serial number */ __u8 serial[MAX_RAID_SERIAL_LEN];/* 0xD8 - 0xE7 ascii serial number */
__u32 total_blocks_lo; /* 0xE8 - 0xEB total blocks lo */ __u32 total_blocks_lo; /* 0xE8 - 0xEB total blocks lo */
__u32 scsi_id; /* 0xEC - 0xEF scsi ID */ __u32 scsi_id; /* 0xEC - 0xEF scsi ID */
#define SPARE_DISK __cpu_to_le32(0x01) /* Spare */ #define SPARE_DISK __cpu_to_le32(0x01) /* Spare */
#define CONFIGURED_DISK __cpu_to_le32(0x02) /* Member of some RaidDev */ #define CONFIGURED_DISK __cpu_to_le32(0x02) /* Member of some RaidDev */
#define FAILED_DISK __cpu_to_le32(0x04) /* Permanent failure */ #define FAILED_DISK __cpu_to_le32(0x04) /* Permanent failure */
#define JOURNAL_DISK __cpu_to_le32(0x2000000) /* Device marked as Journaling Drive */ #define JOURNAL_DISK __cpu_to_le32(0x2000000) /* Device marked as Journaling Drive */
__u32 status; /* 0xF0 - 0xF3 */ __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 */ __u32 total_blocks_hi; /* 0xF4 - 0xF5 total blocks hi */
#define IMSM_DISK_FILLERS 3 #define IMSM_DISK_FILLERS 3
__u32 filler[IMSM_DISK_FILLERS]; /* 0xF5 - 0x107 MPB_DISK_FILLERS for fut ure expansion */ __u32 filler[IMSM_DISK_FILLERS]; /* 0xF5 - 0x107 MPB_DISK_FILLERS for fut ure expansion */
}; };
ASSERT_SIZE(imsm_disk, 48)
/* map selector for map managment /* map selector for map managment
*/ */
#define MAP_0 0 #define MAP_0 0
#define MAP_1 1 #define MAP_1 1
#define MAP_X -1 #define MAP_X -1
/* RAID map configuration infos. */ /* RAID map configuration infos. */
struct imsm_map { struct imsm_map {
__u32 pba_of_lba0_lo; /* start address of partition */ __u32 pba_of_lba0_lo; /* start address of partition */
skipping to change at line 149 skipping to change at line 180
__u8 failed_disk_num; /* valid only when state is degraded */ __u8 failed_disk_num; /* valid only when state is degraded */
__u8 ddf; __u8 ddf;
__u32 pba_of_lba0_hi; __u32 pba_of_lba0_hi;
__u32 blocks_per_member_hi; __u32 blocks_per_member_hi;
__u32 num_data_stripes_hi; __u32 num_data_stripes_hi;
__u32 filler[4]; /* expansion area */ __u32 filler[4]; /* expansion area */
#define IMSM_ORD_REBUILD (1 << 24) #define IMSM_ORD_REBUILD (1 << 24)
__u32 disk_ord_tbl[1]; /* disk_ord_tbl[num_members], __u32 disk_ord_tbl[1]; /* disk_ord_tbl[num_members],
* top byte contains some flags * top byte contains some flags
*/ */
} __attribute__ ((packed)); };
ASSERT_SIZE(imsm_map, 52)
struct imsm_vol { struct imsm_vol {
__u32 curr_migr_unit; __u32 curr_migr_unit_lo;
__u32 checkpoint_id; /* id to access curr_migr_unit */ __u32 checkpoint_id; /* id to access curr_migr_unit */
__u8 migr_state; /* Normal or Migrating */ __u8 migr_state; /* Normal or Migrating */
#define MIGR_INIT 0 #define MIGR_INIT 0
#define MIGR_REBUILD 1 #define MIGR_REBUILD 1
#define MIGR_VERIFY 2 /* analagous to echo check > sync_action */ #define MIGR_VERIFY 2 /* analagous to echo check > sync_action */
#define MIGR_GEN_MIGR 3 #define MIGR_GEN_MIGR 3
#define MIGR_STATE_CHANGE 4 #define MIGR_STATE_CHANGE 4
#define MIGR_REPAIR 5 #define MIGR_REPAIR 5
__u8 migr_type; /* Initializing, Rebuilding, ... */ __u8 migr_type; /* Initializing, Rebuilding, ... */
#define RAIDVOL_CLEAN 0 #define RAIDVOL_CLEAN 0
#define RAIDVOL_DIRTY 1 #define RAIDVOL_DIRTY 1
#define RAIDVOL_DSRECORD_VALID 2 #define RAIDVOL_DSRECORD_VALID 2
__u8 dirty; __u8 dirty;
__u8 fs_state; /* fast-sync state for CnG (0xff == disabled) */ __u8 fs_state; /* fast-sync state for CnG (0xff == disabled) */
__u16 verify_errors; /* number of mismatches */ __u16 verify_errors; /* number of mismatches */
__u16 bad_blocks; /* number of bad blocks during verify */ __u16 bad_blocks; /* number of bad blocks during verify */
__u32 filler[4]; __u32 curr_migr_unit_hi;
__u32 filler[3];
struct imsm_map map[1]; struct imsm_map map[1];
/* here comes another one if migr_state */ /* here comes another one if migr_state */
} __attribute__ ((packed)); };
ASSERT_SIZE(imsm_vol, 84)
struct imsm_dev { struct imsm_dev {
__u8 volume[MAX_RAID_SERIAL_LEN]; __u8 volume[MAX_RAID_SERIAL_LEN];
__u32 size_low; __u32 size_low;
__u32 size_high; __u32 size_high;
#define DEV_BOOTABLE __cpu_to_le32(0x01) #define DEV_BOOTABLE __cpu_to_le32(0x01)
#define DEV_BOOT_DEVICE __cpu_to_le32(0x02) #define DEV_BOOT_DEVICE __cpu_to_le32(0x02)
#define DEV_READ_COALESCING __cpu_to_le32(0x04) #define DEV_READ_COALESCING __cpu_to_le32(0x04)
#define DEV_WRITE_COALESCING __cpu_to_le32(0x08) #define DEV_WRITE_COALESCING __cpu_to_le32(0x08)
#define DEV_LAST_SHUTDOWN_DIRTY __cpu_to_le32(0x10) #define DEV_LAST_SHUTDOWN_DIRTY __cpu_to_le32(0x10)
skipping to change at line 216 skipping to change at line 250
/* Unique Volume Id of the NvCache Volume associated with this volume */ /* Unique Volume Id of the NvCache Volume associated with this volume */
__u32 nvc_vol_orig_family_num; __u32 nvc_vol_orig_family_num;
__u16 nvc_vol_raid_dev_num; __u16 nvc_vol_raid_dev_num;
#define RWH_OFF 0 #define RWH_OFF 0
#define RWH_DISTRIBUTED 1 #define RWH_DISTRIBUTED 1
#define RWH_JOURNALING_DRIVE 2 #define RWH_JOURNALING_DRIVE 2
#define RWH_MULTIPLE_DISTRIBUTED 3 #define RWH_MULTIPLE_DISTRIBUTED 3
#define RWH_MULTIPLE_PPLS_JOURNALING_DRIVE 4 #define RWH_MULTIPLE_PPLS_JOURNALING_DRIVE 4
#define RWH_MULTIPLE_OFF 5 #define RWH_MULTIPLE_OFF 5
#define RWH_BITMAP 6
__u8 rwh_policy; /* Raid Write Hole Policy */ __u8 rwh_policy; /* Raid Write Hole Policy */
__u8 jd_serial[MAX_RAID_SERIAL_LEN]; /* Journal Drive serial number */ __u8 jd_serial[MAX_RAID_SERIAL_LEN]; /* Journal Drive serial number */
__u8 filler1; __u8 filler1;
#define IMSM_DEV_FILLERS 3 #define IMSM_DEV_FILLERS 3
__u32 filler[IMSM_DEV_FILLERS]; __u32 filler[IMSM_DEV_FILLERS];
struct imsm_vol vol; struct imsm_vol vol;
} __attribute__ ((packed)); };
ASSERT_SIZE(imsm_dev, 164)
struct imsm_super { struct imsm_super {
__u8 sig[MAX_SIGNATURE_LENGTH]; /* 0x00 - 0x1F */ __u8 sig[MAX_SIGNATURE_LENGTH]; /* 0x00 - 0x1F */
__u32 check_sum; /* 0x20 - 0x23 MPB Checksum */ __u32 check_sum; /* 0x20 - 0x23 MPB Checksum */
__u32 mpb_size; /* 0x24 - 0x27 Size of MPB */ __u32 mpb_size; /* 0x24 - 0x27 Size of MPB */
__u32 family_num; /* 0x28 - 0x2B Checksum from first time t his config was written */ __u32 family_num; /* 0x28 - 0x2B Checksum from first time t his config was written */
__u32 generation_num; /* 0x2C - 0x2F Incremented each time this array's MPB is written */ __u32 generation_num; /* 0x2C - 0x2F Incremented each time this array's MPB is written */
__u32 error_log_size; /* 0x30 - 0x33 in bytes */ __u32 error_log_size; /* 0x30 - 0x33 in bytes */
__u32 attributes; /* 0x34 - 0x37 */ __u32 attributes; /* 0x34 - 0x37 */
__u8 num_disks; /* 0x38 Number of configured disks */ __u8 num_disks; /* 0x38 Number of configured disks */
skipping to change at line 246 skipping to change at line 282
__u8 fill[1]; /* 0x3B */ __u8 fill[1]; /* 0x3B */
__u32 cache_size; /* 0x3c - 0x40 in mb */ __u32 cache_size; /* 0x3c - 0x40 in mb */
__u32 orig_family_num; /* 0x40 - 0x43 original family num */ __u32 orig_family_num; /* 0x40 - 0x43 original family num */
__u32 pwr_cycle_count; /* 0x44 - 0x47 simulated power cycle coun t for array */ __u32 pwr_cycle_count; /* 0x44 - 0x47 simulated power cycle coun t for array */
__u32 bbm_log_size; /* 0x48 - 0x4B - size of bad Block Mgmt L og in bytes */ __u32 bbm_log_size; /* 0x48 - 0x4B - size of bad Block Mgmt L og in bytes */
__u16 num_raid_devs_created; /* 0x4C - 0x4D Used for generating unique __u16 num_raid_devs_created; /* 0x4C - 0x4D Used for generating unique
* volume IDs for raid_dev created in thi s array * volume IDs for raid_dev created in thi s array
* (starts at 1) * (starts at 1)
*/ */
__u16 filler1; /* 0x4E - 0x4F */ __u16 filler1; /* 0x4E - 0x4F */
#define IMSM_FILLERS 34 __u64 creation_time; /* 0x50 - 0x57 Array creation time */
__u32 filler[IMSM_FILLERS]; /* 0x50 - 0xD7 RAID_MPB_FILLERS */ #define IMSM_FILLERS 32
__u32 filler[IMSM_FILLERS]; /* 0x58 - 0xD7 RAID_MPB_FILLERS */
struct imsm_disk disk[1]; /* 0xD8 diskTbl[numDisks] */ struct imsm_disk disk[1]; /* 0xD8 diskTbl[numDisks] */
/* here comes imsm_dev[num_raid_devs] */ /* here comes imsm_dev[num_raid_devs] */
/* here comes BBM logs */ /* here comes BBM logs */
} __attribute__ ((packed)); };
ASSERT_SIZE(imsm_super, 264)
#define BBM_LOG_MAX_ENTRIES 254 #define BBM_LOG_MAX_ENTRIES 254
#define BBM_LOG_MAX_LBA_ENTRY_VAL 256 /* Represents 256 LBAs */ #define BBM_LOG_MAX_LBA_ENTRY_VAL 256 /* Represents 256 LBAs */
#define BBM_LOG_SIGNATURE 0xabadb10c #define BBM_LOG_SIGNATURE 0xabadb10c
struct bbm_log_block_addr { struct bbm_log_block_addr {
__u16 w1; __u16 w1;
__u32 dw1; __u32 dw1;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
struct bbm_log_entry { struct bbm_log_entry {
__u8 marked_count; /* Number of blocks marked - 1 */ __u8 marked_count; /* Number of blocks marked - 1 */
__u8 disk_ordinal; /* Disk entry within the imsm_super */ __u8 disk_ordinal; /* Disk entry within the imsm_super */
struct bbm_log_block_addr defective_block_start; struct bbm_log_block_addr defective_block_start;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
struct bbm_log { struct bbm_log {
__u32 signature; /* 0xABADB10C */ __u32 signature; /* 0xABADB10C */
__u32 entry_count; __u32 entry_count;
struct bbm_log_entry marked_block_entries[BBM_LOG_MAX_ENTRIES]; struct bbm_log_entry marked_block_entries[BBM_LOG_MAX_ENTRIES];
} __attribute__ ((__packed__)); };
ASSERT_SIZE(bbm_log, 2040)
static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" }; static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" };
#define BLOCKS_PER_KB (1024/512) #define BLOCKS_PER_KB (1024/512)
#define RAID_DISK_RESERVED_BLOCKS_IMSM_HI 2209 #define RAID_DISK_RESERVED_BLOCKS_IMSM_HI 2209
#define GEN_MIGR_AREA_SIZE 2048 /* General Migration Copy Area size in blocks */ #define GEN_MIGR_AREA_SIZE 2048 /* General Migration Copy Area size in blocks */
#define MIGR_REC_BUF_SECTORS 1 /* size of migr_record i/o buffer in sectors */ #define MIGR_REC_BUF_SECTORS 1 /* size of migr_record i/o buffer in sectors */
skipping to change at line 299 skipping to change at line 338
#define UNIT_SRC_IN_CP_AREA 1 /* Source data for curr_migr_unit has #define UNIT_SRC_IN_CP_AREA 1 /* Source data for curr_migr_unit has
* already been migrated and must * already been migrated and must
* be recovered from checkpoint area */ * be recovered from checkpoint area */
#define PPL_ENTRY_SPACE (128 * 1024) /* Size of single PPL, without the header * / #define PPL_ENTRY_SPACE (128 * 1024) /* Size of single PPL, without the header * /
struct migr_record { struct migr_record {
__u32 rec_status; /* Status used to determine how to restart __u32 rec_status; /* Status used to determine how to restart
* migration in case it aborts * migration in case it aborts
* in some fashion */ * in some fashion */
__u32 curr_migr_unit; /* 0..numMigrUnits-1 */ __u32 curr_migr_unit_lo; /* 0..numMigrUnits-1 */
__u32 family_num; /* Family number of MPB __u32 family_num; /* Family number of MPB
* containing the RaidDev * containing the RaidDev
* that is migrating */ * that is migrating */
__u32 ascending_migr; /* True if migrating in increasing __u32 ascending_migr; /* True if migrating in increasing
* order of lbas */ * order of lbas */
__u32 blocks_per_unit; /* Num disk blocks per unit of operation */ __u32 blocks_per_unit; /* Num disk blocks per unit of operation */
__u32 dest_depth_per_unit; /* Num member blocks each destMap __u32 dest_depth_per_unit; /* Num member blocks each destMap
* member disk * member disk
* advances per unit-of-operation */ * advances per unit-of-operation */
__u32 ckpt_area_pba; /* Pba of first block of ckpt copy area */ __u32 ckpt_area_pba_lo; /* Pba of first block of ckpt copy area */
__u32 dest_1st_member_lba; /* First member lba on first __u32 dest_1st_member_lba_lo; /* First member lba on first
* stripe of destination */ * stripe of destination */
__u32 num_migr_units; /* Total num migration units-of-op */ __u32 num_migr_units_lo; /* Total num migration units-of-op */
__u32 post_migr_vol_cap; /* Size of volume after __u32 post_migr_vol_cap; /* Size of volume after
* migration completes */ * migration completes */
__u32 post_migr_vol_cap_hi; /* Expansion space for LBA64 */ __u32 post_migr_vol_cap_hi; /* Expansion space for LBA64 */
__u32 ckpt_read_disk_num; /* Which member disk in destSubMap[0] the __u32 ckpt_read_disk_num; /* Which member disk in destSubMap[0] the
* migration ckpt record was read from * migration ckpt record was read from
* (for recovered migrations) */ * (for recovered migrations) */
} __attribute__ ((__packed__)); __u32 curr_migr_unit_hi; /* 0..numMigrUnits-1 high order 32 bits */
__u32 ckpt_area_pba_hi; /* Pba of first block of ckpt copy area
* high order 32 bits */
__u32 dest_1st_member_lba_hi; /* First member lba on first stripe of
* destination - high order 32 bits */
__u32 num_migr_units_hi; /* Total num migration units-of-op
* high order 32 bits */
__u32 filler[16];
};
ASSERT_SIZE(migr_record, 128)
struct md_list { struct md_list {
/* usage marker: /* usage marker:
* 1: load metadata * 1: load metadata
* 2: metadata does not match * 2: metadata does not match
* 4: already checked * 4: already checked
*/ */
int used; int used;
char *devname; char *devname;
int found; int found;
skipping to change at line 526 skipping to change at line 574
}; };
struct imsm_update_size_change { struct imsm_update_size_change {
enum imsm_update_type type; enum imsm_update_type type;
int subdev; int subdev;
long long new_size; long long new_size;
}; };
struct imsm_update_general_migration_checkpoint { struct imsm_update_general_migration_checkpoint {
enum imsm_update_type type; enum imsm_update_type type;
__u32 curr_migr_unit; __u64 curr_migr_unit;
}; };
struct disk_info { struct disk_info {
__u8 serial[MAX_RAID_SERIAL_LEN]; __u8 serial[MAX_RAID_SERIAL_LEN];
}; };
struct imsm_update_create_array { struct imsm_update_create_array {
enum imsm_update_type type; enum imsm_update_type type;
int dev_idx; int dev_idx;
struct imsm_dev dev; struct imsm_dev dev;
skipping to change at line 646 skipping to change at line 694
} }
static struct sys_dev* find_disk_attached_hba(int fd, const char *devname) static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
{ {
struct sys_dev *list, *elem; struct sys_dev *list, *elem;
char *disk_path; char *disk_path;
if ((list = find_intel_devices()) == NULL) if ((list = find_intel_devices()) == NULL)
return 0; return 0;
if (fd < 0) if (!is_fd_valid(fd))
disk_path = (char *) devname; disk_path = (char *) devname;
else else
disk_path = diskfd_to_devpath(fd); disk_path = diskfd_to_devpath(fd, 1, NULL);
if (!disk_path) if (!disk_path)
return 0; return 0;
for (elem = list; elem; elem = elem->next) for (elem = list; elem; elem = elem->next)
if (path_attached_to_hba(disk_path, elem->path)) if (path_attached_to_hba(disk_path, elem->path))
return elem; return elem;
if (disk_path != devname) if (disk_path != devname)
free(disk_path); free(disk_path);
skipping to change at line 1161 skipping to change at line 1209
if (get_imsm_disk_slot(map, dl->index) >= 0) if (get_imsm_disk_slot(map, dl->index) >= 0)
memberships++; memberships++;
} }
return memberships; return memberships;
} }
static __u32 imsm_min_reserved_sectors(struct intel_super *super); static __u32 imsm_min_reserved_sectors(struct intel_super *super);
static int split_ull(unsigned long long n, __u32 *lo, __u32 *hi) static int split_ull(unsigned long long n, void *lo, void *hi)
{ {
if (lo == 0 || hi == 0) if (lo == 0 || hi == 0)
return 1; return 1;
*lo = __le32_to_cpu((unsigned)n); __put_unaligned32(__cpu_to_le32((__u32)n), lo);
*hi = __le32_to_cpu((unsigned)(n >> 32)); __put_unaligned32(__cpu_to_le32((n >> 32)), hi);
return 0; return 0;
} }
static unsigned long long join_u32(__u32 lo, __u32 hi) static unsigned long long join_u32(__u32 lo, __u32 hi)
{ {
return (unsigned long long)__le32_to_cpu(lo) | return (unsigned long long)__le32_to_cpu(lo) |
(((unsigned long long)__le32_to_cpu(hi)) << 32); (((unsigned long long)__le32_to_cpu(hi)) << 32);
} }
static unsigned long long total_blocks(struct imsm_disk *disk) static unsigned long long total_blocks(struct imsm_disk *disk)
{ {
if (disk == NULL) if (disk == NULL)
return 0; return 0;
return join_u32(disk->total_blocks_lo, disk->total_blocks_hi); return join_u32(disk->total_blocks_lo, disk->total_blocks_hi);
} }
/**
* imsm_num_data_members() - get data drives count for an array.
* @map: Map to analyze.
*
* num_data_members value represents minimal count of drives for level.
* The name of the property could be misleading for RAID5 with asymmetric layout
* because some data required to be calculated from parity.
* The property is extracted from level and num_members value.
*
* Return: num_data_members value on success, zero otherwise.
*/
static __u8 imsm_num_data_members(struct imsm_map *map)
{
switch (get_imsm_raid_level(map)) {
case 0:
return map->num_members;
case 1:
case 10:
return map->num_members / 2;
case 5:
return map->num_members - 1;
default:
dprintf("unsupported raid level\n");
return 0;
}
}
static unsigned long long pba_of_lba0(struct imsm_map *map) static unsigned long long pba_of_lba0(struct imsm_map *map)
{ {
if (map == NULL) if (map == NULL)
return 0; return 0;
return join_u32(map->pba_of_lba0_lo, map->pba_of_lba0_hi); return join_u32(map->pba_of_lba0_lo, map->pba_of_lba0_hi);
} }
static unsigned long long blocks_per_member(struct imsm_map *map) static unsigned long long blocks_per_member(struct imsm_map *map)
{ {
if (map == NULL) if (map == NULL)
skipping to change at line 1204 skipping to change at line 1279
return join_u32(map->blocks_per_member_lo, map->blocks_per_member_hi); return join_u32(map->blocks_per_member_lo, map->blocks_per_member_hi);
} }
static unsigned long long num_data_stripes(struct imsm_map *map) static unsigned long long num_data_stripes(struct imsm_map *map)
{ {
if (map == NULL) if (map == NULL)
return 0; return 0;
return join_u32(map->num_data_stripes_lo, map->num_data_stripes_hi); return join_u32(map->num_data_stripes_lo, map->num_data_stripes_hi);
} }
static unsigned long long vol_curr_migr_unit(struct imsm_dev *dev)
{
if (dev == NULL)
return 0;
return join_u32(dev->vol.curr_migr_unit_lo, dev->vol.curr_migr_unit_hi);
}
static unsigned long long imsm_dev_size(struct imsm_dev *dev) static unsigned long long imsm_dev_size(struct imsm_dev *dev)
{ {
if (dev == NULL) if (dev == NULL)
return 0; return 0;
return join_u32(dev->size_low, dev->size_high); return join_u32(dev->size_low, dev->size_high);
} }
static unsigned long long migr_chkp_area_pba(struct migr_record *migr_rec)
{
if (migr_rec == NULL)
return 0;
return join_u32(migr_rec->ckpt_area_pba_lo,
migr_rec->ckpt_area_pba_hi);
}
static unsigned long long current_migr_unit(struct migr_record *migr_rec)
{
if (migr_rec == NULL)
return 0;
return join_u32(migr_rec->curr_migr_unit_lo,
migr_rec->curr_migr_unit_hi);
}
static unsigned long long migr_dest_1st_member_lba(struct migr_record *migr_rec)
{
if (migr_rec == NULL)
return 0;
return join_u32(migr_rec->dest_1st_member_lba_lo,
migr_rec->dest_1st_member_lba_hi);
}
static unsigned long long get_num_migr_units(struct migr_record *migr_rec)
{
if (migr_rec == NULL)
return 0;
return join_u32(migr_rec->num_migr_units_lo,
migr_rec->num_migr_units_hi);
}
static void set_total_blocks(struct imsm_disk *disk, unsigned long long n) static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
{ {
split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi); split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
} }
/**
* set_num_domains() - Set number of domains for an array.
* @map: Map to be updated.
*
* num_domains property represents copies count of each data drive, thus make
* it meaningful only for RAID1 and RAID10. IMSM supports two domains for
* raid1 and raid10.
*/
static void set_num_domains(struct imsm_map *map)
{
int level = get_imsm_raid_level(map);
if (level == 1 || level == 10)
map->num_domains = 2;
else
map->num_domains = 1;
}
static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n) static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n)
{ {
split_ull(n, &map->pba_of_lba0_lo, &map->pba_of_lba0_hi); split_ull(n, &map->pba_of_lba0_lo, &map->pba_of_lba0_hi);
} }
static void set_blocks_per_member(struct imsm_map *map, unsigned long long n) 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); 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) 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); split_ull(n, &map->num_data_stripes_lo, &map->num_data_stripes_hi);
} }
/**
* update_num_data_stripes() - Calculate and update num_data_stripes value.
* @map: map to be updated.
* @dev_size: size of volume.
*
* num_data_stripes value is addictionally divided by num_domains, therefore for
* levels where num_domains is not 1, nds is a part of real value.
*/
static void update_num_data_stripes(struct imsm_map *map,
unsigned long long dev_size)
{
unsigned long long nds = dev_size / imsm_num_data_members(map);
nds /= map->num_domains;
nds /= map->blocks_per_strip;
set_num_data_stripes(map, nds);
}
static void set_vol_curr_migr_unit(struct imsm_dev *dev, unsigned long long n)
{
if (dev == NULL)
return;
split_ull(n, &dev->vol.curr_migr_unit_lo, &dev->vol.curr_migr_unit_hi);
}
static void set_imsm_dev_size(struct imsm_dev *dev, unsigned long long n) static void set_imsm_dev_size(struct imsm_dev *dev, unsigned long long n)
{ {
split_ull(n, &dev->size_low, &dev->size_high); split_ull(n, &dev->size_low, &dev->size_high);
} }
static void set_migr_chkp_area_pba(struct migr_record *migr_rec,
unsigned long long n)
{
split_ull(n, &migr_rec->ckpt_area_pba_lo, &migr_rec->ckpt_area_pba_hi);
}
static void set_current_migr_unit(struct migr_record *migr_rec,
unsigned long long n)
{
split_ull(n, &migr_rec->curr_migr_unit_lo,
&migr_rec->curr_migr_unit_hi);
}
static void set_migr_dest_1st_member_lba(struct migr_record *migr_rec,
unsigned long long n)
{
split_ull(n, &migr_rec->dest_1st_member_lba_lo,
&migr_rec->dest_1st_member_lba_hi);
}
static void set_num_migr_units(struct migr_record *migr_rec,
unsigned long long n)
{
split_ull(n, &migr_rec->num_migr_units_lo,
&migr_rec->num_migr_units_hi);
}
static unsigned long long per_dev_array_size(struct imsm_map *map) static unsigned long long per_dev_array_size(struct imsm_map *map)
{ {
unsigned long long array_size = 0; unsigned long long array_size = 0;
if (map == NULL) if (map == NULL)
return array_size; return array_size;
array_size = num_data_stripes(map) * map->blocks_per_strip; array_size = num_data_stripes(map) * map->blocks_per_strip;
if (get_imsm_raid_level(map) == 1 || get_imsm_raid_level(map) == 10) if (get_imsm_raid_level(map) == 1 || get_imsm_raid_level(map) == 10)
array_size *= 2; array_size *= 2;
return array_size; return array_size;
} }
static struct extent *get_extents(struct intel_super *super, struct dl *dl) static struct extent *get_extents(struct intel_super *super, struct dl *dl,
int get_minimal_reservation)
{ {
/* find a list of used extents on the given physical device */ /* find a list of used extents on the given physical device */
struct extent *rv, *e; struct extent *rv, *e;
int i; int i;
int memberships = count_memberships(dl, super); int memberships = count_memberships(dl, super);
__u32 reservation; __u32 reservation;
/* trim the reserved area for spares, so they can join any array /* trim the reserved area for spares, so they can join any array
* regardless of whether the OROM has assigned sectors from the * regardless of whether the OROM has assigned sectors from the
* IMSM_RESERVED_SECTORS region * IMSM_RESERVED_SECTORS region
*/ */
if (dl->index == -1) if (dl->index == -1 || get_minimal_reservation)
reservation = imsm_min_reserved_sectors(super); reservation = imsm_min_reserved_sectors(super);
else else
reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS; reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
rv = xcalloc(sizeof(struct extent), (memberships + 1)); rv = xcalloc(sizeof(struct extent), (memberships + 1));
e = rv; e = rv;
for (i = 0; i < super->anchor->num_raid_devs; i++) { for (i = 0; i < super->anchor->num_raid_devs; i++) {
struct imsm_dev *dev = get_imsm_dev(super, i); struct imsm_dev *dev = get_imsm_dev(super, i);
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
skipping to change at line 1323 skipping to change at line 1510
struct extent *e; struct extent *e;
int i; int i;
__u32 rv; __u32 rv;
/* for spares just return a minimal reservation which will grow /* for spares just return a minimal reservation which will grow
* once the spare is picked up by an array * once the spare is picked up by an array
*/ */
if (dl->index == -1) if (dl->index == -1)
return MPB_SECTOR_CNT; return MPB_SECTOR_CNT;
e = get_extents(super, dl); e = get_extents(super, dl, 0);
if (!e) if (!e)
return MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS; return MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
/* scroll to last entry */ /* scroll to last entry */
for (i = 0; e[i].size; i++) for (i = 0; e[i].size; i++)
continue; continue;
rv = total_blocks(&dl->disk) - e[i].start; rv = total_blocks(&dl->disk) - e[i].start;
free(e); free(e);
skipping to change at line 1415 skipping to change at line 1602
unsigned long long blocks = total_blocks(&dl->disk); unsigned long long blocks = total_blocks(&dl->disk);
if (blocks < min_active || min_active == 0) { if (blocks < min_active || min_active == 0) {
dl_min = dl; dl_min = dl;
min_active = blocks; min_active = blocks;
} }
} }
if (!dl_min) if (!dl_min)
return rv; return rv;
/* find last lba used by subarrays on the smallest active disk */ /* find last lba used by subarrays on the smallest active disk */
e = get_extents(super, dl_min); e = get_extents(super, dl_min, 0);
if (!e) if (!e)
return rv; return rv;
for (i = 0; e[i].size; i++) for (i = 0; e[i].size; i++)
continue; continue;
remainder = min_active - e[i].start; remainder = min_active - e[i].start;
free(e); free(e);
/* to give priority to recovery we should not require full /* to give priority to recovery we should not require full
IMSM_RESERVED_SECTORS from the spare */ IMSM_RESERVED_SECTORS from the spare */
skipping to change at line 1456 skipping to change at line 1643
if (!super) if (!super)
return -EINVAL; return -EINVAL;
/* find first active disk in array */ /* find first active disk in array */
dl = super->disks; dl = super->disks;
while (dl && (is_failed(&dl->disk) || dl->index == -1)) while (dl && (is_failed(&dl->disk) || dl->index == -1))
dl = dl->next; dl = dl->next;
if (!dl) if (!dl)
return -EINVAL; return -EINVAL;
/* find last lba used by subarrays */ /* find last lba used by subarrays */
e = get_extents(super, dl); e = get_extents(super, dl, 0);
if (!e) if (!e)
return -EINVAL; return -EINVAL;
for (i = 0; e[i].size; i++) for (i = 0; e[i].size; i++)
continue; continue;
if (i > 0) if (i > 0)
size = e[i-1].start + e[i-1].size; size = e[i-1].start + e[i-1].size;
free(e); free(e);
/* add the amount of space needed for metadata */ /* add the amount of space needed for metadata */
size += imsm_min_reserved_sectors(super); size += imsm_min_reserved_sectors(super);
c->min_size = size * 512; c->min_size = size * 512;
c->sector_size = super->sector_size; c->sector_size = super->sector_size;
return 0; return 0;
} }
static int is_gen_migration(struct imsm_dev *dev); static bool is_gen_migration(struct imsm_dev *dev);
#define IMSM_4K_DIV 8 #define IMSM_4K_DIV 8
static __u64 blocks_per_migr_unit(struct intel_super *super, static __u64 blocks_per_migr_unit(struct intel_super *super,
struct imsm_dev *dev); struct imsm_dev *dev);
static void print_imsm_dev(struct intel_super *super, static void print_imsm_dev(struct intel_super *super,
struct imsm_dev *dev, struct imsm_dev *dev,
char *uuid, char *uuid,
int disk_idx) int disk_idx)
{ {
__u64 sz; __u64 sz;
int slot, i; int slot, i;
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
struct imsm_map *map2 = get_imsm_map(dev, MAP_1); struct imsm_map *map2 = get_imsm_map(dev, MAP_1);
__u32 ord; __u32 ord;
printf("\n"); printf("\n");
printf("[%.16s]:\n", dev->volume); printf("[%.16s]:\n", dev->volume);
printf(" Subarray : %d\n", super->current_vol);
printf(" UUID : %s\n", uuid); printf(" UUID : %s\n", uuid);
printf(" RAID Level : %d", get_imsm_raid_level(map)); printf(" RAID Level : %d", get_imsm_raid_level(map));
if (map2) if (map2)
printf(" <-- %d", get_imsm_raid_level(map2)); printf(" <-- %d", get_imsm_raid_level(map2));
printf("\n"); printf("\n");
printf(" Members : %d", map->num_members); printf(" Members : %d", map->num_members);
if (map2) if (map2)
printf(" <-- %d", map2->num_members); printf(" <-- %d", map2->num_members);
printf("\n"); printf("\n");
printf(" Slots : ["); printf(" Slots : [");
skipping to change at line 1541 skipping to change at line 1729
printf(" Sector Size : %u\n", super->sector_size); printf(" Sector Size : %u\n", super->sector_size);
sz = imsm_dev_size(dev); sz = imsm_dev_size(dev);
printf(" Array Size : %llu%s\n", printf(" Array Size : %llu%s\n",
(unsigned long long)sz * 512 / super->sector_size, (unsigned long long)sz * 512 / super->sector_size,
human_size(sz * 512)); human_size(sz * 512));
sz = blocks_per_member(map); sz = blocks_per_member(map);
printf(" Per Dev Size : %llu%s\n", printf(" Per Dev Size : %llu%s\n",
(unsigned long long)sz * 512 / super->sector_size, (unsigned long long)sz * 512 / super->sector_size,
human_size(sz * 512)); human_size(sz * 512));
printf(" Sector Offset : %llu\n", printf(" Sector Offset : %llu\n",
pba_of_lba0(map)); pba_of_lba0(map) * 512 / super->sector_size);
printf(" Num Stripes : %llu\n", printf(" Num Stripes : %llu\n",
num_data_stripes(map)); num_data_stripes(map));
printf(" Chunk Size : %u KiB", printf(" Chunk Size : %u KiB",
__le16_to_cpu(map->blocks_per_strip) / 2); __le16_to_cpu(map->blocks_per_strip) / 2);
if (map2) if (map2)
printf(" <-- %u KiB", printf(" <-- %u KiB",
__le16_to_cpu(map2->blocks_per_strip) / 2); __le16_to_cpu(map2->blocks_per_strip) / 2);
printf("\n"); printf("\n");
printf(" Reserved : %d\n", __le32_to_cpu(dev->reserved_blocks)); printf(" Reserved : %d\n", __le32_to_cpu(dev->reserved_blocks));
printf(" Migrate State : "); printf(" Migrate State : ");
skipping to change at line 1574 skipping to change at line 1762
printf("repair\n"); printf("repair\n");
else else
printf("<unknown:%d>\n", migr_type(dev)); printf("<unknown:%d>\n", migr_type(dev));
} else } else
printf("idle\n"); printf("idle\n");
printf(" Map State : %s", map_state_str[map->map_state]); printf(" Map State : %s", map_state_str[map->map_state]);
if (dev->vol.migr_state) { if (dev->vol.migr_state) {
struct imsm_map *map = get_imsm_map(dev, MAP_1); struct imsm_map *map = get_imsm_map(dev, MAP_1);
printf(" <-- %s", map_state_str[map->map_state]); printf(" <-- %s", map_state_str[map->map_state]);
printf("\n Checkpoint : %u ", printf("\n Checkpoint : %llu ", vol_curr_migr_unit(dev));
__le32_to_cpu(dev->vol.curr_migr_unit));
if (is_gen_migration(dev) && (slot > 1 || slot < 0)) if (is_gen_migration(dev) && (slot > 1 || slot < 0))
printf("(N/A)"); printf("(N/A)");
else else
printf("(%llu)", (unsigned long long) printf("(%llu)", (unsigned long long)
blocks_per_migr_unit(super, dev)); blocks_per_migr_unit(super, dev));
} }
printf("\n"); printf("\n");
printf(" Dirty State : %s\n", (dev->vol.dirty & RAIDVOL_DIRTY) ? printf(" Dirty State : %s\n", (dev->vol.dirty & RAIDVOL_DIRTY) ?
"dirty" : "clean"); "dirty" : "clean");
printf(" RWH Policy : "); printf(" RWH Policy : ");
if (dev->rwh_policy == RWH_OFF || dev->rwh_policy == RWH_MULTIPLE_OFF) if (dev->rwh_policy == RWH_OFF || dev->rwh_policy == RWH_MULTIPLE_OFF)
printf("off\n"); printf("off\n");
else if (dev->rwh_policy == RWH_DISTRIBUTED) else if (dev->rwh_policy == RWH_DISTRIBUTED)
printf("PPL distributed\n"); printf("PPL distributed\n");
else if (dev->rwh_policy == RWH_JOURNALING_DRIVE) else if (dev->rwh_policy == RWH_JOURNALING_DRIVE)
printf("PPL journaling drive\n"); printf("PPL journaling drive\n");
else if (dev->rwh_policy == RWH_MULTIPLE_DISTRIBUTED) else if (dev->rwh_policy == RWH_MULTIPLE_DISTRIBUTED)
printf("Multiple distributed PPLs\n"); printf("Multiple distributed PPLs\n");
else if (dev->rwh_policy == RWH_MULTIPLE_PPLS_JOURNALING_DRIVE) else if (dev->rwh_policy == RWH_MULTIPLE_PPLS_JOURNALING_DRIVE)
printf("Multiple PPLs on journaling drive\n"); printf("Multiple PPLs on journaling drive\n");
else if (dev->rwh_policy == RWH_BITMAP)
printf("Write-intent bitmap\n");
else else
printf("<unknown:%d>\n", dev->rwh_policy); printf("<unknown:%d>\n", dev->rwh_policy);
printf(" Volume ID : %u\n", dev->my_vol_raid_dev_num);
} }
static void print_imsm_disk(struct imsm_disk *disk, static void print_imsm_disk(struct imsm_disk *disk,
int index, int index,
__u32 reserved, __u32 reserved,
unsigned int sector_size) { unsigned int sector_size) {
char str[MAX_RAID_SERIAL_LEN + 1]; char str[MAX_RAID_SERIAL_LEN + 1];
__u64 sz; __u64 sz;
if (index < -1 || !disk) if (index < -1 || !disk)
skipping to change at line 1632 skipping to change at line 1823
printf(" Usable Size : %llu%s\n", printf(" Usable Size : %llu%s\n",
(unsigned long long)sz * 512 / sector_size, (unsigned long long)sz * 512 / sector_size,
human_size(sz * 512)); human_size(sz * 512));
} }
void convert_to_4k_imsm_migr_rec(struct intel_super *super) void convert_to_4k_imsm_migr_rec(struct intel_super *super)
{ {
struct migr_record *migr_rec = super->migr_rec; struct migr_record *migr_rec = super->migr_rec;
migr_rec->blocks_per_unit /= IMSM_4K_DIV; migr_rec->blocks_per_unit /= IMSM_4K_DIV;
migr_rec->ckpt_area_pba /= IMSM_4K_DIV;
migr_rec->dest_1st_member_lba /= IMSM_4K_DIV;
migr_rec->dest_depth_per_unit /= IMSM_4K_DIV; migr_rec->dest_depth_per_unit /= IMSM_4K_DIV;
split_ull((join_u32(migr_rec->post_migr_vol_cap, split_ull((join_u32(migr_rec->post_migr_vol_cap,
migr_rec->post_migr_vol_cap_hi) / IMSM_4K_DIV), migr_rec->post_migr_vol_cap_hi) / IMSM_4K_DIV),
&migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap_hi); &migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap_hi);
set_migr_chkp_area_pba(migr_rec,
migr_chkp_area_pba(migr_rec) / IMSM_4K_DIV);
set_migr_dest_1st_member_lba(migr_rec,
migr_dest_1st_member_lba(migr_rec) / IMSM_4K_DIV);
} }
void convert_to_4k_imsm_disk(struct imsm_disk *disk) void convert_to_4k_imsm_disk(struct imsm_disk *disk)
{ {
set_total_blocks(disk, (total_blocks(disk)/IMSM_4K_DIV)); set_total_blocks(disk, (total_blocks(disk)/IMSM_4K_DIV));
} }
void convert_to_4k(struct intel_super *super) void convert_to_4k(struct intel_super *super)
{ {
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
skipping to change at line 1662 skipping to change at line 1855
for (i = 0; i < mpb->num_disks ; i++) { for (i = 0; i < mpb->num_disks ; i++) {
disk = __get_imsm_disk(mpb, i); disk = __get_imsm_disk(mpb, i);
/* disk */ /* disk */
convert_to_4k_imsm_disk(disk); convert_to_4k_imsm_disk(disk);
} }
for (i = 0; i < mpb->num_raid_devs; i++) { for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = __get_imsm_dev(mpb, i); struct imsm_dev *dev = __get_imsm_dev(mpb, i);
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
/* dev */ /* dev */
set_imsm_dev_size(dev, imsm_dev_size(dev)/IMSM_4K_DIV); set_imsm_dev_size(dev, imsm_dev_size(dev)/IMSM_4K_DIV);
dev->vol.curr_migr_unit /= IMSM_4K_DIV; set_vol_curr_migr_unit(dev,
vol_curr_migr_unit(dev) / IMSM_4K_DIV);
/* map0 */ /* map0 */
set_blocks_per_member(map, blocks_per_member(map)/IMSM_4K_DIV); set_blocks_per_member(map, blocks_per_member(map)/IMSM_4K_DIV);
map->blocks_per_strip /= IMSM_4K_DIV; map->blocks_per_strip /= IMSM_4K_DIV;
set_pba_of_lba0(map, pba_of_lba0(map)/IMSM_4K_DIV); set_pba_of_lba0(map, pba_of_lba0(map)/IMSM_4K_DIV);
if (dev->vol.migr_state) { if (dev->vol.migr_state) {
/* map1 */ /* map1 */
map = get_imsm_map(dev, MAP_1); map = get_imsm_map(dev, MAP_1);
set_blocks_per_member(map, set_blocks_per_member(map,
skipping to change at line 1711 skipping to change at line 1905
{ {
struct migr_record *migr_rec = super->migr_rec; struct migr_record *migr_rec = super->migr_rec;
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
int i; int i;
for (i = 0; i < mpb->num_raid_devs; i++) { for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = __get_imsm_dev(mpb, i); struct imsm_dev *dev = __get_imsm_dev(mpb, i);
struct imsm_map *map; struct imsm_map *map;
int slot = -1; int slot = -1;
if (is_gen_migration(dev) == 0) if (is_gen_migration(dev) == false)
continue; continue;
printf("\nMigration Record Information:"); printf("\nMigration Record Information:");
/* first map under migration */ /* first map under migration */
map = get_imsm_map(dev, MAP_0); map = get_imsm_map(dev, MAP_0);
if (map) if (map)
slot = get_imsm_disk_slot(map, super->disks->index); slot = get_imsm_disk_slot(map, super->disks->index);
if (map == NULL || slot > 1 || slot < 0) { if (map == NULL || slot > 1 || slot < 0) {
printf(" Empty\n "); printf(" Empty\n ");
printf("Examine one of first two disks in array\n"); printf("Examine one of first two disks in array\n");
break; break;
} }
printf("\n Status : "); printf("\n Status : ");
if (__le32_to_cpu(migr_rec->rec_status) == UNIT_SRC_NORMAL) if (__le32_to_cpu(migr_rec->rec_status) == UNIT_SRC_NORMAL)
printf("Normal\n"); printf("Normal\n");
else else
printf("Contains Data\n"); printf("Contains Data\n");
printf(" Current Unit : %u\n", printf(" Current Unit : %llu\n",
__le32_to_cpu(migr_rec->curr_migr_unit)); current_migr_unit(migr_rec));
printf(" Family : %u\n", printf(" Family : %u\n",
__le32_to_cpu(migr_rec->family_num)); __le32_to_cpu(migr_rec->family_num));
printf(" Ascending : %u\n", printf(" Ascending : %u\n",
__le32_to_cpu(migr_rec->ascending_migr)); __le32_to_cpu(migr_rec->ascending_migr));
printf(" Blocks Per Unit : %u\n", printf(" Blocks Per Unit : %u\n",
__le32_to_cpu(migr_rec->blocks_per_unit)); __le32_to_cpu(migr_rec->blocks_per_unit));
printf(" Dest. Depth Per Unit : %u\n", printf(" Dest. Depth Per Unit : %u\n",
__le32_to_cpu(migr_rec->dest_depth_per_unit)); __le32_to_cpu(migr_rec->dest_depth_per_unit));
printf(" Checkpoint Area pba : %u\n", printf(" Checkpoint Area pba : %llu\n",
__le32_to_cpu(migr_rec->ckpt_area_pba)); migr_chkp_area_pba(migr_rec));
printf(" First member lba : %u\n", printf(" First member lba : %llu\n",
__le32_to_cpu(migr_rec->dest_1st_member_lba)); migr_dest_1st_member_lba(migr_rec));
printf(" Total Number of Units : %u\n", printf(" Total Number of Units : %llu\n",
__le32_to_cpu(migr_rec->num_migr_units)); get_num_migr_units(migr_rec));
printf(" Size of volume : %u\n", printf(" Size of volume : %llu\n",
__le32_to_cpu(migr_rec->post_migr_vol_cap)); join_u32(migr_rec->post_migr_vol_cap,
printf(" Expansion space for LBA64 : %u\n", migr_rec->post_migr_vol_cap_hi));
__le32_to_cpu(migr_rec->post_migr_vol_cap_hi));
printf(" Record was read from : %u\n", printf(" Record was read from : %u\n",
__le32_to_cpu(migr_rec->ckpt_read_disk_num)); __le32_to_cpu(migr_rec->ckpt_read_disk_num));
break; break;
} }
} }
void convert_from_4k_imsm_migr_rec(struct intel_super *super) void convert_from_4k_imsm_migr_rec(struct intel_super *super)
{ {
struct migr_record *migr_rec = super->migr_rec; struct migr_record *migr_rec = super->migr_rec;
migr_rec->blocks_per_unit *= IMSM_4K_DIV; migr_rec->blocks_per_unit *= IMSM_4K_DIV;
migr_rec->ckpt_area_pba *= IMSM_4K_DIV;
migr_rec->dest_1st_member_lba *= IMSM_4K_DIV;
migr_rec->dest_depth_per_unit *= IMSM_4K_DIV; migr_rec->dest_depth_per_unit *= IMSM_4K_DIV;
split_ull((join_u32(migr_rec->post_migr_vol_cap, split_ull((join_u32(migr_rec->post_migr_vol_cap,
migr_rec->post_migr_vol_cap_hi) * IMSM_4K_DIV), migr_rec->post_migr_vol_cap_hi) * IMSM_4K_DIV),
&migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap,
&migr_rec->post_migr_vol_cap_hi); &migr_rec->post_migr_vol_cap_hi);
set_migr_chkp_area_pba(migr_rec,
migr_chkp_area_pba(migr_rec) * IMSM_4K_DIV);
set_migr_dest_1st_member_lba(migr_rec,
migr_dest_1st_member_lba(migr_rec) * IMSM_4K_DIV);
} }
void convert_from_4k(struct intel_super *super) void convert_from_4k(struct intel_super *super)
{ {
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
struct imsm_disk *disk; struct imsm_disk *disk;
int i; int i;
__u32 bbm_log_size = __le32_to_cpu(mpb->bbm_log_size); __u32 bbm_log_size = __le32_to_cpu(mpb->bbm_log_size);
for (i = 0; i < mpb->num_disks ; i++) { for (i = 0; i < mpb->num_disks ; i++) {
disk = __get_imsm_disk(mpb, i); disk = __get_imsm_disk(mpb, i);
/* disk */ /* disk */
set_total_blocks(disk, (total_blocks(disk)*IMSM_4K_DIV)); set_total_blocks(disk, (total_blocks(disk)*IMSM_4K_DIV));
} }
for (i = 0; i < mpb->num_raid_devs; i++) { for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = __get_imsm_dev(mpb, i); struct imsm_dev *dev = __get_imsm_dev(mpb, i);
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
/* dev */ /* dev */
set_imsm_dev_size(dev, imsm_dev_size(dev)*IMSM_4K_DIV); set_imsm_dev_size(dev, imsm_dev_size(dev)*IMSM_4K_DIV);
dev->vol.curr_migr_unit *= IMSM_4K_DIV; set_vol_curr_migr_unit(dev,
vol_curr_migr_unit(dev) * IMSM_4K_DIV);
/* map0 */ /* map0 */
set_blocks_per_member(map, blocks_per_member(map)*IMSM_4K_DIV); set_blocks_per_member(map, blocks_per_member(map)*IMSM_4K_DIV);
map->blocks_per_strip *= IMSM_4K_DIV; map->blocks_per_strip *= IMSM_4K_DIV;
set_pba_of_lba0(map, pba_of_lba0(map)*IMSM_4K_DIV); set_pba_of_lba0(map, pba_of_lba0(map)*IMSM_4K_DIV);
if (dev->vol.migr_state) { if (dev->vol.migr_state) {
/* map1 */ /* map1 */
map = get_imsm_map(dev, MAP_1); map = get_imsm_map(dev, MAP_1);
set_blocks_per_member(map, set_blocks_per_member(map,
skipping to change at line 1927 skipping to change at line 2123
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
char str[MAX_SIGNATURE_LENGTH]; char str[MAX_SIGNATURE_LENGTH];
int i; int i;
struct mdinfo info; struct mdinfo info;
char nbuf[64]; char nbuf[64];
__u32 sum; __u32 sum;
__u32 reserved = imsm_reserved_sectors(super, super->disks); __u32 reserved = imsm_reserved_sectors(super, super->disks);
struct dl *dl; struct dl *dl;
time_t creation_time;
strncpy(str, (char *)mpb->sig, MPB_SIG_LEN); strncpy(str, (char *)mpb->sig, MPB_SIG_LEN);
str[MPB_SIG_LEN-1] = '\0'; str[MPB_SIG_LEN-1] = '\0';
printf(" Magic : %s\n", str); printf(" Magic : %s\n", str);
printf(" Version : %s\n", get_imsm_version(mpb)); printf(" Version : %s\n", get_imsm_version(mpb));
printf(" Orig Family : %08x\n", __le32_to_cpu(mpb->orig_family_num)); printf(" Orig Family : %08x\n", __le32_to_cpu(mpb->orig_family_num));
printf(" Family : %08x\n", __le32_to_cpu(mpb->family_num)); printf(" Family : %08x\n", __le32_to_cpu(mpb->family_num));
printf(" Generation : %08x\n", __le32_to_cpu(mpb->generation_num)); printf(" Generation : %08x\n", __le32_to_cpu(mpb->generation_num));
creation_time = __le64_to_cpu(mpb->creation_time);
printf(" Creation Time : %.24s\n",
creation_time ? ctime(&creation_time) : "Unknown");
printf(" Attributes : "); printf(" Attributes : ");
if (imsm_check_attributes(mpb->attributes)) if (imsm_check_attributes(mpb->attributes))
printf("All supported\n"); printf("All supported\n");
else else
printf("not supported\n"); printf("not supported\n");
getinfo_super_imsm(st, &info, NULL); getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(st, &info, nbuf, ':'); fname_from_uuid(st, &info, nbuf, ':');
printf(" UUID : %s\n", nbuf + 5); printf(" UUID : %s\n", nbuf + 5);
sum = __le32_to_cpu(mpb->check_sum); sum = __le32_to_cpu(mpb->check_sum);
printf(" Checksum : %08x %s\n", sum, printf(" Checksum : %08x %s\n", sum,
skipping to change at line 1989 skipping to change at line 2189
super->sector_size); super->sector_size);
examine_migr_rec_imsm(super); examine_migr_rec_imsm(super);
} }
static void brief_examine_super_imsm(struct supertype *st, int verbose) static void brief_examine_super_imsm(struct supertype *st, int verbose)
{ {
/* We just write a generic IMSM ARRAY entry */ /* We just write a generic IMSM ARRAY entry */
struct mdinfo info; struct mdinfo info;
char nbuf[64]; char nbuf[64];
struct intel_super *super = st->sb;
if (!super->anchor->num_raid_devs) {
printf("ARRAY metadata=imsm\n");
return;
}
getinfo_super_imsm(st, &info, NULL); getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(st, &info, nbuf, ':'); fname_from_uuid(st, &info, nbuf, ':');
printf("ARRAY metadata=imsm UUID=%s\n", nbuf + 5); printf("ARRAY metadata=imsm UUID=%s\n", nbuf + 5);
} }
static void brief_examine_subarrays_imsm(struct supertype *st, int verbose) static void brief_examine_subarrays_imsm(struct supertype *st, int verbose)
{ {
/* We just write a generic IMSM ARRAY entry */ /* We just write a generic IMSM ARRAY entry */
struct mdinfo info; struct mdinfo info;
skipping to change at line 2039 skipping to change at line 2233
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
struct mdinfo info; struct mdinfo info;
char nbuf[64]; char nbuf[64];
getinfo_super_imsm(st, &info, NULL); getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(st, &info, nbuf, ':'); fname_from_uuid(st, &info, nbuf, ':');
printf("MD_METADATA=imsm\n"); printf("MD_METADATA=imsm\n");
printf("MD_LEVEL=container\n"); printf("MD_LEVEL=container\n");
printf("MD_UUID=%s\n", nbuf+5); printf("MD_UUID=%s\n", nbuf+5);
printf("MD_DEVICES=%u\n", mpb->num_disks); printf("MD_DEVICES=%u\n", mpb->num_disks);
printf("MD_CREATION_TIME=%llu\n", __le64_to_cpu(mpb->creation_time));
} }
static int copy_metadata_imsm(struct supertype *st, int from, int to) static void detail_super_imsm(struct supertype *st, char *homehost,
{ char *subarray)
/* The second last 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;
struct intel_super *super = st->sb;
unsigned int sector_size = super->sector_size;
unsigned int written = 0;
if (posix_memalign(&buf, MAX_SECTOR_SIZE, MAX_SECTOR_SIZE) != 0)
return 1;
if (!get_dev_size(from, NULL, &dsize))
goto err;
if (lseek64(from, dsize-(2*sector_size), 0) < 0)
goto err;
if ((unsigned int)read(from, buf, sector_size) != sector_size)
goto err;
sb = buf;
if (strncmp((char*)sb->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0)
goto err;
sectors = mpb_sectors(sb, sector_size) + 2;
offset = dsize - sectors * sector_size;
if (lseek64(from, offset, 0) < 0 ||
lseek64(to, offset, 0) < 0)
goto err;
while (written < sectors * sector_size) {
int n = sectors*sector_size - 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; struct mdinfo info;
char nbuf[64]; char nbuf[64];
struct intel_super *super = st->sb;
int temp_vol = super->current_vol;
if (subarray)
super->current_vol = strtoul(subarray, NULL, 10);
getinfo_super_imsm(st, &info, NULL); getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(st, &info, nbuf, ':'); fname_from_uuid(st, &info, nbuf, ':');
printf("\n UUID : %s\n", nbuf + 5); printf("\n UUID : %s\n", nbuf + 5);
super->current_vol = temp_vol;
} }
static void brief_detail_super_imsm(struct supertype *st) static void brief_detail_super_imsm(struct supertype *st, char *subarray)
{ {
struct mdinfo info; struct mdinfo info;
char nbuf[64]; char nbuf[64];
struct intel_super *super = st->sb;
int temp_vol = super->current_vol;
if (subarray)
super->current_vol = strtoul(subarray, NULL, 10);
getinfo_super_imsm(st, &info, NULL); getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(st, &info, nbuf, ':'); fname_from_uuid(st, &info, nbuf, ':');
printf(" UUID=%s", nbuf + 5); printf(" UUID=%s", nbuf + 5);
super->current_vol = temp_vol;
} }
static int imsm_read_serial(int fd, char *devname, __u8 *serial); static int imsm_read_serial(int fd, char *devname, __u8 *serial,
size_t serial_buf_len);
static void fd2devname(int fd, char *name); static void fd2devname(int fd, char *name);
static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b ase, int verbose) static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b ase, int verbose)
{ {
/* dump an unsorted list of devices attached to AHCI Intel storage /* dump an unsorted list of devices attached to AHCI Intel storage
* controller, as well as non-connected ports * controller, as well as non-connected ports
*/ */
int hba_len = strlen(hba_path) + 1; int hba_len = strlen(hba_path) + 1;
struct dirent *ent; struct dirent *ent;
DIR *dir; DIR *dir;
skipping to change at line 2149 skipping to change at line 2306
dir = opendir("/sys/dev/block"); dir = opendir("/sys/dev/block");
if (!dir) if (!dir)
return 1; return 1;
for (ent = readdir(dir); ent; ent = readdir(dir)) { for (ent = readdir(dir); ent; ent = readdir(dir)) {
int fd; int fd;
char model[64]; char model[64];
char vendor[64]; char vendor[64];
char buf[1024]; char buf[1024];
int major, minor; int major, minor;
char *device; char device[PATH_MAX];
char *c; char *c;
int port; int port;
int type; int type;
if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2) if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2)
continue; continue;
path = devt_to_devpath(makedev(major, minor)); path = devt_to_devpath(makedev(major, minor), 1, NULL);
if (!path) if (!path)
continue; continue;
if (!path_attached_to_hba(path, hba_path)) { if (!path_attached_to_hba(path, hba_path)) {
free(path); free(path);
path = NULL; path = NULL;
continue; continue;
} }
/* retrieve the scsi device type */ /* retrieve the scsi device */
if (asprintf(&device, "/sys/dev/block/%d:%d/device/xxxxxxx", majo if (!devt_to_devpath(makedev(major, minor), 1, device)) {
r, minor) < 0) {
if (verbose > 0) if (verbose > 0)
pr_err("failed to allocate 'device'\n"); pr_err("failed to get device\n");
err = 2; err = 2;
break; break;
} }
sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor) if (devpath_to_char(device, "type", buf, sizeof(buf), 0)) {
;
if (load_sys(device, buf, sizeof(buf)) != 0) {
if (verbose > 0)
pr_err("failed to read device type for %s\n",
path);
err = 2; err = 2;
free(device);
break; break;
} }
type = strtoul(buf, NULL, 10); type = strtoul(buf, NULL, 10);
/* if it's not a disk print the vendor and model */ /* if it's not a disk print the vendor and model */
if (!(type == 0 || type == 7 || type == 14)) { if (!(type == 0 || type == 7 || type == 14)) {
vendor[0] = '\0'; vendor[0] = '\0';
model[0] = '\0'; model[0] = '\0';
sprintf(device, "/sys/dev/block/%d:%d/device/vendor", maj
or, minor); if (devpath_to_char(device, "vendor", buf,
if (load_sys(device, buf, sizeof(buf)) == 0) { sizeof(buf), 0) == 0) {
strncpy(vendor, buf, sizeof(vendor)); strncpy(vendor, buf, sizeof(vendor));
vendor[sizeof(vendor) - 1] = '\0'; vendor[sizeof(vendor) - 1] = '\0';
c = (char *) &vendor[sizeof(vendor) - 1]; c = (char *) &vendor[sizeof(vendor) - 1];
while (isspace(*c) || *c == '\0') while (isspace(*c) || *c == '\0')
*c-- = '\0'; *c-- = '\0';
} }
sprintf(device, "/sys/dev/block/%d:%d/device/model", majo
r, minor); if (devpath_to_char(device, "model", buf,
if (load_sys(device, buf, sizeof(buf)) == 0) { sizeof(buf), 0) == 0) {
strncpy(model, buf, sizeof(model)); strncpy(model, buf, sizeof(model));
model[sizeof(model) - 1] = '\0'; model[sizeof(model) - 1] = '\0';
c = (char *) &model[sizeof(model) - 1]; c = (char *) &model[sizeof(model) - 1];
while (isspace(*c) || *c == '\0') while (isspace(*c) || *c == '\0')
*c-- = '\0'; *c-- = '\0';
} }
if (vendor[0] && model[0]) if (vendor[0] && model[0])
sprintf(buf, "%.64s %.64s", vendor, model); sprintf(buf, "%.64s %.64s", vendor, model);
else else
skipping to change at line 2222 skipping to change at line 2376
case 4: case 4:
case 5: sprintf(buf, "cdrom"); break; case 5: sprintf(buf, "cdrom"); break;
case 6: sprintf(buf, "scanner"); break; case 6: sprintf(buf, "scanner"); break;
case 8: sprintf(buf, "media_changer"); break; case 8: sprintf(buf, "media_changer"); break;
case 9: sprintf(buf, "comm"); break; case 9: sprintf(buf, "comm"); break;
case 12: sprintf(buf, "raid"); break; case 12: sprintf(buf, "raid"); break;
default: sprintf(buf, "unknown"); default: sprintf(buf, "unknown");
} }
} else } else
buf[0] = '\0'; buf[0] = '\0';
free(device);
/* chop device path to 'host%d' and calculate the port number */ /* chop device path to 'host%d' and calculate the port number */
c = strchr(&path[hba_len], '/'); c = strchr(&path[hba_len], '/');
if (!c) { if (!c) {
if (verbose > 0) if (verbose > 0)
pr_err("%s - invalid path name\n", path + hba_len ); pr_err("%s - invalid path name\n", path + hba_len );
err = 2; err = 2;
break; break;
} }
*c = '\0'; *c = '\0';
skipping to change at line 2256 skipping to change at line 2409
/* mark this port as used */ /* mark this port as used */
port_mask &= ~(1 << port); port_mask &= ~(1 << port);
/* print out the device information */ /* print out the device information */
if (buf[0]) { if (buf[0]) {
printf(" Port%d : - non-disk device (%s) -\n", p ort, buf); printf(" Port%d : - non-disk device (%s) -\n", p ort, buf);
continue; continue;
} }
fd = dev_open(ent->d_name, O_RDONLY); fd = dev_open(ent->d_name, O_RDONLY);
if (fd < 0) if (!is_fd_valid(fd))
printf(" Port%d : - disk info unavailable -\n", port); printf(" Port%d : - disk info unavailable -\n", port);
else { else {
fd2devname(fd, buf); fd2devname(fd, buf);
printf(" Port%d : %s", port, buf); printf(" Port%d : %s", port, buf);
if (imsm_read_serial(fd, NULL, (__u8 *) buf) == 0) if (imsm_read_serial(fd, NULL, (__u8 *)buf,
printf(" (%.*s)\n", MAX_RAID_SERIAL_LEN, buf); sizeof(buf)) == 0)
printf(" (%s)\n", buf);
else else
printf(" ()\n"); printf(" ()\n");
close(fd); close(fd);
} }
free(path); free(path);
path = NULL; path = NULL;
} }
if (path) if (path)
free(path); free(path);
if (dir) if (dir)
skipping to change at line 2285 skipping to change at line 2439
int i; int i;
for (i = 0; i < port_count; i++) for (i = 0; i < port_count; i++)
if (port_mask & (1 << i)) if (port_mask & (1 << i))
printf(" Port%d : - no device attached - \n", i); printf(" Port%d : - no device attached - \n", i);
} }
return err; return err;
} }
static int print_vmd_attached_devs(struct sys_dev *hba) static int print_nvme_info(struct sys_dev *hba)
{ {
struct dirent *ent; struct dirent *ent;
DIR *dir; DIR *dir;
char path[292];
char link[256];
char *c, *rp;
if (hba->type != SYS_DEV_VMD)
return 1;
/* scroll through /sys/dev/block looking for devices attached to dir = opendir("/sys/block/");
* this hba
*/
dir = opendir("/sys/bus/pci/drivers/nvme");
if (!dir) if (!dir)
return 1; return 1;
for (ent = readdir(dir); ent; ent = readdir(dir)) { for (ent = readdir(dir); ent; ent = readdir(dir)) {
int n; char ns_path[PATH_MAX];
char cntrl_path[PATH_MAX];
/* is 'ent' a device? check that the 'subsystem' link exists and char buf[PATH_MAX];
* that its target matches 'bus' int fd = -1;
*/
sprintf(path, "/sys/bus/pci/drivers/nvme/%s/subsystem", if (!strstr(ent->d_name, "nvme"))
ent->d_name); goto skip;
n = readlink(path, link, sizeof(link));
if (n < 0 || n >= (int)sizeof(link)) fd = open_dev(ent->d_name);
continue; if (!is_fd_valid(fd))
link[n] = '\0'; goto skip;
c = strrchr(link, '/');
if (!c) if (!diskfd_to_devpath(fd, 0, ns_path) ||
continue; !diskfd_to_devpath(fd, 1, cntrl_path))
if (strncmp("pci", c+1, strlen("pci")) != 0) goto skip;
continue;
if (!path_attached_to_hba(cntrl_path, hba->path))
sprintf(path, "/sys/bus/pci/drivers/nvme/%s", ent->d_name); goto skip;
rp = realpath(path, NULL); if (!imsm_is_nvme_namespace_supported(fd, 0))
if (!rp) goto skip;
continue;
fd2devname(fd, buf);
if (hba->type == SYS_DEV_VMD)
printf(" NVMe under VMD : %s", buf);
else if (hba->type == SYS_DEV_NVME)
printf(" NVMe Device : %s", buf);
if (!imsm_read_serial(fd, NULL, (__u8 *)buf,
sizeof(buf)))
printf(" (%s)\n", buf);
else
printf("()\n");
if (path_attached_to_hba(rp, hba->path)) { skip:
printf(" NVMe under VMD : %s\n", rp); close_fd(&fd);
}
free(rp);
} }
closedir(dir); closedir(dir);
return 0; return 0;
} }
static void print_found_intel_controllers(struct sys_dev *elem) static void print_found_intel_controllers(struct sys_dev *elem)
{ {
for (; elem; elem = elem->next) { for (; elem; elem = elem->next) {
pr_err("found Intel(R) "); pr_err("found Intel(R) ");
skipping to change at line 2545 skipping to change at line 2699
for (entry = orom_entries; entry; entry = entry->next) { for (entry = orom_entries; entry; entry = entry->next) {
if (entry->type == SYS_DEV_VMD) { if (entry->type == SYS_DEV_VMD) {
print_imsm_capability(&entry->orom); print_imsm_capability(&entry->orom);
printf(" 3rd party NVMe :%s supported\n", printf(" 3rd party NVMe :%s supported\n",
imsm_orom_has_tpv_support(&entry->orom)?"":" not"); imsm_orom_has_tpv_support(&entry->orom)?"":" not");
for (hba = list; hba; hba = hba->next) { for (hba = list; hba; hba = hba->next) {
if (hba->type == SYS_DEV_VMD) { if (hba->type == SYS_DEV_VMD) {
char buf[PATH_MAX]; char buf[PATH_MAX];
printf(" I/O Controller : %s (%s)\n", printf(" I/O Controller : %s (%s)\n",
vmd_domain_to_controller(hba, buf ), get_sys_dev_type(hba->type)); vmd_domain_to_controller(hba, buf ), get_sys_dev_type(hba->type));
if (print_vmd_attached_devs(hba)) { if (print_nvme_info(hba)) {
if (verbose > 0) if (verbose > 0)
pr_err("failed to get dev ices attached to VMD domain.\n"); pr_err("failed to get dev ices attached to VMD domain.\n");
result |= 2; result |= 2;
} }
} }
} }
printf("\n"); printf("\n");
continue; continue;
} }
print_imsm_capability(&entry->orom); print_imsm_capability(&entry->orom);
if (entry->type == SYS_DEV_NVME) { if (entry->type == SYS_DEV_NVME) {
for (hba = list; hba; hba = hba->next) { for (hba = list; hba; hba = hba->next) {
if (hba->type == SYS_DEV_NVME) if (hba->type == SYS_DEV_NVME)
printf(" NVMe Device : %s\n", hba->pat h); print_nvme_info(hba);
} }
printf("\n"); printf("\n");
continue; continue;
} }
struct devid_list *devid; struct devid_list *devid;
for (devid = entry->devid_list; devid; devid = devid->next) { for (devid = entry->devid_list; devid; devid = devid->next) {
hba = device_by_id(devid->devid); hba = device_by_id(devid->devid);
if (!hba) if (!hba)
continue; continue;
skipping to change at line 2783 skipping to change at line 2937
int level = get_imsm_raid_level(lo); int level = get_imsm_raid_level(lo);
if (level == 1 || level == 10) { if (level == 1 || level == 10) {
struct imsm_map *hi = get_imsm_map(dev, MAP_1); struct imsm_map *hi = get_imsm_map(dev, MAP_1);
return hi->num_domains; return hi->num_domains;
} else } else
return num_stripes_per_unit_resync(dev); return num_stripes_per_unit_resync(dev);
} }
static __u8 imsm_num_data_members(struct imsm_map *map)
{
/* named 'imsm_' because raid0, raid1 and raid10
* counter-intuitively have the same number of data disks
*/
switch (get_imsm_raid_level(map)) {
case 0:
return map->num_members;
break;
case 1:
case 10:
return map->num_members/2;
case 5:
return map->num_members - 1;
default:
dprintf("unsupported raid level\n");
return 0;
}
}
static unsigned long long calc_component_size(struct imsm_map *map, static unsigned long long calc_component_size(struct imsm_map *map,
struct imsm_dev *dev) struct imsm_dev *dev)
{ {
unsigned long long component_size; unsigned long long component_size;
unsigned long long dev_size = imsm_dev_size(dev); unsigned long long dev_size = imsm_dev_size(dev);
unsigned long long calc_dev_size = 0; long long calc_dev_size = 0;
unsigned int member_disks = imsm_num_data_members(map); unsigned int member_disks = imsm_num_data_members(map);
if (member_disks == 0) if (member_disks == 0)
return 0; return 0;
component_size = per_dev_array_size(map); component_size = per_dev_array_size(map);
calc_dev_size = component_size * member_disks; calc_dev_size = component_size * member_disks;
/* Component size is rounded to 1MB so difference between size from /* Component size is rounded to 1MB so difference between size from
* metadata and size calculated from num_data_stripes equals up to * metadata and size calculated from num_data_stripes equals up to
* 2048 blocks per each device. If the difference is higher it means * 2048 blocks per each device. If the difference is higher it means
* that array size was expanded and num_data_stripes was not updated. * that array size was expanded and num_data_stripes was not updated.
*/ */
if ((unsigned int)abs(calc_dev_size - dev_size) > if (llabs(calc_dev_size - (long long)dev_size) >
(1 << SECT_PER_MB_SHIFT) * member_disks) { (1 << SECT_PER_MB_SHIFT) * member_disks) {
component_size = dev_size / member_disks; component_size = dev_size / member_disks;
dprintf("Invalid num_data_stripes in metadata; expected=%llu, fou nd=%llu\n", dprintf("Invalid num_data_stripes in metadata; expected=%llu, fou nd=%llu\n",
component_size / map->blocks_per_strip, component_size / map->blocks_per_strip,
num_data_stripes(map)); num_data_stripes(map));
} }
return component_size; return component_size;
} }
skipping to change at line 3001 skipping to change at line 3135
} }
return NULL; return NULL;
} }
/******************************************************************************* /*******************************************************************************
* Function: load_imsm_migr_rec * Function: load_imsm_migr_rec
* Description: Function reads imsm migration record (it is stored at the last * Description: Function reads imsm migration record (it is stored at the last
* sector of disk) * sector of disk)
* Parameters: * Parameters:
* super : imsm internal array info * super : imsm internal array info
* info : general array info
* Returns: * Returns:
* 0 : success * 0 : success
* -1 : fail * -1 : fail
* -2 : no migration in progress * -2 : no migration in progress
******************************************************************************/ ******************************************************************************/
static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info) static int load_imsm_migr_rec(struct intel_super *super)
{ {
struct mdinfo *sd;
struct dl *dl; struct dl *dl;
char nm[30]; char nm[30];
int retval = -1; int retval = -1;
int fd = -1; int fd = -1;
struct imsm_dev *dev; struct imsm_dev *dev;
struct imsm_map *map; struct imsm_map *map;
int slot = -1; int slot = -1;
int keep_fd = 1;
/* find map under migration */ /* find map under migration */
dev = imsm_get_device_during_migration(super); dev = imsm_get_device_during_migration(super);
/* nothing to load,no migration in progress? /* nothing to load,no migration in progress?
*/ */
if (dev == NULL) if (dev == NULL)
return -2; return -2;
if (info) { map = get_imsm_map(dev, MAP_0);
for (sd = info->devs ; sd ; sd = sd->next) { if (!map)
/* read only from one of the first two slots */ return -1;
if ((sd->disk.raid_disk < 0) ||
(sd->disk.raid_disk > 1))
continue;
sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor); for (dl = super->disks; dl; dl = dl->next) {
fd = dev_open(nm, O_RDONLY); /* skip spare and failed disks
if (fd >= 0) */
break; if (dl->index < 0)
} continue;
} /* read only from one of the first two slots
if (fd < 0) { */
map = get_imsm_map(dev, MAP_0); slot = get_imsm_disk_slot(map, dl->index);
for (dl = super->disks; dl; dl = dl->next) { if (slot > 1 || slot < 0)
/* skip spare and failed disks continue;
*/
if (dl->index < 0) if (!is_fd_valid(dl->fd)) {
continue;
/* read only from one of the first two slots */
if (map)
slot = get_imsm_disk_slot(map, dl->index);
if (map == NULL || slot > 1 || slot < 0)
continue;
sprintf(nm, "%d:%d", dl->major, dl->minor); sprintf(nm, "%d:%d", dl->major, dl->minor);
fd = dev_open(nm, O_RDONLY); fd = dev_open(nm, O_RDONLY);
if (fd >= 0)
if (is_fd_valid(fd)) {
keep_fd = 0;
break; break;
}
} else {
fd = dl->fd;
break;
} }
} }
if (fd < 0)
goto out;
retval = read_imsm_migr_rec(fd, super);
out: if (!is_fd_valid(fd))
if (fd >= 0) return retval;
retval = read_imsm_migr_rec(fd, super);
if (!keep_fd)
close(fd); close(fd);
return retval; return retval;
} }
/******************************************************************************* /*******************************************************************************
* function: imsm_create_metadata_checkpoint_update * function: imsm_create_metadata_checkpoint_update
* Description: It creates update for checkpoint change. * Description: It creates update for checkpoint change.
* Parameters: * Parameters:
* super : imsm internal array info * super : imsm internal array info
* u : pointer to prepared update * u : pointer to prepared update
* Returns: * Returns:
skipping to change at line 3099 skipping to change at line 3229
/* size of all update data without anchor */ /* size of all update data without anchor */
update_memory_size = update_memory_size =
sizeof(struct imsm_update_general_migration_checkpoint); sizeof(struct imsm_update_general_migration_checkpoint);
*u = xcalloc(1, update_memory_size); *u = xcalloc(1, update_memory_size);
if (*u == NULL) { if (*u == NULL) {
dprintf("error: cannot get memory\n"); dprintf("error: cannot get memory\n");
return 0; return 0;
} }
(*u)->type = update_general_migration_checkpoint; (*u)->type = update_general_migration_checkpoint;
(*u)->curr_migr_unit = __le32_to_cpu(super->migr_rec->curr_migr_unit); (*u)->curr_migr_unit = current_migr_unit(super->migr_rec);
dprintf("prepared for %u\n", (*u)->curr_migr_unit); dprintf("prepared for %llu\n", (unsigned long long)(*u)->curr_migr_unit);
return update_memory_size; return update_memory_size;
} }
static void imsm_update_metadata_locally(struct supertype *st, static void imsm_update_metadata_locally(struct supertype *st,
void *buf, int len); void *buf, int len);
/******************************************************************************* /*******************************************************************************
* Function: write_imsm_migr_rec * Function: write_imsm_migr_rec
* Description: Function writes imsm migration record * Description: Function writes imsm migration record
skipping to change at line 3123 skipping to change at line 3253
* super : imsm internal array info * super : imsm internal array info
* Returns: * Returns:
* 0 : success * 0 : success
* -1 : if fail * -1 : if fail
******************************************************************************/ ******************************************************************************/
static int write_imsm_migr_rec(struct supertype *st) static int write_imsm_migr_rec(struct supertype *st)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
unsigned int sector_size = super->sector_size; unsigned int sector_size = super->sector_size;
unsigned long long dsize; unsigned long long dsize;
char nm[30];
int fd = -1;
int retval = -1; int retval = -1;
struct dl *sd; struct dl *sd;
int len; int len;
struct imsm_update_general_migration_checkpoint *u; struct imsm_update_general_migration_checkpoint *u;
struct imsm_dev *dev; struct imsm_dev *dev;
struct imsm_map *map; struct imsm_map *map;
/* find map under migration */ /* find map under migration */
dev = imsm_get_device_during_migration(super); dev = imsm_get_device_during_migration(super);
/* if no migration, write buffer anyway to clear migr_record /* if no migration, write buffer anyway to clear migr_record
skipping to change at line 3157 skipping to change at line 3285
/* skip failed and spare devices */ /* skip failed and spare devices */
if (sd->index < 0) if (sd->index < 0)
continue; continue;
/* write to 2 first slots only */ /* write to 2 first slots only */
if (map) if (map)
slot = get_imsm_disk_slot(map, sd->index); slot = get_imsm_disk_slot(map, sd->index);
if (map == NULL || slot > 1 || slot < 0) if (map == NULL || slot > 1 || slot < 0)
continue; continue;
sprintf(nm, "%d:%d", sd->major, sd->minor); get_dev_size(sd->fd, NULL, &dsize);
fd = dev_open(nm, O_RDWR); if (lseek64(sd->fd, dsize - (MIGR_REC_SECTOR_POSITION *
if (fd < 0) sector_size),
continue;
get_dev_size(fd, NULL, &dsize);
if (lseek64(fd, dsize - (MIGR_REC_SECTOR_POSITION*sector_size),
SEEK_SET) < 0) { SEEK_SET) < 0) {
pr_err("Cannot seek to anchor block: %s\n", pr_err("Cannot seek to anchor block: %s\n",
strerror(errno)); strerror(errno));
goto out; goto out;
} }
if ((unsigned int)write(fd, super->migr_rec_buf, if ((unsigned int)write(sd->fd, super->migr_rec_buf,
MIGR_REC_BUF_SECTORS*sector_size) != MIGR_REC_BUF_SECTORS*sector_size) !=
MIGR_REC_BUF_SECTORS*sector_size) { MIGR_REC_BUF_SECTORS*sector_size) {
pr_err("Cannot write migr record block: %s\n", pr_err("Cannot write migr record block: %s\n",
strerror(errno)); strerror(errno));
goto out; goto out;
} }
close(fd);
fd = -1;
} }
if (sector_size == 4096) if (sector_size == 4096)
convert_from_4k_imsm_migr_rec(super); convert_from_4k_imsm_migr_rec(super);
/* update checkpoint information in metadata */ /* update checkpoint information in metadata */
len = imsm_create_metadata_checkpoint_update(super, &u); len = imsm_create_metadata_checkpoint_update(super, &u);
if (len <= 0) { if (len <= 0) {
dprintf("imsm: Cannot prepare update\n"); dprintf("imsm: Cannot prepare update\n");
goto out; goto out;
} }
/* update metadata locally */ /* update metadata locally */
skipping to change at line 3202 skipping to change at line 3325
* manage_reshape(), so metadata update has to be triggered * manage_reshape(), so metadata update has to be triggered
* insida it * insida it
*/ */
flush_metadata_updates(st); flush_metadata_updates(st);
st->update_tail = &st->updates; st->update_tail = &st->updates;
} else } else
free(u); free(u);
retval = 0; retval = 0;
out: out:
if (fd >= 0)
close(fd);
return retval; return retval;
} }
/* spare/missing disks activations are not allowe when /* spare/missing disks activations are not allowe when
* array/container performs reshape operation, because * array/container performs reshape operation, because
* all arrays in container works on the same disks set * all arrays in container works on the same disks set
*/ */
int imsm_reshape_blocks_arrays_changes(struct intel_super *super) int imsm_reshape_blocks_arrays_changes(struct intel_super *super)
{ {
int rv = 0; int rv = 0;
skipping to change at line 3256 skipping to change at line 3377
dprintf("imsm: reported component size aligned from %llu ", dprintf("imsm: reported component size aligned from %llu ",
component_size); component_size);
component_size -= component_size_alignment; component_size -= component_size_alignment;
dprintf_cont("to %llu (%i).\n", dprintf_cont("to %llu (%i).\n",
component_size, component_size_alignment); component_size, component_size_alignment);
} }
return component_size; return component_size;
} }
/*******************************************************************************
* Function: get_bitmap_header_sector
* Description: Returns the sector where the bitmap header is placed.
* Parameters:
* st : supertype information
* dev_idx : index of the device with bitmap
*
* Returns:
* The sector where the bitmap header is placed
******************************************************************************/
static unsigned long long get_bitmap_header_sector(struct intel_super *super,
int dev_idx)
{
struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
struct imsm_map *map = get_imsm_map(dev, MAP_0);
if (!super->sector_size) {
dprintf("sector size is not set\n");
return 0;
}
return pba_of_lba0(map) + calc_component_size(map, dev) +
(IMSM_BITMAP_HEADER_OFFSET / super->sector_size);
}
/*******************************************************************************
* Function: get_bitmap_sector
* Description: Returns the sector where the bitmap is placed.
* Parameters:
* st : supertype information
* dev_idx : index of the device with bitmap
*
* Returns:
* The sector where the bitmap is placed
******************************************************************************/
static unsigned long long get_bitmap_sector(struct intel_super *super,
int dev_idx)
{
if (!super->sector_size) {
dprintf("sector size is not set\n");
return 0;
}
return get_bitmap_header_sector(super, dev_idx) +
(IMSM_BITMAP_HEADER_SIZE / super->sector_size);
}
static unsigned long long get_ppl_sector(struct intel_super *super, int dev_idx) static unsigned long long get_ppl_sector(struct intel_super *super, int dev_idx)
{ {
struct imsm_dev *dev = get_imsm_dev(super, dev_idx); struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
return pba_of_lba0(map) + return pba_of_lba0(map) +
(num_data_stripes(map) * map->blocks_per_strip); (num_data_stripes(map) * map->blocks_per_strip);
} }
static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap) static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
skipping to change at line 3296 skipping to change at line 3464
info->array.md_minor = -1; info->array.md_minor = -1;
info->array.ctime = 0; info->array.ctime = 0;
info->array.utime = 0; info->array.utime = 0;
info->array.chunk_size = info->array.chunk_size =
__le16_to_cpu(map_to_analyse->blocks_per_strip) << 9; __le16_to_cpu(map_to_analyse->blocks_per_strip) << 9;
info->array.state = !(dev->vol.dirty & RAIDVOL_DIRTY); info->array.state = !(dev->vol.dirty & RAIDVOL_DIRTY);
info->custom_array_size = imsm_dev_size(dev); info->custom_array_size = imsm_dev_size(dev);
info->recovery_blocked = imsm_reshape_blocks_arrays_changes(st->sb); info->recovery_blocked = imsm_reshape_blocks_arrays_changes(st->sb);
if (is_gen_migration(dev)) { if (is_gen_migration(dev)) {
/*
* device prev_map should be added if it is in the middle
* of migration
*/
assert(prev_map);
info->reshape_active = 1; info->reshape_active = 1;
info->new_level = get_imsm_raid_level(map); info->new_level = get_imsm_raid_level(map);
info->new_layout = imsm_level_to_layout(info->new_level); info->new_layout = imsm_level_to_layout(info->new_level);
info->new_chunk = __le16_to_cpu(map->blocks_per_strip) << 9; info->new_chunk = __le16_to_cpu(map->blocks_per_strip) << 9;
info->delta_disks = map->num_members - prev_map->num_members; info->delta_disks = map->num_members - prev_map->num_members;
if (info->delta_disks) { if (info->delta_disks) {
/* this needs to be applied to every array /* this needs to be applied to every array
* in the container. * in the container.
*/ */
info->reshape_active = CONTAINER_RESHAPE; info->reshape_active = CONTAINER_RESHAPE;
skipping to change at line 3376 skipping to change at line 3550
info->consistency_policy = CONSISTENCY_POLICY_PPL; info->consistency_policy = CONSISTENCY_POLICY_PPL;
info->ppl_sector = get_ppl_sector(super, super->current_vol); info->ppl_sector = get_ppl_sector(super, super->current_vol);
if (dev->rwh_policy == RWH_MULTIPLE_DISTRIBUTED) if (dev->rwh_policy == RWH_MULTIPLE_DISTRIBUTED)
info->ppl_size = MULTIPLE_PPL_AREA_SIZE_IMSM >> 9; info->ppl_size = MULTIPLE_PPL_AREA_SIZE_IMSM >> 9;
else else
info->ppl_size = (PPL_HEADER_SIZE + PPL_ENTRY_SPACE) info->ppl_size = (PPL_HEADER_SIZE + PPL_ENTRY_SPACE)
>> 9; >> 9;
} else if (info->array.level <= 0) { } else if (info->array.level <= 0) {
info->consistency_policy = CONSISTENCY_POLICY_NONE; info->consistency_policy = CONSISTENCY_POLICY_NONE;
} else { } else {
info->consistency_policy = CONSISTENCY_POLICY_RESYNC; if (dev->rwh_policy == RWH_BITMAP) {
info->bitmap_offset = get_bitmap_sector(super, super->cur
rent_vol);
info->consistency_policy = CONSISTENCY_POLICY_BITMAP;
} else {
info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
}
} }
info->reshape_progress = 0; info->reshape_progress = 0;
info->resync_start = MaxSector; info->resync_start = MaxSector;
if ((map_to_analyse->map_state == IMSM_T_STATE_UNINITIALIZED || if ((map_to_analyse->map_state == IMSM_T_STATE_UNINITIALIZED ||
!(info->array.state & 1)) && !(info->array.state & 1)) &&
imsm_reshape_blocks_arrays_changes(super) == 0) { imsm_reshape_blocks_arrays_changes(super) == 0) {
info->resync_start = 0; info->resync_start = 0;
} }
if (dev->vol.migr_state) { if (dev->vol.migr_state) {
switch (migr_type(dev)) { switch (migr_type(dev)) {
case MIGR_REPAIR: case MIGR_REPAIR:
case MIGR_INIT: { case MIGR_INIT: {
__u64 blocks_per_unit = blocks_per_migr_unit(super, __u64 blocks_per_unit = blocks_per_migr_unit(super,
dev); dev);
__u64 units = __le32_to_cpu(dev->vol.curr_migr_unit); __u64 units = vol_curr_migr_unit(dev);
info->resync_start = blocks_per_unit * units; info->resync_start = blocks_per_unit * units;
break; break;
} }
case MIGR_GEN_MIGR: { case MIGR_GEN_MIGR: {
__u64 blocks_per_unit = blocks_per_migr_unit(super, __u64 blocks_per_unit = blocks_per_migr_unit(super,
dev); dev);
__u64 units = __le32_to_cpu(migr_rec->curr_migr_unit); __u64 units = current_migr_unit(migr_rec);
unsigned long long array_blocks;
int used_disks; int used_disks;
if (__le32_to_cpu(migr_rec->ascending_migr) && if (__le32_to_cpu(migr_rec->ascending_migr) &&
(units < (units <
(__le32_to_cpu(migr_rec->num_migr_units)-1)) && (get_num_migr_units(migr_rec)-1)) &&
(super->migr_rec->rec_status == (super->migr_rec->rec_status ==
__cpu_to_le32(UNIT_SRC_IN_CP_AREA))) __cpu_to_le32(UNIT_SRC_IN_CP_AREA)))
units++; units++;
info->reshape_progress = blocks_per_unit * units; info->reshape_progress = blocks_per_unit * units;
dprintf("IMSM: General Migration checkpoint : %llu (%llu) -> read reshape progress : %llu\n", dprintf("IMSM: General Migration checkpoint : %llu (%llu) -> read reshape progress : %llu\n",
(unsigned long long)units, (unsigned long long)units,
(unsigned long long)blocks_per_unit, (unsigned long long)blocks_per_unit,
info->reshape_progress); info->reshape_progress);
used_disks = imsm_num_data_members(prev_map); used_disks = imsm_num_data_members(prev_map);
if (used_disks > 0) { if (used_disks > 0) {
array_blocks = per_dev_array_size(map) * info->custom_array_size = per_dev_array_size(map) *
used_disks; used_disks;
info->custom_array_size =
round_size_to_mb(array_blocks,
used_disks);
} }
} }
case MIGR_VERIFY: case MIGR_VERIFY:
/* we could emulate the checkpointing of /* we could emulate the checkpointing of
* 'sync_action=check' migrations, but for now * 'sync_action=check' migrations, but for now
* we just immediately complete them * we just immediately complete them
*/ */
case MIGR_REBUILD: case MIGR_REBUILD:
/* this is handled by container_content_imsm() */ /* this is handled by container_content_imsm() */
case MIGR_STATE_CHANGE: case MIGR_STATE_CHANGE:
skipping to change at line 3780 skipping to change at line 3954
free(super->devlist); free(super->devlist);
super->devlist = dv; super->devlist = dv;
} }
} }
static void imsm_copy_dev(struct imsm_dev *dest, struct imsm_dev *src) static void imsm_copy_dev(struct imsm_dev *dest, struct imsm_dev *src)
{ {
memcpy(dest, src, sizeof_imsm_dev(src, 0)); memcpy(dest, src, sizeof_imsm_dev(src, 0));
} }
static int compare_super_imsm(struct supertype *st, struct supertype *tst) static int compare_super_imsm(struct supertype *st, struct supertype *tst,
int verbose)
{ {
/* /* return:
* return:
* 0 same, or first was empty, and second was copied * 0 same, or first was empty, and second was copied
* 1 second had wrong number * 1 sb are different
* 2 wrong uuid
* 3 wrong other info
*/ */
struct intel_super *first = st->sb; struct intel_super *first = st->sb;
struct intel_super *sec = tst->sb; struct intel_super *sec = tst->sb;
if (!first) { if (!first) {
st->sb = tst->sb; st->sb = tst->sb;
tst->sb = NULL; tst->sb = NULL;
return 0; return 0;
} }
/* in platform dependent environment test if the disks /* in platform dependent environment test if the disks
* use the same Intel hba * use the same Intel hba
* If not on Intel hba at all, allow anything. * if not on Intel hba at all, allow anything.
* doesn't check HBAs if num_raid_devs is not set, as it means
* it is a free floating spare, and all spares regardless of HBA type
* will fall into separate container during the assembly
*/ */
if (!check_env("IMSM_NO_PLATFORM") && first->hba && sec->hba) { if (first->hba && sec->hba && first->anchor->num_raid_devs != 0) {
if (first->hba->type != sec->hba->type) { if (first->hba->type != sec->hba->type) {
fprintf(stderr, if (verbose)
"HBAs of devices do not match %s != %s\n", pr_err("HBAs of devices do not match %s != %s\n",
get_sys_dev_type(first->hba->type), get_sys_dev_type(first->hba->type),
get_sys_dev_type(sec->hba->type)); get_sys_dev_type(sec->hba->type));
return 3; return 1;
} }
if (first->orom != sec->orom) { if (first->orom != sec->orom) {
fprintf(stderr, if (verbose)
"HBAs of devices do not match %s != %s\n", pr_err("HBAs of devices do not match %s != %s\n",
first->hba->pci_id, sec->hba->pci_id); first->hba->pci_id, sec->hba->pci_id);
return 3; return 1;
} }
} }
/* if an anchor does not have num_raid_devs set then it is a free
* floating spare
*/
if (first->anchor->num_raid_devs > 0 && if (first->anchor->num_raid_devs > 0 &&
sec->anchor->num_raid_devs > 0) { sec->anchor->num_raid_devs > 0) {
/* Determine if these disks might ever have been /* Determine if these disks might ever have been
* related. Further disambiguation can only take place * related. Further disambiguation can only take place
* in load_super_imsm_all * in load_super_imsm_all
*/ */
__u32 first_family = first->anchor->orig_family_num; __u32 first_family = first->anchor->orig_family_num;
__u32 sec_family = sec->anchor->orig_family_num; __u32 sec_family = sec->anchor->orig_family_num;
if (memcmp(first->anchor->sig, sec->anchor->sig, if (memcmp(first->anchor->sig, sec->anchor->sig,
MAX_SIGNATURE_LENGTH) != 0) MAX_SIGNATURE_LENGTH) != 0)
return 3; return 1;
if (first_family == 0) if (first_family == 0)
first_family = first->anchor->family_num; first_family = first->anchor->family_num;
if (sec_family == 0) if (sec_family == 0)
sec_family = sec->anchor->family_num; sec_family = sec->anchor->family_num;
if (first_family != sec_family) if (first_family != sec_family)
return 3; return 1;
} }
/* if 'first' is a spare promote it to a populated mpb with sec's /* if an anchor does not have num_raid_devs set then it is a free
* family number * floating spare. don't assosiate spare with any array, as during assembl
*/ y
if (first->anchor->num_raid_devs == 0 && * spares shall fall into separate container, from which they can be moved
sec->anchor->num_raid_devs > 0) { * when necessary
int i; */
struct intel_dev *dv; if (first->anchor->num_raid_devs ^ sec->anchor->num_raid_devs)
struct imsm_dev *dev; return 1;
/* we need to copy raid device info from sec if an allocation
* fails here we don't associate the spare
*/
for (i = 0; i < sec->anchor->num_raid_devs; i++) {
dv = xmalloc(sizeof(*dv));
dev = xmalloc(sizeof_imsm_dev(get_imsm_dev(sec, i), 1));
dv->dev = dev;
dv->index = i;
dv->next = first->devlist;
first->devlist = dv;
}
if (i < sec->anchor->num_raid_devs) {
/* allocation failure */
free_devlist(first);
pr_err("imsm: failed to associate spare\n");
return 3;
}
first->anchor->num_raid_devs = sec->anchor->num_raid_devs;
first->anchor->orig_family_num = sec->anchor->orig_family_num;
first->anchor->family_num = sec->anchor->family_num;
memcpy(first->anchor->sig, sec->anchor->sig, MAX_SIGNATURE_LENGTH
);
for (i = 0; i < sec->anchor->num_raid_devs; i++)
imsm_copy_dev(get_imsm_dev(first, i), get_imsm_dev(sec, i
));
}
return 0; return 0;
} }
static void fd2devname(int fd, char *name) static void fd2devname(int fd, char *name)
{ {
struct stat st;
char path[256];
char dname[PATH_MAX];
char *nm; char *nm;
int rv;
name[0] = '\0';
if (fstat(fd, &st) != 0)
return;
sprintf(path, "/sys/dev/block/%d:%d",
major(st.st_rdev), minor(st.st_rdev));
rv = readlink(path, dname, sizeof(dname)-1); nm = fd2kname(fd);
if (rv <= 0) if (!nm)
return; return;
dname[rv] = '\0'; snprintf(name, MAX_RAID_SERIAL_LEN, "/dev/%s", nm);
nm = strrchr(dname, '/');
if (nm) {
nm++;
snprintf(name, MAX_RAID_SERIAL_LEN, "/dev/%s", nm);
}
} }
static int nvme_get_serial(int fd, void *buf, size_t buf_len) static int nvme_get_serial(int fd, void *buf, size_t buf_len)
{ {
char path[60]; char path[PATH_MAX];
char *name = fd2kname(fd); char *name = fd2kname(fd);
if (!name) if (!name)
return 1; return 1;
if (strncmp(name, "nvme", 4) != 0) if (strncmp(name, "nvme", 4) != 0)
return 1; return 1;
snprintf(path, sizeof(path) - 1, "/sys/block/%s/device/serial", name); if (!diskfd_to_devpath(fd, 1, path))
return 1;
return load_sys(path, buf, buf_len); return devpath_to_char(path, "serial", buf, buf_len, 0);
} }
extern int scsi_get_serial(int fd, void *buf, size_t buf_len); extern int scsi_get_serial(int fd, void *buf, size_t buf_len);
static int imsm_read_serial(int fd, char *devname, static int imsm_read_serial(int fd, char *devname,
__u8 serial[MAX_RAID_SERIAL_LEN]) __u8 *serial, size_t serial_buf_len)
{ {
char buf[50]; char buf[50];
int rv; int rv;
int len; size_t len;
char *dest; char *dest;
char *src; char *src;
unsigned int i; unsigned int i;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
rv = nvme_get_serial(fd, buf, sizeof(buf)); rv = nvme_get_serial(fd, buf, sizeof(buf));
if (rv) if (rv)
rv = scsi_get_serial(fd, buf, sizeof(buf)); rv = scsi_get_serial(fd, buf, sizeof(buf));
skipping to change at line 3972 skipping to change at line 4105
*/ */
if (*src == ':') if (*src == ':')
*dest++ = ';'; *dest++ = ';';
else else
*dest++ = *src; *dest++ = *src;
} }
} }
len = dest - buf; len = dest - buf;
dest = buf; dest = buf;
/* truncate leading characters */ if (len > serial_buf_len) {
if (len > MAX_RAID_SERIAL_LEN) { /* truncate leading characters */
dest += len - MAX_RAID_SERIAL_LEN; dest += len - serial_buf_len;
len = MAX_RAID_SERIAL_LEN; len = serial_buf_len;
} }
memset(serial, 0, MAX_RAID_SERIAL_LEN); memset(serial, 0, serial_buf_len);
memcpy(serial, dest, len); memcpy(serial, dest, len);
return 0; return 0;
} }
static int serialcmp(__u8 *s1, __u8 *s2) static int serialcmp(__u8 *s1, __u8 *s2)
{ {
return strncmp((char *) s1, (char *) s2, MAX_RAID_SERIAL_LEN); return strncmp((char *) s1, (char *) s2, MAX_RAID_SERIAL_LEN);
} }
skipping to change at line 4033 skipping to change at line 4166
static int static int
load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd) load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd)
{ {
struct imsm_disk *disk; struct imsm_disk *disk;
struct dl *dl; struct dl *dl;
struct stat stb; struct stat stb;
int rv; int rv;
char name[40]; char name[40];
__u8 serial[MAX_RAID_SERIAL_LEN]; __u8 serial[MAX_RAID_SERIAL_LEN];
rv = imsm_read_serial(fd, devname, serial); rv = imsm_read_serial(fd, devname, serial, MAX_RAID_SERIAL_LEN);
if (rv != 0) if (rv != 0)
return 2; return 2;
dl = xcalloc(1, sizeof(*dl)); dl = xcalloc(1, sizeof(*dl));
fstat(fd, &stb); fstat(fd, &stb);
dl->major = major(stb.st_rdev); dl->major = major(stb.st_rdev);
dl->minor = minor(stb.st_rdev); dl->minor = minor(stb.st_rdev);
dl->next = super->disks; dl->next = super->disks;
skipping to change at line 4096 skipping to change at line 4229
* map1state=normal) * map1state=normal)
*/ */
static void migrate(struct imsm_dev *dev, struct intel_super *super, static void migrate(struct imsm_dev *dev, struct intel_super *super,
__u8 to_state, int migr_type) __u8 to_state, int migr_type)
{ {
struct imsm_map *dest; struct imsm_map *dest;
struct imsm_map *src = get_imsm_map(dev, MAP_0); struct imsm_map *src = get_imsm_map(dev, MAP_0);
dev->vol.migr_state = 1; dev->vol.migr_state = 1;
set_migr_type(dev, migr_type); set_migr_type(dev, migr_type);
dev->vol.curr_migr_unit = 0; set_vol_curr_migr_unit(dev, 0);
dest = get_imsm_map(dev, MAP_1); dest = get_imsm_map(dev, MAP_1);
/* duplicate and then set the target end state in map[0] */ /* duplicate and then set the target end state in map[0] */
memcpy(dest, src, sizeof_imsm_map(src)); memcpy(dest, src, sizeof_imsm_map(src));
if (migr_type == MIGR_GEN_MIGR) { if (migr_type == MIGR_GEN_MIGR) {
__u32 ord; __u32 ord;
int i; int i;
for (i = 0; i < src->num_members; i++) { for (i = 0; i < src->num_members; i++) {
ord = __le32_to_cpu(src->disk_ord_tbl[i]); ord = __le32_to_cpu(src->disk_ord_tbl[i]);
skipping to change at line 4131 skipping to change at line 4264
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
struct imsm_map *prev = get_imsm_map(dev, dev->vol.migr_state == 0 ? struct imsm_map *prev = get_imsm_map(dev, dev->vol.migr_state == 0 ?
MAP_0 : MAP_1); MAP_0 : MAP_1);
int i, j; int i, j;
/* merge any IMSM_ORD_REBUILD bits that were not successfully /* merge any IMSM_ORD_REBUILD bits that were not successfully
* completed in the last migration. * completed in the last migration.
* *
* FIXME add support for raid-level-migration * FIXME add support for raid-level-migration
*/ */
if (map_state != map->map_state && (is_gen_migration(dev) == 0) && if (map_state != map->map_state && (is_gen_migration(dev) == false) &&
prev->map_state != IMSM_T_STATE_UNINITIALIZED) { prev->map_state != IMSM_T_STATE_UNINITIALIZED) {
/* when final map state is other than expected /* when final map state is other than expected
* merge maps (not for migration) * merge maps (not for migration)
*/ */
int failed; int failed;
for (i = 0; i < prev->num_members; i++) for (i = 0; i < prev->num_members; i++)
for (j = 0; j < map->num_members; j++) for (j = 0; j < map->num_members; j++)
/* during online capacity expansion /* during online capacity expansion
* disks position can be changed * disks position can be changed
skipping to change at line 4156 skipping to change at line 4289
map->disk_ord_tbl[j] |= map->disk_ord_tbl[j] |=
prev->disk_ord_tbl[i]; prev->disk_ord_tbl[i];
break; break;
} }
failed = imsm_count_failed(super, dev, MAP_0); failed = imsm_count_failed(super, dev, MAP_0);
map_state = imsm_check_degraded(super, dev, failed, MAP_0); map_state = imsm_check_degraded(super, dev, failed, MAP_0);
} }
dev->vol.migr_state = 0; dev->vol.migr_state = 0;
set_migr_type(dev, 0); set_migr_type(dev, 0);
dev->vol.curr_migr_unit = 0; set_vol_curr_migr_unit(dev, 0);
map->map_state = map_state; map->map_state = map_state;
} }
static int parse_raid_devices(struct intel_super *super) static int parse_raid_devices(struct intel_super *super)
{ {
int i; int i;
struct imsm_dev *dev_new; struct imsm_dev *dev_new;
size_t len, len_migr; size_t len, len_migr;
size_t max_len = 0; size_t max_len = 0;
size_t space_needed = 0; size_t space_needed = 0;
skipping to change at line 4418 skipping to change at line 4551
if (err) if (err)
return err; return err;
err = parse_raid_devices(super); err = parse_raid_devices(super);
if (err) if (err)
return err; return err;
err = load_bbm_log(super); err = load_bbm_log(super);
clear_hi(super); clear_hi(super);
return err; return err;
} }
static void __free_imsm_disk(struct dl *d) static void __free_imsm_disk(struct dl *d, int do_close)
{ {
if (d->fd >= 0) if (do_close)
close(d->fd); close_fd(&d->fd);
if (d->devname) if (d->devname)
free(d->devname); free(d->devname);
if (d->e) if (d->e)
free(d->e); free(d->e);
free(d); free(d);
} }
static void free_imsm_disks(struct intel_super *super) static void free_imsm_disks(struct intel_super *super)
{ {
struct dl *d; struct dl *d;
while (super->disks) { while (super->disks) {
d = super->disks; d = super->disks;
super->disks = d->next; super->disks = d->next;
__free_imsm_disk(d); __free_imsm_disk(d, 1);
} }
while (super->disk_mgmt_list) { while (super->disk_mgmt_list) {
d = super->disk_mgmt_list; d = super->disk_mgmt_list;
super->disk_mgmt_list = d->next; super->disk_mgmt_list = d->next;
__free_imsm_disk(d); __free_imsm_disk(d, 1);
} }
while (super->missing) { while (super->missing) {
d = super->missing; d = super->missing;
super->missing = d->next; super->missing = d->next;
__free_imsm_disk(d); __free_imsm_disk(d, 1);
} }
} }
/* free all the pieces hanging off of a super pointer */ /* free all the pieces hanging off of a super pointer */
static void __free_imsm(struct intel_super *super, int free_disks) static void __free_imsm(struct intel_super *super, int free_disks)
{ {
struct intel_hba *elem, *next; struct intel_hba *elem, *next;
if (super->buf) { if (super->buf) {
skipping to change at line 4526 skipping to change at line 4659
} }
/* /*
* find and allocate hba and OROM/EFI based on valid fd of RAID component device * find and allocate hba and OROM/EFI based on valid fd of RAID component device
*/ */
static int find_intel_hba_capability(int fd, struct intel_super *super, char *de vname) static int find_intel_hba_capability(int fd, struct intel_super *super, char *de vname)
{ {
struct sys_dev *hba_name; struct sys_dev *hba_name;
int rv = 0; int rv = 0;
if (fd >= 0 && test_partition(fd)) { if (is_fd_valid(fd) && test_partition(fd)) {
pr_err("imsm: %s is a partition, cannot be used in IMSM\n", pr_err("imsm: %s is a partition, cannot be used in IMSM\n",
devname); devname);
return 1; return 1;
} }
if (fd < 0 || check_env("IMSM_NO_PLATFORM")) { if (!is_fd_valid(fd) || check_env("IMSM_NO_PLATFORM")) {
super->orom = NULL; super->orom = NULL;
super->hba = NULL; super->hba = NULL;
return 0; return 0;
} }
hba_name = find_disk_attached_hba(fd, NULL); hba_name = find_disk_attached_hba(fd, NULL);
if (!hba_name) { if (!hba_name) {
if (devname) if (devname)
pr_err("%s is not attached to Intel(R) RAID controller.\n ", pr_err("%s is not attached to Intel(R) RAID controller.\n ",
devname); devname);
return 1; return 1;
skipping to change at line 4940 skipping to change at line 5073
static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
char *devname, struct md_list *devlist, char *devname, struct md_list *devlist,
int keep_fd) int keep_fd)
{ {
struct intel_super *super_list = NULL; struct intel_super *super_list = NULL;
struct intel_super *super = NULL; struct intel_super *super = NULL;
int err = 0; int err = 0;
int i = 0; int i = 0;
if (fd >= 0) if (is_fd_valid(fd))
/* 'fd' is an opened container */ /* 'fd' is an opened container */
err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd); err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd);
else else
/* get super block from devlist devices */ /* get super block from devlist devices */
err = get_devlist_super_block(devlist, &super_list, &i, keep_fd); err = get_devlist_super_block(devlist, &super_list, &i, keep_fd);
if (err) if (err)
goto error; goto error;
/* all mpbs enter, maybe one leaves */ /* all mpbs enter, maybe one leaves */
super = imsm_thunderdome(&super_list, i); super = imsm_thunderdome(&super_list, i);
if (!super) { if (!super) {
skipping to change at line 4962 skipping to change at line 5095
goto error; goto error;
} }
if (find_missing(super) != 0) { if (find_missing(super) != 0) {
free_imsm(super); free_imsm(super);
err = 2; err = 2;
goto error; goto error;
} }
/* load migration record */ /* load migration record */
err = load_imsm_migr_rec(super, NULL); err = load_imsm_migr_rec(super);
if (err == -1) { if (err == -1) {
/* migration is in progress, /* migration is in progress,
* but migr_rec cannot be loaded, * but migr_rec cannot be loaded,
*/ */
err = 4; err = 4;
goto error; goto error;
} }
/* Check migration compatibility */ /* Check migration compatibility */
if (err == 0 && check_mpb_migr_compatibility(super) != 0) { if (err == 0 && check_mpb_migr_compatibility(super) != 0) {
skipping to change at line 4997 skipping to change at line 5130
struct intel_super *s = super_list; struct intel_super *s = super_list;
super_list = super_list->next; super_list = super_list->next;
free_imsm(s); free_imsm(s);
} }
if (err) if (err)
return err; return err;
*sbp = super; *sbp = super;
if (fd >= 0) if (is_fd_valid(fd))
strcpy(st->container_devnm, fd2devnm(fd)); strcpy(st->container_devnm, fd2devnm(fd));
else else
st->container_devnm[0] = 0; st->container_devnm[0] = 0;
if (err == 0 && st->ss == NULL) { if (err == 0 && st->ss == NULL) {
st->ss = &super_imsm; st->ss = &super_imsm;
st->minor_version = 0; st->minor_version = 0;
st->max_devs = IMSM_MAX_DEVICES; st->max_devs = IMSM_MAX_DEVICES;
} }
return 0; return 0;
} }
skipping to change at line 5023 skipping to change at line 5156
struct md_list *tmpdev; struct md_list *tmpdev;
int err = 0; int err = 0;
int i = 0; int i = 0;
for (i = 0, tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) { for (i = 0, tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
if (tmpdev->used != 1) if (tmpdev->used != 1)
continue; continue;
if (tmpdev->container == 1) { if (tmpdev->container == 1) {
int lmax = 0; int lmax = 0;
int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL); int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL);
if (fd < 0) { if (!is_fd_valid(fd)) {
pr_err("cannot open device %s: %s\n", pr_err("cannot open device %s: %s\n",
tmpdev->devname, strerror(errno)); tmpdev->devname, strerror(errno));
err = 8; err = 8;
goto error; goto error;
} }
err = get_sra_super_block(fd, super_list, err = get_sra_super_block(fd, super_list,
tmpdev->devname, &lmax, tmpdev->devname, &lmax,
keep_fd); keep_fd);
i += lmax; i += lmax;
close(fd); close(fd);
skipping to change at line 5075 skipping to change at line 5208
int retry; int retry;
s = alloc_super(); s = alloc_super();
if (!s) { if (!s) {
err = 1; err = 1;
goto error; goto error;
} }
sprintf(nm, "%d:%d", major, minor); sprintf(nm, "%d:%d", major, minor);
dfd = dev_open(nm, O_RDWR); dfd = dev_open(nm, O_RDWR);
if (dfd < 0) { if (!is_fd_valid(dfd)) {
err = 2; err = 2;
goto error; goto error;
} }
get_dev_sector_size(dfd, NULL, &s->sector_size); if (!get_dev_sector_size(dfd, NULL, &s->sector_size)) {
err = 2;
goto error;
}
find_intel_hba_capability(dfd, s, devname); find_intel_hba_capability(dfd, s, devname);
err = load_and_parse_mpb(dfd, s, NULL, keep_fd); err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
/* retry the load if we might have raced against mdmon */ /* retry the load if we might have raced against mdmon */
if (err == 3 && devnm && mdmon_running(devnm)) if (err == 3 && devnm && mdmon_running(devnm))
for (retry = 0; retry < 3; retry++) { for (retry = 0; retry < 3; retry++) {
usleep(3000); usleep(3000);
err = load_and_parse_mpb(dfd, s, NULL, keep_fd); err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
if (err != 3) if (err != 3)
break; break;
} }
error: error:
if (!err) { if (!err) {
s->next = *super_list; s->next = *super_list;
*super_list = s; *super_list = s;
} else { } else {
if (s) if (s)
free_imsm(s); free_imsm(s);
if (dfd >= 0) close_fd(&dfd);
close(dfd);
} }
if (dfd >= 0 && !keep_fd) if (!keep_fd)
close(dfd); close_fd(&dfd);
return err; return err;
} }
static int static int
get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd) get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd)
{ {
struct mdinfo *sra; struct mdinfo *sra;
char *devnm; char *devnm;
struct mdinfo *sd; struct mdinfo *sd;
skipping to change at line 5159 skipping to change at line 5294
int rv; int rv;
int retry; int retry;
if (test_partition(fd)) if (test_partition(fd))
/* IMSM not allowed on partitions */ /* IMSM not allowed on partitions */
return 1; return 1;
free_super_imsm(st); free_super_imsm(st);
super = alloc_super(); super = alloc_super();
get_dev_sector_size(fd, NULL, &super->sector_size);
if (!super) if (!super)
return 1; return 1;
if (!get_dev_sector_size(fd, NULL, &super->sector_size)) {
free_imsm(super);
return 1;
}
/* Load hba and capabilities if they exist. /* Load hba and capabilities if they exist.
* But do not preclude loading metadata in case capabilities or hba are * But do not preclude loading metadata in case capabilities or hba are
* non-compliant and ignore_hw_compat is set. * non-compliant and ignore_hw_compat is set.
*/ */
rv = find_intel_hba_capability(fd, super, devname); rv = find_intel_hba_capability(fd, super, devname);
/* no orom/efi or non-intel hba of the disk */ /* no orom/efi or non-intel hba of the disk */
if (rv != 0 && st->ignore_hw_compat == 0) { if (rv != 0 && st->ignore_hw_compat == 0) {
if (devname) if (devname)
pr_err("No OROM/EFI properties for %s\n", devname); pr_err("No OROM/EFI properties for %s\n", devname);
free_imsm(super); free_imsm(super);
skipping to change at line 5211 skipping to change at line 5350
} }
st->sb = super; st->sb = super;
if (st->ss == NULL) { if (st->ss == NULL) {
st->ss = &super_imsm; st->ss = &super_imsm;
st->minor_version = 0; st->minor_version = 0;
st->max_devs = IMSM_MAX_DEVICES; st->max_devs = IMSM_MAX_DEVICES;
} }
/* load migration record */ /* load migration record */
if (load_imsm_migr_rec(super, NULL) == 0) { if (load_imsm_migr_rec(super) == 0) {
/* Check for unsupported migration features */ /* Check for unsupported migration features */
if (check_mpb_migr_compatibility(super) != 0) { if (check_mpb_migr_compatibility(super) != 0) {
pr_err("Unsupported migration detected"); pr_err("Unsupported migration detected");
if (devname) if (devname)
fprintf(stderr, " on %s\n", devname); fprintf(stderr, " on %s\n", devname);
else else
fprintf(stderr, " (IMSM).\n"); fprintf(stderr, " (IMSM).\n");
return 3; return 3;
} }
} }
skipping to change at line 5345 skipping to change at line 5484
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
struct intel_dev *dv; struct intel_dev *dv;
struct imsm_dev *dev; struct imsm_dev *dev;
struct imsm_vol *vol; struct imsm_vol *vol;
struct imsm_map *map; struct imsm_map *map;
int idx = mpb->num_raid_devs; int idx = mpb->num_raid_devs;
int i; int i;
int namelen; int namelen;
unsigned long long array_blocks; unsigned long long array_blocks;
size_t size_old, size_new; size_t size_old, size_new;
unsigned long long num_data_stripes;
unsigned int data_disks; unsigned int data_disks;
unsigned long long size_per_member; unsigned long long size_per_member;
if (super->orom && mpb->num_raid_devs >= super->orom->vpa) { if (super->orom && mpb->num_raid_devs >= super->orom->vpa) {
pr_err("This imsm-container already has the maximum of %d volumes \n", super->orom->vpa); pr_err("This imsm-container already has the maximum of %d volumes \n", super->orom->vpa);
return 0; return 0;
} }
/* ensure the mpb is large enough for the new data */ /* ensure the mpb is large enough for the new data */
size_old = __le32_to_cpu(mpb->mpb_size); size_old = __le32_to_cpu(mpb->mpb_size);
skipping to change at line 5442 skipping to change at line 5580
info->raid_disks); info->raid_disks);
array_blocks = round_size_to_mb(array_blocks, data_disks); array_blocks = round_size_to_mb(array_blocks, data_disks);
size_per_member = array_blocks / data_disks; size_per_member = array_blocks / data_disks;
set_imsm_dev_size(dev, array_blocks); set_imsm_dev_size(dev, array_blocks);
dev->status = (DEV_READ_COALESCING | DEV_WRITE_COALESCING); dev->status = (DEV_READ_COALESCING | DEV_WRITE_COALESCING);
vol = &dev->vol; vol = &dev->vol;
vol->migr_state = 0; vol->migr_state = 0;
set_migr_type(dev, MIGR_INIT); set_migr_type(dev, MIGR_INIT);
vol->dirty = !info->state; vol->dirty = !info->state;
vol->curr_migr_unit = 0; set_vol_curr_migr_unit(dev, 0);
map = get_imsm_map(dev, MAP_0); map = get_imsm_map(dev, MAP_0);
set_pba_of_lba0(map, super->create_offset); set_pba_of_lba0(map, super->create_offset);
map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info)); map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
map->failed_disk_num = ~0; map->failed_disk_num = ~0;
if (info->level > 0) if (info->level > 0)
map->map_state = (info->state ? IMSM_T_STATE_NORMAL map->map_state = (info->state ? IMSM_T_STATE_NORMAL
: IMSM_T_STATE_UNINITIALIZED); : IMSM_T_STATE_UNINITIALIZED);
else else
map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED : map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED :
IMSM_T_STATE_NORMAL; IMSM_T_STATE_NORMAL;
map->ddf = 1; map->ddf = 1;
if (info->level == 1 && info->raid_disks > 2) { if (info->level == 1 && info->raid_disks > 2) {
free(dev); free(dev);
free(dv); free(dv);
pr_err("imsm does not support more than 2 disksin a raid1 volume\ n"); pr_err("imsm does not support more than 2 disksin a raid1 volume\ n");
return 0; return 0;
} }
map->raid_level = info->level; map->raid_level = info->level;
if (info->level == 10) { if (info->level == 10)
map->raid_level = 1; map->raid_level = 1;
map->num_domains = info->raid_disks / 2; set_num_domains(map);
} else if (info->level == 1)
map->num_domains = info->raid_disks;
else
map->num_domains = 1;
/* info->size is only int so use the 'size' parameter instead */
num_data_stripes = size_per_member / info_to_blocks_per_strip(info);
num_data_stripes /= map->num_domains;
set_num_data_stripes(map, num_data_stripes);
size_per_member += NUM_BLOCKS_DIRTY_STRIPE_REGION; size_per_member += NUM_BLOCKS_DIRTY_STRIPE_REGION;
set_blocks_per_member(map, info_to_blocks_per_member(info, set_blocks_per_member(map, info_to_blocks_per_member(info,
size_per_member / size_per_member /
BLOCKS_PER_KB)); BLOCKS_PER_KB));
map->num_members = info->raid_disks; map->num_members = info->raid_disks;
update_num_data_stripes(map, array_blocks);
for (i = 0; i < map->num_members; i++) { for (i = 0; i < map->num_members; i++) {
/* initialized in add_to_super */ /* initialized in add_to_super */
set_imsm_ord_tbl_ent(map, i, IMSM_ORD_REBUILD); set_imsm_ord_tbl_ent(map, i, IMSM_ORD_REBUILD);
} }
mpb->num_raid_devs++; mpb->num_raid_devs++;
mpb->num_raid_devs_created++; mpb->num_raid_devs_created++;
dev->my_vol_raid_dev_num = mpb->num_raid_devs_created; dev->my_vol_raid_dev_num = mpb->num_raid_devs_created;
if (s->consistency_policy <= CONSISTENCY_POLICY_RESYNC) { if (s->consistency_policy <= CONSISTENCY_POLICY_RESYNC) {
dev->rwh_policy = RWH_MULTIPLE_OFF; dev->rwh_policy = RWH_MULTIPLE_OFF;
skipping to change at line 5585 skipping to change at line 5715
version += strlen(MPB_SIGNATURE); version += strlen(MPB_SIGNATURE);
strcpy(version, MPB_VERSION_RAID0); strcpy(version, MPB_VERSION_RAID0);
return 1; return 1;
} }
static int drive_validate_sector_size(struct intel_super *super, struct dl *dl) static int drive_validate_sector_size(struct intel_super *super, struct dl *dl)
{ {
unsigned int member_sector_size; unsigned int member_sector_size;
if (dl->fd < 0) { if (!is_fd_valid(dl->fd)) {
pr_err("Invalid file descriptor for %s\n", dl->devname); pr_err("Invalid file descriptor for %s\n", dl->devname);
return 0; return 0;
} }
if (!get_dev_sector_size(dl->fd, dl->devname, &member_sector_size)) if (!get_dev_sector_size(dl->fd, dl->devname, &member_sector_size))
return 0; return 0;
if (member_sector_size != super->sector_size) if (member_sector_size != super->sector_size)
return 0; return 0;
return 1; return 1;
} }
skipping to change at line 5617 skipping to change at line 5747
dev = get_imsm_dev(super, super->current_vol); dev = get_imsm_dev(super, super->current_vol);
map = get_imsm_map(dev, MAP_0); map = get_imsm_map(dev, MAP_0);
if (! (dk->state & (1<<MD_DISK_SYNC))) { if (! (dk->state & (1<<MD_DISK_SYNC))) {
pr_err("%s: Cannot add spare devices to IMSM volume\n", pr_err("%s: Cannot add spare devices to IMSM volume\n",
devname); devname);
return 1; return 1;
} }
if (fd == -1) { if (!is_fd_valid(fd)) {
/* we're doing autolayout so grab the pre-marked (in /* we're doing autolayout so grab the pre-marked (in
* validate_geometry) raid_disk * validate_geometry) raid_disk
*/ */
for (dl = super->disks; dl; dl = dl->next) for (dl = super->disks; dl; dl = dl->next)
if (dl->raiddisk == dk->raid_disk) if (dl->raiddisk == dk->raid_disk)
break; break;
} else { } else {
for (dl = super->disks; dl ; dl = dl->next) for (dl = super->disks; dl ; dl = dl->next)
if (dl->major == dk->major && if (dl->major == dk->major &&
dl->minor == dk->minor) dl->minor == dk->minor)
skipping to change at line 5719 skipping to change at line 5849
if (!_dev || !_disk) { if (!_dev || !_disk) {
pr_err("BUG mpb setup error\n"); pr_err("BUG mpb setup error\n");
return 1; return 1;
} }
*_dev = *dev; *_dev = *dev;
*_disk = dl->disk; *_disk = dl->disk;
sum = random32(); sum = random32();
sum += __gen_imsm_checksum(mpb); sum += __gen_imsm_checksum(mpb);
mpb->family_num = __cpu_to_le32(sum); mpb->family_num = __cpu_to_le32(sum);
mpb->orig_family_num = mpb->family_num; mpb->orig_family_num = mpb->family_num;
mpb->creation_time = __cpu_to_le64((__u64)time(NULL));
} }
super->current_disk = dl; super->current_disk = dl;
return 0; return 0;
} }
/* mark_spare() /* mark_spare()
* Function marks disk as spare and restores disk serial * Function marks disk as spare and restores disk serial
* in case it was previously marked as failed by takeover operation * in case it was previously marked as failed by takeover operation
* reruns: * reruns:
* -1 : critical error * -1 : critical error
skipping to change at line 5741 skipping to change at line 5872
*/ */
int mark_spare(struct dl *disk) int mark_spare(struct dl *disk)
{ {
__u8 serial[MAX_RAID_SERIAL_LEN]; __u8 serial[MAX_RAID_SERIAL_LEN];
int ret_val = -1; int ret_val = -1;
if (!disk) if (!disk)
return ret_val; return ret_val;
ret_val = 0; ret_val = 0;
if (!imsm_read_serial(disk->fd, NULL, serial)) { if (!imsm_read_serial(disk->fd, NULL, serial, MAX_RAID_SERIAL_LEN)) {
/* Restore disk serial number, because takeover marks disk /* Restore disk serial number, because takeover marks disk
* as failed and adds to serial ':0' before it becomes * as failed and adds to serial ':0' before it becomes
* a spare disk. * a spare disk.
*/ */
serialcpy(disk->serial, serial); serialcpy(disk->serial, serial);
serialcpy(disk->disk.serial, serial); serialcpy(disk->disk.serial, serial);
ret_val = 1; ret_val = 1;
} }
disk->disk.status = SPARE_DISK; disk->disk.status = SPARE_DISK;
disk->index = -1; disk->index = -1;
return ret_val; return ret_val;
} }
static int write_super_imsm_spare(struct intel_super *super, struct dl *d);
static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, 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) unsigned long long data_offset)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
struct dl *dd; struct dl *dd;
unsigned long long size; unsigned long long size;
unsigned int member_sector_size; unsigned int member_sector_size;
__u32 id; __u32 id;
int rv; int rv;
skipping to change at line 5792 skipping to change at line 5925
return add_to_super_imsm_volume(st, dk, fd, devname); return add_to_super_imsm_volume(st, dk, fd, devname);
fstat(fd, &stb); fstat(fd, &stb);
dd = xcalloc(sizeof(*dd), 1); dd = xcalloc(sizeof(*dd), 1);
dd->major = major(stb.st_rdev); dd->major = major(stb.st_rdev);
dd->minor = minor(stb.st_rdev); dd->minor = minor(stb.st_rdev);
dd->devname = devname ? xstrdup(devname) : NULL; dd->devname = devname ? xstrdup(devname) : NULL;
dd->fd = fd; dd->fd = fd;
dd->e = NULL; dd->e = NULL;
dd->action = DISK_ADD; dd->action = DISK_ADD;
rv = imsm_read_serial(fd, devname, dd->serial); rv = imsm_read_serial(fd, devname, dd->serial, MAX_RAID_SERIAL_LEN);
if (rv) { if (rv) {
pr_err("failed to retrieve scsi serial, aborting\n"); pr_err("failed to retrieve scsi serial, aborting\n");
if (dd->devname) __free_imsm_disk(dd, 0);
free(dd->devname);
free(dd);
abort(); abort();
} }
if (super->hba && ((super->hba->type == SYS_DEV_NVME) || if (super->hba && ((super->hba->type == SYS_DEV_NVME) ||
(super->hba->type == SYS_DEV_VMD))) { (super->hba->type == SYS_DEV_VMD))) {
int i; int i;
char *devpath = diskfd_to_devpath(fd); char cntrl_path[PATH_MAX];
char controller_path[PATH_MAX]; char *cntrl_name;
char pci_dev_path[PATH_MAX];
if (!devpath) {
pr_err("failed to get devpath, aborting\n"); if (!diskfd_to_devpath(fd, 2, pci_dev_path) ||
if (dd->devname) !diskfd_to_devpath(fd, 1, cntrl_path)) {
free(dd->devname); pr_err("failed to get dev paths, aborting\n");
free(dd); __free_imsm_disk(dd, 0);
return 1; return 1;
} }
snprintf(controller_path, PATH_MAX-1, "%s/device", devpath); cntrl_name = basename(cntrl_path);
free(devpath); if (is_multipath_nvme(fd))
pr_err("%s controller supports Multi-Path I/O, Intel (R)
VROC does not support multipathing\n",
cntrl_name);
if (devpath_to_vendor(controller_path) == 0x8086) { if (devpath_to_vendor(pci_dev_path) == 0x8086) {
/* /*
* If Intel's NVMe drive has serial ended with * If Intel's NVMe drive has serial ended with
* "-A","-B","-1" or "-2" it means that this is "x8" * "-A","-B","-1" or "-2" it means that this is "x8"
* device (double drive on single PCIe card). * device (double drive on single PCIe card).
* User should be warned about potential data loss. * User should be warned about potential data loss.
*/ */
for (i = MAX_RAID_SERIAL_LEN-1; i > 0; i--) { for (i = MAX_RAID_SERIAL_LEN-1; i > 0; i--) {
/* Skip empty character at the end */ /* Skip empty character at the end */
if (dd->serial[i] == 0) if (dd->serial[i] == 0)
continue; continue;
skipping to change at line 5844 skipping to change at line 5978
pr_err("\tThe action you are about to tak e may put your data at risk.\n" pr_err("\tThe action you are about to tak e may put your data at risk.\n"
"\tPlease note that x8 devices ma y consist of two separate x4 devices " "\tPlease note that x8 devices ma y consist of two separate x4 devices "
"located on a single PCIe port.\n " "located on a single PCIe port.\n "
"\tRAID 0 is the only supported c onfiguration for this type of x8 device.\n"); "\tRAID 0 is the only supported c onfiguration for this type of x8 device.\n");
break; break;
} }
} else if (super->hba->type == SYS_DEV_VMD && super->orom && } else if (super->hba->type == SYS_DEV_VMD && super->orom &&
!imsm_orom_has_tpv_support(super->orom)) { !imsm_orom_has_tpv_support(super->orom)) {
pr_err("\tPlatform configuration does not support non-Int el NVMe drives.\n" pr_err("\tPlatform configuration does not support non-Int el NVMe drives.\n"
"\tPlease refer to Intel(R) RSTe/VROC user guide.\ n"); "\tPlease refer to Intel(R) RSTe/VROC user guide.\ n");
free(dd->devname); __free_imsm_disk(dd, 0);
free(dd);
return 1; return 1;
} }
} }
get_dev_size(fd, NULL, &size); get_dev_size(fd, NULL, &size);
get_dev_sector_size(fd, NULL, &member_sector_size); if (!get_dev_sector_size(fd, NULL, &member_sector_size)) {
__free_imsm_disk(dd, 0);
return 1;
}
if (super->sector_size == 0) { if (super->sector_size == 0) {
/* this a first device, so sector_size is not set yet */ /* this a first device, so sector_size is not set yet */
super->sector_size = member_sector_size; super->sector_size = member_sector_size;
} }
/* clear migr_rec when adding disk to container */ /* clear migr_rec when adding disk to container */
memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE); memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE);
if (lseek64(fd, size - MIGR_REC_SECTOR_POSITION*member_sector_size, if (lseek64(fd, size - MIGR_REC_SECTOR_POSITION*member_sector_size,
SEEK_SET) >= 0) { SEEK_SET) >= 0) {
skipping to change at line 5885 skipping to change at line 6021
mark_spare(dd); mark_spare(dd);
if (sysfs_disk_to_scsi_id(fd, &id) == 0) if (sysfs_disk_to_scsi_id(fd, &id) == 0)
dd->disk.scsi_id = __cpu_to_le32(id); dd->disk.scsi_id = __cpu_to_le32(id);
else else
dd->disk.scsi_id = __cpu_to_le32(0); dd->disk.scsi_id = __cpu_to_le32(0);
if (st->update_tail) { if (st->update_tail) {
dd->next = super->disk_mgmt_list; dd->next = super->disk_mgmt_list;
super->disk_mgmt_list = dd; super->disk_mgmt_list = dd;
} else { } else {
/* this is called outside of mdmon
* write initial spare metadata
* mdmon will overwrite it.
*/
dd->next = super->disks; dd->next = super->disks;
super->disks = dd; super->disks = dd;
super->updates_pending++; write_super_imsm_spare(super, dd);
} }
return 0; return 0;
} }
static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk) static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
struct dl *dd; struct dl *dd;
skipping to change at line 5926 skipping to change at line 6066
return 0; return 0;
} }
static int store_imsm_mpb(int fd, struct imsm_super *mpb); static int store_imsm_mpb(int fd, struct imsm_super *mpb);
static union { static union {
char buf[MAX_SECTOR_SIZE]; char buf[MAX_SECTOR_SIZE];
struct imsm_super anchor; struct imsm_super anchor;
} spare_record __attribute__ ((aligned(MAX_SECTOR_SIZE))); } spare_record __attribute__ ((aligned(MAX_SECTOR_SIZE)));
/* spare records have their own family number and do not have any defined raid static int write_super_imsm_spare(struct intel_super *super, struct dl *d)
* devices
*/
static int write_super_imsm_spares(struct intel_super *super, int doclose)
{ {
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
struct imsm_super *spare = &spare_record.anchor; struct imsm_super *spare = &spare_record.anchor;
__u32 sum; __u32 sum;
struct dl *d;
if (d->index != -1)
return 1;
spare->mpb_size = __cpu_to_le32(sizeof(struct imsm_super)); spare->mpb_size = __cpu_to_le32(sizeof(struct imsm_super));
spare->generation_num = __cpu_to_le32(1UL); spare->generation_num = __cpu_to_le32(1UL);
spare->attributes = MPB_ATTRIB_CHECKSUM_VERIFY; spare->attributes = MPB_ATTRIB_CHECKSUM_VERIFY;
spare->num_disks = 1; spare->num_disks = 1;
spare->num_raid_devs = 0; spare->num_raid_devs = 0;
spare->cache_size = mpb->cache_size; spare->cache_size = mpb->cache_size;
spare->pwr_cycle_count = __cpu_to_le32(1); spare->pwr_cycle_count = __cpu_to_le32(1);
snprintf((char *) spare->sig, MAX_SIGNATURE_LENGTH, snprintf((char *) spare->sig, MAX_SIGNATURE_LENGTH,
MPB_SIGNATURE MPB_VERSION_RAID0); MPB_SIGNATURE MPB_VERSION_RAID0);
spare->disk[0] = d->disk;
if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
spare->attributes |= MPB_ATTRIB_2TB_DISK;
if (super->sector_size == 4096)
convert_to_4k_imsm_disk(&spare->disk[0]);
sum = __gen_imsm_checksum(spare);
spare->family_num = __cpu_to_le32(sum);
spare->orig_family_num = 0;
sum = __gen_imsm_checksum(spare);
spare->check_sum = __cpu_to_le32(sum);
if (store_imsm_mpb(d->fd, spare)) {
pr_err("failed for device %d:%d %s\n",
d->major, d->minor, strerror(errno));
return 1;
}
return 0;
}
/* spare records have their own family number and do not have any defined raid
* devices
*/
static int write_super_imsm_spares(struct intel_super *super, int doclose)
{
struct dl *d;
for (d = super->disks; d; d = d->next) { for (d = super->disks; d; d = d->next) {
if (d->index != -1) if (d->index != -1)
continue; continue;
spare->disk[0] = d->disk; if (write_super_imsm_spare(super, d))
if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
spare->attributes |= MPB_ATTRIB_2TB_DISK;
if (super->sector_size == 4096)
convert_to_4k_imsm_disk(&spare->disk[0]);
sum = __gen_imsm_checksum(spare);
spare->family_num = __cpu_to_le32(sum);
spare->orig_family_num = 0;
sum = __gen_imsm_checksum(spare);
spare->check_sum = __cpu_to_le32(sum);
if (store_imsm_mpb(d->fd, spare)) {
pr_err("failed for device %d:%d %s\n",
d->major, d->minor, strerror(errno));
return 1; return 1;
}
if (doclose) { if (doclose)
close(d->fd); close_fd(&d->fd);
d->fd = -1;
}
} }
return 0; return 0;
} }
static int write_super_imsm(struct supertype *st, int doclose) static int write_super_imsm(struct supertype *st, int doclose)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
unsigned int sector_size = super->sector_size; unsigned int sector_size = super->sector_size;
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
skipping to change at line 6086 skipping to change at line 6236
perror("Write migr_rec failed"); perror("Write migr_rec failed");
} }
} }
if (store_imsm_mpb(d->fd, mpb)) if (store_imsm_mpb(d->fd, mpb))
fprintf(stderr, fprintf(stderr,
"failed for device %d:%d (fd: %d)%s\n", "failed for device %d:%d (fd: %d)%s\n",
d->major, d->minor, d->major, d->minor,
d->fd, strerror(errno)); d->fd, strerror(errno));
if (doclose) { if (doclose)
close(d->fd); close_fd(&d->fd);
d->fd = -1;
}
} }
if (spares) if (spares)
return write_super_imsm_spares(super, doclose); return write_super_imsm_spares(super, doclose);
return 0; return 0;
} }
static int create_array(struct supertype *st, int dev_idx) static int create_array(struct supertype *st, int dev_idx)
{ {
skipping to change at line 6343 skipping to change at line 6491
} }
} }
if (ret == 1) { if (ret == 1) {
struct imsm_map *map = get_imsm_map(dev, MAP_X); struct imsm_map *map = get_imsm_map(dev, MAP_X);
if (map->map_state == IMSM_T_STATE_UNINITIALIZED || if (map->map_state == IMSM_T_STATE_UNINITIALIZED ||
(map->map_state == IMSM_T_STATE_NORMAL && (map->map_state == IMSM_T_STATE_NORMAL &&
!(dev->vol.dirty & RAIDVOL_DIRTY)) || !(dev->vol.dirty & RAIDVOL_DIRTY)) ||
(is_rebuilding(dev) && (is_rebuilding(dev) &&
dev->vol.curr_migr_unit == 0 && vol_curr_migr_unit(dev) == 0 &&
get_imsm_disk_idx(dev, disk->disk.raid_disk, MAP_1) != idx)) get_imsm_disk_idx(dev, disk->disk.raid_disk, MAP_1) != idx))
ret = st->ss->write_init_ppl(st, info, d->fd); ret = st->ss->write_init_ppl(st, info, d->fd);
else else
info->mismatch_cnt++; info->mismatch_cnt++;
} else if (ret == 0 && } else if (ret == 0 &&
ppl_hdr->entries_count == 0 && ppl_hdr->entries_count == 0 &&
is_rebuilding(dev) && is_rebuilding(dev) &&
info->resync_start == 0) { info->resync_start == 0) {
/* /*
* The header has no entries - add a single empty entry and * The header has no entries - add a single empty entry and
skipping to change at line 6388 skipping to change at line 6536
continue; continue;
ret = st->ss->write_init_ppl(st, info, d->fd); ret = st->ss->write_init_ppl(st, info, d->fd);
if (ret) if (ret)
break; break;
} }
return ret; return ret;
} }
/*******************************************************************************
* Function: write_init_bitmap_imsm_vol
* Description: Write a bitmap header and prepares the area for the bitma
p.
* Parameters:
* st : supertype information
* vol_idx : the volume index to use
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int write_init_bitmap_imsm_vol(struct supertype *st, int vol_idx)
{
struct intel_super *super = st->sb;
int prev_current_vol = super->current_vol;
struct dl *d;
int ret = 0;
super->current_vol = vol_idx;
for (d = super->disks; d; d = d->next) {
if (d->index < 0 || is_failed(&d->disk))
continue;
ret = st->ss->write_bitmap(st, d->fd, NoUpdate);
if (ret)
break;
}
super->current_vol = prev_current_vol;
return ret;
}
/*******************************************************************************
* Function: write_init_bitmap_imsm_all
* Description: Write a bitmap header and prepares the area for the bitma
p.
* Operation is executed for volumes with CONSISTENCY_POLICY_BITMAP.
* Parameters:
* st : supertype information
* info : info about the volume where the bitmap should be written
* vol_idx : the volume index to use
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int write_init_bitmap_imsm_all(struct supertype *st, struct mdinfo *info,
int vol_idx)
{
int ret = 0;
if (info && (info->consistency_policy == CONSISTENCY_POLICY_BITMAP))
ret = write_init_bitmap_imsm_vol(st, vol_idx);
return ret;
}
static int write_init_super_imsm(struct supertype *st) static int write_init_super_imsm(struct supertype *st)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
int current_vol = super->current_vol; int current_vol = super->current_vol;
int rv = 0; int rv = 0;
struct mdinfo info; struct mdinfo info;
getinfo_super_imsm(st, &info, NULL); getinfo_super_imsm(st, &info, NULL);
/* we are done with current_vol reset it to point st at the container */ /* we are done with current_vol reset it to point st at the container */
skipping to change at line 6411 skipping to change at line 6613
/* queue the recently created array / added disk /* queue the recently created array / added disk
* as a metadata update */ * as a metadata update */
/* determine if we are creating a volume or adding a disk */ /* determine if we are creating a volume or adding a disk */
if (current_vol < 0) { if (current_vol < 0) {
/* in the mgmt (add/remove) disk case we are running /* in the mgmt (add/remove) disk case we are running
* in mdmon context, so don't close fd's * in mdmon context, so don't close fd's
*/ */
rv = mgmt_disk(st); rv = mgmt_disk(st);
} else { } else {
/* adding the second volume to the array */
rv = write_init_ppl_imsm_all(st, &info); rv = write_init_ppl_imsm_all(st, &info);
if (!rv) if (!rv)
rv = write_init_bitmap_imsm_all(st, &info, curren
t_vol);
if (!rv)
rv = create_array(st, current_vol); rv = create_array(st, current_vol);
} }
} else { } else {
struct dl *d; struct dl *d;
for (d = super->disks; d; d = d->next) for (d = super->disks; d; d = d->next)
Kill(d->devname, NULL, 0, -1, 1); Kill(d->devname, NULL, 0, -1, 1);
if (current_vol >= 0) if (current_vol >= 0) {
rv = write_init_ppl_imsm_all(st, &info); rv = write_init_ppl_imsm_all(st, &info);
if (!rv)
rv = write_init_bitmap_imsm_all(st, &info, curren
t_vol);
}
if (!rv) if (!rv)
rv = write_super_imsm(st, 1); rv = write_super_imsm(st, 1);
} }
return rv; return rv;
} }
static int store_super_imsm(struct supertype *st, int fd) static int store_super_imsm(struct supertype *st, int fd)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
skipping to change at line 6442 skipping to change at line 6651
if (!mpb) if (!mpb)
return 1; return 1;
if (super->sector_size == 4096) if (super->sector_size == 4096)
convert_to_4k(super); convert_to_4k(super);
return store_imsm_mpb(fd, mpb); return store_imsm_mpb(fd, mpb);
} }
static int validate_geometry_imsm_container(struct supertype *st, int level, static int validate_geometry_imsm_container(struct supertype *st, int level,
int layout, int raiddisks, int chunk, int raiddisks,
unsigned long long size,
unsigned long long data_offset, unsigned long long data_offset,
char *dev, char *dev,
unsigned long long *freesize, unsigned long long *freesize,
int verbose) int verbose)
{ {
int fd; int fd;
unsigned long long ldsize; unsigned long long ldsize;
struct intel_super *super; struct intel_super *super = NULL;
int rv = 0; int rv = 0;
if (level != LEVEL_CONTAINER) if (level != LEVEL_CONTAINER)
return 0; return 0;
if (!dev) if (!dev)
return 1; return 1;
fd = open(dev, O_RDONLY|O_EXCL, 0); fd = dev_open(dev, O_RDONLY|O_EXCL);
if (fd < 0) { if (!is_fd_valid(fd)) {
if (verbose > 0) pr_vrb("imsm: Cannot open %s: %s\n", dev, strerror(errno));
pr_err("imsm: Cannot open %s: %s\n",
dev, strerror(errno));
return 0;
}
if (!get_dev_size(fd, dev, &ldsize)) {
close(fd);
return 0; return 0;
} }
if (!get_dev_size(fd, dev, &ldsize))
goto exit;
/* capabilities retrieve could be possible /* capabilities retrieve could be possible
* note that there is no fd for the disks in array. * note that there is no fd for the disks in array.
*/ */
super = alloc_super(); super = alloc_super();
if (!super) { if (!super)
close(fd); goto exit;
return 0;
} if (!get_dev_sector_size(fd, NULL, &super->sector_size))
if (!get_dev_sector_size(fd, NULL, &super->sector_size)) { goto exit;
close(fd);
free_imsm(super);
return 0;
}
rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL); rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL);
if (rv != 0) { if (rv != 0) {
#if DEBUG #if DEBUG
char str[256]; char str[256];
fd2devname(fd, str); fd2devname(fd, str);
dprintf("fd: %d %s orom: %p rv: %d raiddisk: %d\n", dprintf("fd: %d %s orom: %p rv: %d raiddisk: %d\n",
fd, str, super->orom, rv, raiddisks); fd, str, super->orom, rv, raiddisks);
#endif #endif
/* no orom/efi or non-intel hba of the disk */ /* no orom/efi or non-intel hba of the disk */
close(fd); rv = 0;
free_imsm(super); goto exit;
return 0;
} }
close(fd);
if (super->orom) { if (super->orom) {
if (raiddisks > super->orom->tds) { if (raiddisks > super->orom->tds) {
if (verbose) if (verbose)
pr_err("%d exceeds maximum number of platform sup ported disks: %d\n", pr_err("%d exceeds maximum number of platform sup ported disks: %d\n",
raiddisks, super->orom->tds); raiddisks, super->orom->tds);
free_imsm(super); goto exit;
return 0;
} }
if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 && if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 &&
(ldsize >> 9) >> 32 > 0) { (ldsize >> 9) >> 32 > 0) {
if (verbose) if (verbose)
pr_err("%s exceeds maximum platform supported siz e\n", dev); pr_err("%s exceeds maximum platform supported siz e\n", dev);
free_imsm(super); goto exit;
return 0;
} }
}
*freesize = avail_size_imsm(st, ldsize >> 9, data_offset); if (super->hba->type == SYS_DEV_VMD ||
free_imsm(super); super->hba->type == SYS_DEV_NVME) {
if (!imsm_is_nvme_namespace_supported(fd, 1)) {
if (verbose)
pr_err("NVMe namespace %s is not supporte
d by IMSM\n",
basename(dev));
goto exit;
}
}
}
if (freesize)
*freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
rv = 1;
exit:
if (super)
free_imsm(super);
close(fd);
return 1; return rv;
} }
static unsigned long long find_size(struct extent *e, int *idx, int num_extents) static unsigned long long find_size(struct extent *e, int *idx, int num_extents)
{ {
const unsigned long long base_start = e[*idx].start; const unsigned long long base_start = e[*idx].start;
unsigned long long end = base_start + e[*idx].size; unsigned long long end = base_start + e[*idx].size;
int i; int i;
if (base_start == end) if (base_start == end)
return 0; return 0;
skipping to change at line 6668 skipping to change at line 6878
int found; int found;
for (memb = mdstat ; memb ; memb = memb->next) { for (memb = mdstat ; memb ; memb = memb->next) {
if (memb->metadata_version && if (memb->metadata_version &&
(strncmp(memb->metadata_version, "external:", 9) == 0) && (strncmp(memb->metadata_version, "external:", 9) == 0) &&
(strcmp(&memb->metadata_version[9], name) == 0) && (strcmp(&memb->metadata_version[9], name) == 0) &&
!is_subarray(memb->metadata_version+9) && !is_subarray(memb->metadata_version+9) &&
memb->members) { memb->members) {
struct dev_member *dev = memb->members; struct dev_member *dev = memb->members;
int fd = -1; int fd = -1;
while(dev && (fd < 0)) { while (dev && !is_fd_valid(fd)) {
char *path = xmalloc(strlen(dev->name) + strlen(" /dev/") + 1); char *path = xmalloc(strlen(dev->name) + strlen(" /dev/") + 1);
num = sprintf(path, "%s%s", "/dev/", dev->name); num = sprintf(path, "%s%s", "/dev/", dev->name);
if (num > 0) if (num > 0)
fd = open(path, O_RDONLY, 0); fd = open(path, O_RDONLY, 0);
if (num <= 0 || fd < 0) { if (num <= 0 || !is_fd_valid(fd)) {
pr_vrb("Cannot open %s: %s\n", pr_vrb("Cannot open %s: %s\n",
dev->name, strerror(errno)); dev->name, strerror(errno));
} }
free(path); free(path);
dev = dev->next; dev = dev->next;
} }
found = 0; found = 0;
if (fd >= 0 && disk_attached_to_hba(fd, hba)) { if (is_fd_valid(fd) && disk_attached_to_hba(fd, hba)) {
struct mdstat_ent *vol; struct mdstat_ent *vol;
for (vol = mdstat ; vol ; vol = vol->next) { for (vol = mdstat ; vol ; vol = vol->next) {
if (vol->active > 0 && if (vol->active > 0 &&
vol->metadata_version && vol->metadata_version &&
is_container_member(vol, memb->devnm) ) { is_container_member(vol, memb->devnm) ) {
found++; found++;
count++; count++;
} }
} }
if (*devlist && (found < dpa)) { if (*devlist && (found < dpa)) {
dv = xcalloc(1, sizeof(*dv)); dv = xcalloc(1, sizeof(*dv));
dv->devname = xmalloc(strlen(memb->devnm) + strlen("/dev/") + 1); dv->devname = xmalloc(strlen(memb->devnm) + strlen("/dev/") + 1);
sprintf(dv->devname, "%s%s", "/dev/", mem b->devnm); sprintf(dv->devname, "%s%s", "/dev/", mem b->devnm);
dv->found = found; dv->found = found;
dv->used = 0; dv->used = 0;
dv->next = *devlist; dv->next = *devlist;
*devlist = dv; *devlist = dv;
} }
} }
if (fd >= 0) close_fd(&fd);
close(fd);
} }
} }
free_mdstat(mdstat); free_mdstat(mdstat);
return count; return count;
} }
#ifdef DEBUG_LOOP #ifdef DEBUG_LOOP
static struct md_list* static struct md_list*
get_loop_devices(void) get_loop_devices(void)
{ {
skipping to change at line 6752 skipping to change at line 6961
* this hba * this hba
*/ */
dir = opendir("/sys/dev/block"); dir = opendir("/sys/dev/block");
for (ent = dir ? readdir(dir) : NULL; ent; ent = readdir(dir)) { for (ent = dir ? readdir(dir) : NULL; ent; ent = readdir(dir)) {
int fd; int fd;
char buf[1024]; char buf[1024];
int major, minor; int major, minor;
char *path = NULL; char *path = NULL;
if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2) if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2)
continue; continue;
path = devt_to_devpath(makedev(major, minor)); path = devt_to_devpath(makedev(major, minor), 1, NULL);
if (!path) if (!path)
continue; continue;
if (!path_attached_to_hba(path, hba_path)) { if (!path_attached_to_hba(path, hba_path)) {
free(path); free(path);
path = NULL; path = NULL;
continue; continue;
} }
free(path); free(path);
path = NULL; path = NULL;
fd = dev_open(ent->d_name, O_RDONLY); fd = dev_open(ent->d_name, O_RDONLY);
if (fd >= 0) { if (is_fd_valid(fd)) {
fd2devname(fd, buf); fd2devname(fd, buf);
close(fd); close(fd);
} else { } else {
pr_err("cannot open device: %s\n", pr_err("cannot open device: %s\n",
ent->d_name); ent->d_name);
continue; continue;
} }
dv = xcalloc(1, sizeof(*dv)); dv = xcalloc(1, sizeof(*dv));
dv->devname = xstrdup(buf); dv->devname = xstrdup(buf);
skipping to change at line 6822 skipping to change at line 7031
int dfd; int dfd;
if (tmpdev->used > 1) if (tmpdev->used > 1)
continue; continue;
tst = dup_super(st); tst = dup_super(st);
if (tst == NULL) { if (tst == NULL) {
pr_vrb("cannot allocate memory for imsm supertype\n"); pr_vrb("cannot allocate memory for imsm supertype\n");
goto err_1; goto err_1;
} }
tmpdev->container = 0; tmpdev->container = 0;
dfd = dev_open(devname, O_RDONLY|O_EXCL); dfd = dev_open(devname, O_RDONLY|O_EXCL);
if (dfd < 0) { if (!is_fd_valid(dfd)) {
dprintf("cannot open device %s: %s\n", dprintf("cannot open device %s: %s\n",
devname, strerror(errno)); devname, strerror(errno));
tmpdev->used = 2; tmpdev->used = 2;
} else if (!fstat_is_blkdev(dfd, devname, &rdev)) { } else if (!fstat_is_blkdev(dfd, devname, &rdev)) {
tmpdev->used = 2; tmpdev->used = 2;
} else if (must_be_container(dfd)) { } else if (must_be_container(dfd)) {
struct supertype *cst; struct supertype *cst;
cst = super_by_fd(dfd, NULL); cst = super_by_fd(dfd, NULL);
if (cst == NULL) { if (cst == NULL) {
dprintf("cannot recognize container type %s\n", dprintf("cannot recognize container type %s\n",
skipping to change at line 6859 skipping to change at line 7068
if (tst->ss->load_super(tst,dfd, NULL)) { if (tst->ss->load_super(tst,dfd, NULL)) {
dprintf("no RAID superblock on %s\n", dprintf("no RAID superblock on %s\n",
devname); devname);
tmpdev->used = 2; tmpdev->used = 2;
} else if (tst->ss->compare_super == NULL) { } else if (tst->ss->compare_super == NULL) {
dprintf("Cannot assemble %s metadata on %s\n", dprintf("Cannot assemble %s metadata on %s\n",
tst->ss->name, devname); tst->ss->name, devname);
tmpdev->used = 2; tmpdev->used = 2;
} }
} }
if (dfd >= 0) close_fd(&dfd);
close(dfd);
if (tmpdev->used == 2 || tmpdev->used == 4) { if (tmpdev->used == 2 || tmpdev->used == 4) {
/* Ignore unrecognised devices during auto-assembly */ /* Ignore unrecognised devices during auto-assembly */
goto loop; goto loop;
} }
else { else {
struct mdinfo info; struct mdinfo info;
tst->ss->getinfo_super(tst, &info, NULL); tst->ss->getinfo_super(tst, &info, NULL);
if (st->minor_version == -1) if (st->minor_version == -1)
st->minor_version = tst->minor_version; st->minor_version = tst->minor_version;
skipping to change at line 6885 skipping to change at line 7094
* an array unless there are no more arrays of * an array unless there are no more arrays of
* this type to be found. It can be included * this type to be found. It can be included
* in an array of this type though. * in an array of this type though.
*/ */
tmpdev->used = 3; tmpdev->used = 3;
goto loop; goto loop;
} }
if (st->ss != tst->ss || if (st->ss != tst->ss ||
st->minor_version != tst->minor_version || st->minor_version != tst->minor_version ||
st->ss->compare_super(st, tst) != 0) { st->ss->compare_super(st, tst, 1) != 0) {
/* Some mismatch. If exactly one array matches th is host, /* Some mismatch. If exactly one array matches th is host,
* we can resolve on that one. * we can resolve on that one.
* Or, if we are auto assembling, we just ignore the second * Or, if we are auto assembling, we just ignore the second
* for now. * for now.
*/ */
dprintf("superblock on %s doesn't match others - assembly aborted\n", dprintf("superblock on %s doesn't match others - assembly aborted\n",
devname); devname);
goto loop; goto loop;
} }
tmpdev->used = 1; tmpdev->used = 1;
skipping to change at line 7137 skipping to change at line 7346
unsigned long long minsize = size; unsigned long long minsize = size;
unsigned long long start_offset = MaxSector; unsigned long long start_offset = MaxSector;
int dcnt = 0; int dcnt = 0;
if (minsize == 0) if (minsize == 0)
minsize = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS; minsize = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
for (dl = super->disks; dl ; dl = dl->next) { for (dl = super->disks; dl ; dl = dl->next) {
int found = 0; int found = 0;
pos = 0; pos = 0;
i = 0; i = 0;
e = get_extents(super, dl); e = get_extents(super, dl, 0);
if (!e) continue; if (!e) continue;
do { do {
unsigned long long esize; unsigned long long esize;
esize = e[i].start - pos; esize = e[i].start - pos;
if (esize >= minsize) if (esize >= minsize)
found = 1; found = 1;
if (found && start_offset == MaxSector) { if (found && start_offset == MaxSector) {
start_offset = pos; start_offset = pos;
break; break;
} else if (found && pos != start_offset) { } else if (found && pos != start_offset) {
skipping to change at line 7195 skipping to change at line 7404
pr_err("%s is a spare and a volume is already defined for this co ntainer\n", dev); pr_err("%s is a spare and a volume is already defined for this co ntainer\n", dev);
pr_err("The option-rom requires all member disks to be a member o f all volumes\n"); pr_err("The option-rom requires all member disks to be a member o f all volumes\n");
return 0; return 0;
} else if (super->orom && mpb->num_raid_devs > 0 && } else if (super->orom && mpb->num_raid_devs > 0 &&
mpb->num_disks != raiddisks) { mpb->num_disks != raiddisks) {
pr_err("The option-rom requires all member disks to be a member o f all volumes\n"); pr_err("The option-rom requires all member disks to be a member o f all volumes\n");
return 0; return 0;
} }
/* retrieve the largest free space block */ /* retrieve the largest free space block */
e = get_extents(super, dl); e = get_extents(super, dl, 0);
maxsize = 0; maxsize = 0;
i = 0; i = 0;
if (e) { if (e) {
do { do {
unsigned long long esize; unsigned long long esize;
esize = e[i].start - pos; esize = e[i].start - pos;
if (esize >= maxsize) if (esize >= maxsize)
maxsize = esize; maxsize = esize;
pos = e[i].start + e[i].size; pos = e[i].start + e[i].size;
skipping to change at line 7231 skipping to change at line 7440
} }
/* count total number of extents for merge */ /* count total number of extents for merge */
i = 0; i = 0;
for (dl = super->disks; dl; dl = dl->next) for (dl = super->disks; dl; dl = dl->next)
if (dl->e) if (dl->e)
i += dl->extent_cnt; i += dl->extent_cnt;
maxsize = merge_extents(super, i); maxsize = merge_extents(super, i);
if (!check_env("IMSM_NO_PLATFORM") && if (mpb->num_raid_devs > 0 && size && size != maxsize)
mpb->num_raid_devs > 0 && size && size != maxsize) { pr_err("attempting to create a second volume with size less then
pr_err("attempting to create a second volume with size less then remaining space.\n");
remaining space. Aborting...\n");
return 0;
}
if (maxsize < size || maxsize == 0) { if (maxsize < size || maxsize == 0) {
if (verbose) { if (verbose) {
if (maxsize == 0) if (maxsize == 0)
pr_err("no free space left on device. Aborting... \n"); pr_err("no free space left on device. Aborting... \n");
else else
pr_err("not enough space to create volume of give n size (%llu < %llu). Aborting...\n", pr_err("not enough space to create volume of give n size (%llu < %llu). Aborting...\n",
maxsize, size); maxsize, size);
} }
return 0; return 0;
skipping to change at line 7293 skipping to change at line 7499
if (dl->index >= 0) if (dl->index >= 0)
used++; used++;
/* don't activate new spares if we are orom constrained /* don't activate new spares if we are orom constrained
* and there is already a volume active in the container * and there is already a volume active in the container
*/ */
if (super->orom && dl->index < 0 && mpb->num_raid_devs) if (super->orom && dl->index < 0 && mpb->num_raid_devs)
continue; continue;
e = get_extents(super, dl); e = get_extents(super, dl, 0);
if (!e) if (!e)
continue; continue;
for (i = 1; e[i-1].size; i++) for (i = 1; e[i-1].size; i++)
; ;
dl->e = e; dl->e = e;
dl->extent_cnt = i; dl->extent_cnt = i;
extent_cnt += i; extent_cnt += i;
cnt++; cnt++;
} }
skipping to change at line 7326 skipping to change at line 7532
} }
if (size == 0) { if (size == 0) {
size = maxsize; size = maxsize;
if (chunk) { if (chunk) {
size /= 2 * chunk; size /= 2 * chunk;
size *= 2 * chunk; size *= 2 * chunk;
} }
maxsize = size; maxsize = size;
} }
if (!check_env("IMSM_NO_PLATFORM") && if (mpb->num_raid_devs > 0 && size && size != maxsize)
mpb->num_raid_devs > 0 && size && size != maxsize) { pr_err("attempting to create a second volume with size less then
pr_err("attempting to create a second volume with size less then remaining space.\n");
remaining space. Aborting...\n");
return 0;
}
cnt = 0; cnt = 0;
for (dl = super->disks; dl; dl = dl->next) for (dl = super->disks; dl; dl = dl->next)
if (dl->e) if (dl->e)
dl->raiddisk = cnt++; dl->raiddisk = cnt++;
*freesize = size; *freesize = size;
dprintf("imsm: imsm_get_free_size() returns : %llu\n", size); dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
return 1; return 1;
skipping to change at line 7378 skipping to change at line 7581
int consistency_policy, int verbose) int consistency_policy, int verbose)
{ {
int fd, cfd; int fd, cfd;
struct mdinfo *sra; struct mdinfo *sra;
int is_member = 0; int is_member = 0;
/* load capability /* load capability
* if given unused devices create a container * if given unused devices create a container
* if given given devices in a container create a member volume * if given given devices in a container create a member volume
*/ */
if (level == LEVEL_CONTAINER) { if (level == LEVEL_CONTAINER)
/* Must be a fresh device to add to a container */ /* Must be a fresh device to add to a container */
return validate_geometry_imsm_container(st, level, layout, return validate_geometry_imsm_container(st, level, raiddisks,
raiddisks, data_offset, dev,
*chunk, freesize, verbose);
size, data_offset,
dev, freesize,
verbose);
}
if (size && ((size < 1024) || (*chunk != UnSet && /*
size < (unsigned long long) *chunk))) { * Size is given in sectors.
pr_err("Given size must be greater than 1M and chunk size.\n"); */
if (size && (size < 2048)) {
pr_err("Given size must be greater than 1M.\n");
/* Depends on algorithm in Create.c : /* Depends on algorithm in Create.c :
* if container was given (dev == NULL) return -1, * if container was given (dev == NULL) return -1,
* if block device was given ( dev != NULL) return 0. * if block device was given ( dev != NULL) return 0.
*/ */
return dev ? -1 : 0; return dev ? -1 : 0;
} }
if (!dev) { if (!dev) {
if (st->sb) { if (st->sb) {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
skipping to change at line 7441 skipping to change at line 7642
if (st->sb) { if (st->sb) {
/* creating in a given container */ /* creating in a given container */
return validate_geometry_imsm_volume(st, level, layout, return validate_geometry_imsm_volume(st, level, layout,
raiddisks, chunk, size, raiddisks, chunk, size,
data_offset, data_offset,
dev, freesize, verbose); dev, freesize, verbose);
} }
/* This device needs to be a device in an 'imsm' container */ /* This device needs to be a device in an 'imsm' container */
fd = open(dev, O_RDONLY|O_EXCL, 0); fd = open(dev, O_RDONLY|O_EXCL, 0);
if (fd >= 0) {
if (verbose) if (is_fd_valid(fd)) {
pr_err("Cannot create this array on device %s\n", pr_vrb("Cannot create this array on device %s\n", dev);
dev);
close(fd); close(fd);
return 0; return 0;
} }
if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) { if (errno == EBUSY)
if (verbose) fd = open(dev, O_RDONLY, 0);
pr_err("Cannot open %s: %s\n",
dev, strerror(errno)); if (!is_fd_valid(fd)) {
pr_vrb("Cannot open %s: %s\n", dev, strerror(errno));
return 0; return 0;
} }
/* Well, it is in use by someone, maybe an 'imsm' container. */ /* Well, it is in use by someone, maybe an 'imsm' container. */
cfd = open_container(fd); cfd = open_container(fd);
close(fd); close_fd(&fd);
if (cfd < 0) {
if (verbose) if (!is_fd_valid(cfd)) {
pr_err("Cannot use %s: It is busy\n", pr_vrb("Cannot use %s: It is busy\n", dev);
dev);
return 0; return 0;
} }
sra = sysfs_read(cfd, NULL, GET_VERSION); sra = sysfs_read(cfd, NULL, GET_VERSION);
if (sra && sra->array.major_version == -1 && if (sra && sra->array.major_version == -1 &&
strcmp(sra->text_version, "imsm") == 0) strcmp(sra->text_version, "imsm") == 0)
is_member = 1; is_member = 1;
sysfs_free(sra); sysfs_free(sra);
if (is_member) { if (is_member) {
/* This is a member of a imsm container. Load the container /* This is a member of a imsm container. Load the container
* and try to create a volume * and try to create a volume
skipping to change at line 7509 skipping to change at line 7710
if (level && layout && *layout == UnSet) if (level && layout && *layout == UnSet)
*layout = imsm_level_to_layout(*level); *layout = imsm_level_to_layout(*level);
if (chunk && (*chunk == UnSet || *chunk == 0)) if (chunk && (*chunk == UnSet || *chunk == 0))
*chunk = imsm_default_chunk(super->orom); *chunk = imsm_default_chunk(super->orom);
} }
static void handle_missing(struct intel_super *super, struct imsm_dev *dev); static void handle_missing(struct intel_super *super, struct imsm_dev *dev);
static int kill_subarray_imsm(struct supertype *st) static int kill_subarray_imsm(struct supertype *st, char *subarray_id)
{ {
/* remove the subarray currently referenced by ->current_vol */ /* remove the subarray currently referenced by subarray_id */
__u8 i; __u8 i;
struct intel_dev **dp; struct intel_dev **dp;
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
__u8 current_vol = super->current_vol; __u8 current_vol = strtoul(subarray_id, NULL, 10);
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
if (super->current_vol < 0) if (mpb->num_raid_devs == 0)
return 2; return 2;
super->current_vol = -1; /* invalidate subarray cursor */
/* block deletions that would change the uuid of active subarrays /* block deletions that would change the uuid of active subarrays
* *
* FIXME when immutable ids are available, but note that we'll * FIXME when immutable ids are available, but note that we'll
* also need to fixup the invalidated/active subarray indexes in * also need to fixup the invalidated/active subarray indexes in
* mdstat * mdstat
*/ */
for (i = 0; i < mpb->num_raid_devs; i++) { for (i = 0; i < mpb->num_raid_devs; i++) {
char subarray[4]; char subarray[4];
skipping to change at line 7578 skipping to change at line 7778
for (d = super->disks; d; d = d->next) for (d = super->disks; d; d = d->next)
if (d->index > -2) if (d->index > -2)
mark_spare(d); mark_spare(d);
} }
super->updates_pending++; super->updates_pending++;
return 0; return 0;
} }
static int get_rwh_policy_from_update(char *update)
{
if (strcmp(update, "ppl") == 0)
return RWH_MULTIPLE_DISTRIBUTED;
else if (strcmp(update, "no-ppl") == 0)
return RWH_MULTIPLE_OFF;
else if (strcmp(update, "bitmap") == 0)
return RWH_BITMAP;
else if (strcmp(update, "no-bitmap") == 0)
return RWH_OFF;
return -1;
}
static int update_subarray_imsm(struct supertype *st, char *subarray, static int update_subarray_imsm(struct supertype *st, char *subarray,
char *update, struct mddev_ident *ident) char *update, struct mddev_ident *ident)
{ {
/* update the subarray currently referenced by ->current_vol */ /* update the subarray currently referenced by ->current_vol */
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
if (strcmp(update, "name") == 0) { if (strcmp(update, "name") == 0) {
char *name = ident->name; char *name = ident->name;
char *ep; char *ep;
skipping to change at line 7624 skipping to change at line 7837
dev = get_imsm_dev(super, vol); dev = get_imsm_dev(super, vol);
memset(dev->volume, '\0', MAX_RAID_SERIAL_LEN); memset(dev->volume, '\0', MAX_RAID_SERIAL_LEN);
namelen = min((int)strlen(name), MAX_RAID_SERIAL_LEN); namelen = min((int)strlen(name), MAX_RAID_SERIAL_LEN);
memcpy(dev->volume, name, namelen); memcpy(dev->volume, name, namelen);
for (i = 0; i < mpb->num_raid_devs; i++) { for (i = 0; i < mpb->num_raid_devs; i++) {
dev = get_imsm_dev(super, i); dev = get_imsm_dev(super, i);
handle_missing(super, dev); handle_missing(super, dev);
} }
super->updates_pending++; super->updates_pending++;
} }
} else if (strcmp(update, "ppl") == 0 || } else if (get_rwh_policy_from_update(update) != -1) {
strcmp(update, "no-ppl") == 0) {
int new_policy; int new_policy;
char *ep; char *ep;
int vol = strtoul(subarray, &ep, 10); int vol = strtoul(subarray, &ep, 10);
if (*ep != '\0' || vol >= super->anchor->num_raid_devs) if (*ep != '\0' || vol >= super->anchor->num_raid_devs)
return 2; return 2;
if (strcmp(update, "ppl") == 0) new_policy = get_rwh_policy_from_update(update);
new_policy = RWH_MULTIPLE_DISTRIBUTED;
else
new_policy = RWH_MULTIPLE_OFF;
if (st->update_tail) { if (st->update_tail) {
struct imsm_update_rwh_policy *u = xmalloc(sizeof(*u)); struct imsm_update_rwh_policy *u = xmalloc(sizeof(*u));
u->type = update_rwh_policy; u->type = update_rwh_policy;
u->dev_idx = vol; u->dev_idx = vol;
u->new_policy = new_policy; u->new_policy = new_policy;
append_metadata_update(st, u, sizeof(*u)); append_metadata_update(st, u, sizeof(*u));
} else { } else {
struct imsm_dev *dev; struct imsm_dev *dev;
dev = get_imsm_dev(super, vol); dev = get_imsm_dev(super, vol);
dev->rwh_policy = new_policy; dev->rwh_policy = new_policy;
super->updates_pending++; super->updates_pending++;
} }
if (new_policy == RWH_BITMAP)
return write_init_bitmap_imsm_vol(st, vol);
} else } else
return 2; return 2;
return 0; return 0;
} }
static int is_gen_migration(struct imsm_dev *dev) static bool is_gen_migration(struct imsm_dev *dev)
{ {
if (dev == NULL) if (dev && dev->vol.migr_state &&
return 0; migr_type(dev) == MIGR_GEN_MIGR)
return true;
if (!dev->vol.migr_state)
return 0;
if (migr_type(dev) == MIGR_GEN_MIGR) return false;
return 1;
return 0;
} }
static int is_rebuilding(struct imsm_dev *dev) static int is_rebuilding(struct imsm_dev *dev)
{ {
struct imsm_map *migr_map; struct imsm_map *migr_map;
if (!dev->vol.migr_state) if (!dev->vol.migr_state)
return 0; return 0;
if (migr_type(dev) != MIGR_REBUILD) if (migr_type(dev) != MIGR_REBUILD)
skipping to change at line 7736 skipping to change at line 7942
if (!rebuild) { if (!rebuild) {
/* (?) none of the disks are marked with /* (?) none of the disks are marked with
* IMSM_ORD_REBUILD, so assume they are missing and the * IMSM_ORD_REBUILD, so assume they are missing and the
* disk_ord_tbl was not correctly updated * disk_ord_tbl was not correctly updated
*/ */
dprintf("failed to locate out-of-sync disk\n"); dprintf("failed to locate out-of-sync disk\n");
return; return;
} }
units = __le32_to_cpu(dev->vol.curr_migr_unit); units = vol_curr_migr_unit(dev);
rebuild->recovery_start = units * blocks_per_migr_unit(super, dev); rebuild->recovery_start = units * blocks_per_migr_unit(super, dev);
} }
static int recover_backup_imsm(struct supertype *st, struct mdinfo *info); static int recover_backup_imsm(struct supertype *st, struct mdinfo *info);
static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra y) static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra y)
{ {
/* Given a container loaded by load_super_imsm_all, /* Given a container loaded by load_super_imsm_all,
* extract information about all the arrays into * extract information about all the arrays into
* an mdinfo tree. * an mdinfo tree.
skipping to change at line 7760 skipping to change at line 7966
* then look for matching devices in super->disks * then look for matching devices in super->disks
* and create appropriate device mdinfo. * and create appropriate device mdinfo.
*/ */
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
struct mdinfo *rest = NULL; struct mdinfo *rest = NULL;
unsigned int i; unsigned int i;
int sb_errors = 0; int sb_errors = 0;
struct dl *d; struct dl *d;
int spare_disks = 0; int spare_disks = 0;
int current_vol = super->current_vol;
/* do not assemble arrays when not all attributes are supported */ /* do not assemble arrays when not all attributes are supported */
if (imsm_check_attributes(mpb->attributes) == 0) { if (imsm_check_attributes(mpb->attributes) == 0) {
sb_errors = 1; sb_errors = 1;
pr_err("Unsupported attributes in IMSM metadata.Arrays activation is blocked.\n"); pr_err("Unsupported attributes in IMSM metadata.Arrays activation is blocked.\n");
} }
/* count spare devices, not used in maps /* count spare devices, not used in maps
*/ */
for (d = super->disks; d; d = d->next) for (d = super->disks; d; d = d->next)
skipping to change at line 7854 skipping to change at line 8061
if (d->index == idx) if (d->index == idx)
break; break;
recovery_start = MaxSector; recovery_start = MaxSector;
if (d == NULL) if (d == NULL)
skip = 1; skip = 1;
if (d && is_failed(&d->disk)) if (d && is_failed(&d->disk))
skip = 1; skip = 1;
if (!skip && (ord & IMSM_ORD_REBUILD)) if (!skip && (ord & IMSM_ORD_REBUILD))
recovery_start = 0; recovery_start = 0;
if (!(ord & IMSM_ORD_REBUILD))
this->array.working_disks++;
/* /*
* if we skip some disks the array will be assmebled degr aded; * if we skip some disks the array will be assmebled degr aded;
* reset resync start to avoid a dirty-degraded * reset resync start to avoid a dirty-degraded
* situation when performing the intial sync * situation when performing the intial sync
*/ */
if (skip) if (skip)
missing++; missing++;
if (!(dev->vol.dirty & RAIDVOL_DIRTY)) { if (!(dev->vol.dirty & RAIDVOL_DIRTY)) {
if ((!able_to_resync(level, missing) || if ((!able_to_resync(level, missing) ||
recovery_start == 0)) recovery_start == 0))
this->resync_start = MaxSector; this->resync_start = MaxSector;
} else {
/*
* FIXME handle dirty degraded
*/
} }
if (skip) if (skip)
continue; continue;
info_d = xcalloc(1, sizeof(*info_d)); info_d = xcalloc(1, sizeof(*info_d));
info_d->next = this->devs; info_d->next = this->devs;
this->devs = info_d; this->devs = info_d;
info_d->disk.number = d->index; info_d->disk.number = d->index;
skipping to change at line 7896 skipping to change at line 8100
if (slot < map2->num_members) if (slot < map2->num_members)
info_d->disk.state = (1 << MD_DISK_ACTIVE ); info_d->disk.state = (1 << MD_DISK_ACTIVE );
else else
this->array.spare_disks++; this->array.spare_disks++;
} else { } else {
if (slot < map->num_members) if (slot < map->num_members)
info_d->disk.state = (1 << MD_DISK_ACTIVE ); info_d->disk.state = (1 << MD_DISK_ACTIVE );
else else
this->array.spare_disks++; this->array.spare_disks++;
} }
if (info_d->recovery_start == MaxSector)
this->array.working_disks++;
info_d->events = __le32_to_cpu(mpb->generation_num); info_d->events = __le32_to_cpu(mpb->generation_num);
info_d->data_offset = pba_of_lba0(map); info_d->data_offset = pba_of_lba0(map);
info_d->component_size = calc_component_size(map, dev); info_d->component_size = calc_component_size(map, dev);
if (map->raid_level == 5) { if (map->raid_level == 5) {
info_d->ppl_sector = this->ppl_sector; info_d->ppl_sector = this->ppl_sector;
info_d->ppl_size = this->ppl_size; info_d->ppl_size = this->ppl_size;
if (this->consistency_policy == CONSISTENCY_POLIC Y_PPL && if (this->consistency_policy == CONSISTENCY_POLIC Y_PPL &&
recovery_start == 0) recovery_start == 0)
skipping to change at line 7927 skipping to change at line 8129
/* now that the disk list is up-to-date fixup recovery_start */ /* now that the disk list is up-to-date fixup recovery_start */
update_recovery_start(super, dev, this); update_recovery_start(super, dev, this);
this->array.spare_disks += spare_disks; this->array.spare_disks += spare_disks;
/* check for reshape */ /* check for reshape */
if (this->reshape_active == 1) if (this->reshape_active == 1)
recover_backup_imsm(st, this); recover_backup_imsm(st, this);
rest = this; rest = this;
} }
super->current_vol = current_vol;
return rest; return rest;
} }
static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
int failed, int look_in_map) int failed, int look_in_map)
{ {
struct imsm_map *map; struct imsm_map *map;
map = get_imsm_map(dev, look_in_map); map = get_imsm_map(dev, look_in_map);
skipping to change at line 8054 skipping to change at line 8257
ord & IMSM_ORD_REBUILD) ord & IMSM_ORD_REBUILD)
failed++; failed++;
} }
} }
} }
return failed; return failed;
} }
static int imsm_open_new(struct supertype *c, struct active_array *a, static int imsm_open_new(struct supertype *c, struct active_array *a,
char *inst) int inst)
{ {
struct intel_super *super = c->sb; struct intel_super *super = c->sb;
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
struct imsm_update_prealloc_bb_mem u; struct imsm_update_prealloc_bb_mem u;
if (atoi(inst) >= mpb->num_raid_devs) { if (inst >= mpb->num_raid_devs) {
pr_err("subarry index %d, out of range\n", atoi(inst)); pr_err("subarry index %d, out of range\n", inst);
return -ENODEV; return -ENODEV;
} }
dprintf("imsm: open_new %s\n", inst); dprintf("imsm: open_new %d\n", inst);
a->info.container_member = atoi(inst); a->info.container_member = inst;
u.type = update_prealloc_badblocks_mem; u.type = update_prealloc_badblocks_mem;
imsm_update_metadata_locally(c, &u, sizeof(u)); imsm_update_metadata_locally(c, &u, sizeof(u));
return 0; return 0;
} }
static int is_resyncing(struct imsm_dev *dev) static int is_resyncing(struct imsm_dev *dev)
{ {
struct imsm_map *migr_map; struct imsm_map *migr_map;
skipping to change at line 8139 skipping to change at line 8342
* This is valid for migration, initialization and rebuild * This is valid for migration, initialization and rebuild
*/ */
if (dev->vol.migr_state) { if (dev->vol.migr_state) {
struct imsm_map *map2 = get_imsm_map(dev, MAP_1); struct imsm_map *map2 = get_imsm_map(dev, MAP_1);
int slot2 = get_imsm_disk_slot(map2, idx); int slot2 = get_imsm_disk_slot(map2, idx);
if (slot2 < map2->num_members && slot2 >= 0) if (slot2 < map2->num_members && slot2 >= 0)
set_imsm_ord_tbl_ent(map2, slot2, set_imsm_ord_tbl_ent(map2, slot2,
idx | IMSM_ORD_REBUILD); idx | IMSM_ORD_REBUILD);
} }
if (map->failed_disk_num == 0xff) if (map->failed_disk_num == 0xff ||
(!is_rebuilding(dev) && map->failed_disk_num > slot))
map->failed_disk_num = slot; map->failed_disk_num = slot;
clear_disk_badblocks(super->bbm_log, ord_to_idx(ord)); clear_disk_badblocks(super->bbm_log, ord_to_idx(ord));
return 1; return 1;
} }
static void mark_missing(struct intel_super *super, static void mark_missing(struct intel_super *super,
struct imsm_dev *dev, struct imsm_disk *disk, int idx) struct imsm_dev *dev, struct imsm_disk *disk, int idx)
{ {
skipping to change at line 8175 skipping to change at line 8379
/* When orom adds replacement for missing disk it does /* When orom adds replacement for missing disk it does
* not remove entry of missing disk, but just updates map with * 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 * 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 * any missing disk, we have to look if there are any failed disks
* in map to stop migration */ * in map to stop migration */
dprintf("imsm: mark missing\n"); dprintf("imsm: mark missing\n");
/* end process for initialization and rebuild only /* end process for initialization and rebuild only
*/ */
if (is_gen_migration(dev) == 0) { if (is_gen_migration(dev) == false) {
int failed = imsm_count_failed(super, dev, MAP_0); int failed = imsm_count_failed(super, dev, MAP_0);
if (failed) { if (failed) {
__u8 map_state; __u8 map_state;
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
struct imsm_map *map1; struct imsm_map *map1;
int i, ord, ord_map1; int i, ord, ord_map1;
int rebuilt = 1; int rebuilt = 1;
for (i = 0; i < map->num_members; i++) { for (i = 0; i < map->num_members; i++) {
skipping to change at line 8281 skipping to change at line 8485
continue; continue;
/* OK, this array needs to enter reshape mode. /* OK, this array needs to enter reshape mode.
* i.e it needs a migr_state * i.e it needs a migr_state
*/ */
copy_map_size = sizeof_imsm_map(map); copy_map_size = sizeof_imsm_map(map);
prev_num_members = map->num_members; prev_num_members = map->num_members;
map->num_members = prev_disks; map->num_members = prev_disks;
dev->vol.migr_state = 1; dev->vol.migr_state = 1;
dev->vol.curr_migr_unit = 0; set_vol_curr_migr_unit(dev, 0);
set_migr_type(dev, MIGR_GEN_MIGR); set_migr_type(dev, MIGR_GEN_MIGR);
for (i = prev_num_members; for (i = prev_num_members;
i < map->num_members; i++) i < map->num_members; i++)
set_imsm_ord_tbl_ent(map, i, i); set_imsm_ord_tbl_ent(map, i, i);
map2 = get_imsm_map(dev, MAP_1); map2 = get_imsm_map(dev, MAP_1);
/* Copy the current map */ /* Copy the current map */
memcpy(map2, map, copy_map_size); memcpy(map2, map, copy_map_size);
map2->num_members = prev_num_members; map2->num_members = prev_num_members;
imsm_set_array_size(dev, -1); imsm_set_array_size(dev, -1);
skipping to change at line 8318 skipping to change at line 8522
int failed = imsm_count_failed(super, dev, MAP_0); int failed = imsm_count_failed(super, dev, MAP_0);
__u8 map_state = imsm_check_degraded(super, dev, failed, MAP_0); __u8 map_state = imsm_check_degraded(super, dev, failed, MAP_0);
__u32 blocks_per_unit; __u32 blocks_per_unit;
if (dev->vol.migr_state && if (dev->vol.migr_state &&
dev->vol.migr_type == MIGR_GEN_MIGR) { dev->vol.migr_type == MIGR_GEN_MIGR) {
/* array state change is blocked due to reshape action /* array state change is blocked due to reshape action
* We might need to * We might need to
* - abort the reshape (if last_checkpoint is 0 and action!= resh ape) * - abort the reshape (if last_checkpoint is 0 and action!= resh ape)
* - finish the reshape (if last_checkpoint is big and action != reshape) * - finish the reshape (if last_checkpoint is big and action != reshape)
* - update curr_migr_unit * - update vol_curr_migr_unit
*/ */
if (a->curr_action == reshape) { if (a->curr_action == reshape) {
/* still reshaping, maybe update curr_migr_unit */ /* still reshaping, maybe update vol_curr_migr_unit */
goto mark_checkpoint; goto mark_checkpoint;
} else { } else {
if (a->last_checkpoint == 0 && a->prev_action == reshape) { if (a->last_checkpoint == 0 && a->prev_action == reshape) {
/* for some reason we aborted the reshape. /* for some reason we aborted the reshape.
* *
* disable automatic metadata rollback * disable automatic metadata rollback
* user action is required to recover process * user action is required to recover process
*/ */
if (0) { if (0) {
struct imsm_map *map2 = struct imsm_map *map2 =
get_imsm_map(dev, MAP_1); get_imsm_map(dev, MAP_1);
dev->vol.migr_state = 0; dev->vol.migr_state = 0;
set_migr_type(dev, 0); set_migr_type(dev, 0);
dev->vol.curr_migr_unit = 0; set_vol_curr_migr_unit(dev, 0);
memcpy(map, map2, memcpy(map, map2,
sizeof_imsm_map(map2)); sizeof_imsm_map(map2));
super->updates_pending++; super->updates_pending++;
} }
} }
if (a->last_checkpoint >= a->info.component_size) { if (a->last_checkpoint >= a->info.component_size) {
unsigned long long array_blocks; unsigned long long array_blocks;
int used_disks; int used_disks;
struct mdinfo *mdi; struct mdinfo *mdi;
skipping to change at line 8411 skipping to change at line 8615
super->updates_pending++; super->updates_pending++;
} }
mark_checkpoint: mark_checkpoint:
/* skip checkpointing for general migration, /* skip checkpointing for general migration,
* it is controlled in mdadm * it is controlled in mdadm
*/ */
if (is_gen_migration(dev)) if (is_gen_migration(dev))
goto skip_mark_checkpoint; goto skip_mark_checkpoint;
/* check if we can update curr_migr_unit from resync_start, recovery_star /* check if we can update vol_curr_migr_unit from resync_start,
t */ * recovery_start
*/
blocks_per_unit = blocks_per_migr_unit(super, dev); blocks_per_unit = blocks_per_migr_unit(super, dev);
if (blocks_per_unit) { if (blocks_per_unit) {
__u32 units32; set_vol_curr_migr_unit(dev,
__u64 units; a->last_checkpoint / blocks_per_unit);
dprintf("imsm: mark checkpoint (%llu)\n",
units = a->last_checkpoint / blocks_per_unit; vol_curr_migr_unit(dev));
units32 = units; super->updates_pending++;
/* check that we did not overflow 32-bits, and that
* curr_migr_unit needs updating
*/
if (units32 == units &&
units32 != 0 &&
__le32_to_cpu(dev->vol.curr_migr_unit) != units32) {
dprintf("imsm: mark checkpoint (%u)\n", units32);
dev->vol.curr_migr_unit = __cpu_to_le32(units32);
super->updates_pending++;
}
} }
skip_mark_checkpoint: skip_mark_checkpoint:
/* mark dirty / clean */ /* mark dirty / clean */
if (((dev->vol.dirty & RAIDVOL_DIRTY) && consistent) || if (((dev->vol.dirty & RAIDVOL_DIRTY) && consistent) ||
(!(dev->vol.dirty & RAIDVOL_DIRTY) && !consistent)) { (!(dev->vol.dirty & RAIDVOL_DIRTY) && !consistent)) {
dprintf("imsm: mark '%s'\n", consistent ? "clean" : "dirty"); dprintf("imsm: mark '%s'\n", consistent ? "clean" : "dirty");
if (consistent) { if (consistent) {
dev->vol.dirty = RAIDVOL_CLEAN; dev->vol.dirty = RAIDVOL_CLEAN;
} else { } else {
skipping to change at line 8493 skipping to change at line 8688
int i; int i;
ord = get_imsm_ord_tbl_ent(dev, n, MAP_X); ord = get_imsm_ord_tbl_ent(dev, n, MAP_X);
if (ord < 0) if (ord < 0)
return; return;
dprintf("imsm: set_disk %d:%x\n", n, state); dprintf("imsm: set_disk %d:%x\n", n, state);
disk = get_imsm_disk(super, ord_to_idx(ord)); disk = get_imsm_disk(super, ord_to_idx(ord));
/* check for new failures */ /* check for new failures */
if (state & DS_FAULTY) { if (disk && (state & DS_FAULTY)) {
if (mark_failure(super, dev, disk, ord_to_idx(ord))) if (mark_failure(super, dev, disk, ord_to_idx(ord)))
super->updates_pending++; super->updates_pending++;
} }
/* check if in_sync */ /* check if in_sync */
if (state & DS_INSYNC && ord & IMSM_ORD_REBUILD && is_rebuilding(dev)) { if (state & DS_INSYNC && ord & IMSM_ORD_REBUILD && is_rebuilding(dev)) {
struct imsm_map *migr_map = get_imsm_map(dev, MAP_1); struct imsm_map *migr_map = get_imsm_map(dev, MAP_1);
set_imsm_ord_tbl_ent(migr_map, n, ord_to_idx(ord)); set_imsm_ord_tbl_ent(migr_map, n, ord_to_idx(ord));
rebuild_done = 1; rebuild_done = 1;
skipping to change at line 8533 skipping to change at line 8728
if (recovery_not_finished) { if (recovery_not_finished) {
dprintf_cont("\n"); dprintf_cont("\n");
dprintf("Rebuild has not finished yet, state not changed"); dprintf("Rebuild has not finished yet, state not changed");
if (a->last_checkpoint < mdi->recovery_start) { if (a->last_checkpoint < mdi->recovery_start) {
a->last_checkpoint = mdi->recovery_start; a->last_checkpoint = mdi->recovery_start;
super->updates_pending++; super->updates_pending++;
} }
break; break;
} }
end_migration(dev, super, map_state); end_migration(dev, super, map_state);
map = get_imsm_map(dev, MAP_0);
map->failed_disk_num = ~0; map->failed_disk_num = ~0;
super->updates_pending++; super->updates_pending++;
a->last_checkpoint = 0; a->last_checkpoint = 0;
break; break;
} }
if (is_gen_migration(dev)) { if (is_gen_migration(dev)) {
dprintf_cont("while general migration"); dprintf_cont("while general migration");
if (a->last_checkpoint >= a->info.component_size) if (a->last_checkpoint >= a->info.component_size)
end_migration(dev, super, map_state); end_migration(dev, super, map_state);
else else
map->map_state = map_state; map->map_state = map_state;
map = get_imsm_map(dev, MAP_0);
map->failed_disk_num = ~0; map->failed_disk_num = ~0;
super->updates_pending++; super->updates_pending++;
break; break;
} }
break; break;
case IMSM_T_STATE_DEGRADED: /* transition to degraded state */ case IMSM_T_STATE_DEGRADED: /* transition to degraded state */
dprintf_cont("degraded: "); dprintf_cont("degraded: ");
if (map->map_state != map_state && !dev->vol.migr_state) { if (map->map_state != map_state && !dev->vol.migr_state) {
dprintf_cont("mark degraded"); dprintf_cont("mark degraded");
map->map_state = map_state; map->map_state = map_state;
super->updates_pending++; super->updates_pending++;
a->last_checkpoint = 0; a->last_checkpoint = 0;
break; break;
} }
if (is_rebuilding(dev)) { if (is_rebuilding(dev)) {
dprintf_cont("while rebuilding."); dprintf_cont("while rebuilding ");
if (map->map_state != map_state) { if (state & DS_FAULTY) {
dprintf_cont(" Map state change"); dprintf_cont("removing failed drive ");
end_migration(dev, super, map_state); if (n == map->failed_disk_num) {
dprintf_cont("end migration");
end_migration(dev, super, map_state);
a->last_checkpoint = 0;
} else {
dprintf_cont("fail detected during rebuil
d, changing map state");
map->map_state = map_state;
}
super->updates_pending++; super->updates_pending++;
} else if (!rebuild_done) {
break;
} }
if (!rebuild_done)
break;
/* check if recovery is really finished */ /* check if recovery is really finished */
for (mdi = a->info.devs; mdi ; mdi = mdi->next) for (mdi = a->info.devs; mdi ; mdi = mdi->next)
if (mdi->recovery_start != MaxSector) { if (mdi->recovery_start != MaxSector) {
recovery_not_finished = 1; recovery_not_finished = 1;
break; break;
} }
if (recovery_not_finished) { if (recovery_not_finished) {
dprintf_cont("\n"); dprintf_cont("\n");
dprintf("Rebuild has not finished yet, state not changed"); dprintf_cont("Rebuild has not finished yet");
if (a->last_checkpoint < mdi->recovery_start) { if (a->last_checkpoint < mdi->recovery_start) {
a->last_checkpoint = a->last_checkpoint =
mdi->recovery_start; mdi->recovery_start;
super->updates_pending++; super->updates_pending++;
} }
break; break;
} }
dprintf_cont(" Rebuild done, still degraded"); dprintf_cont(" Rebuild done, still degraded");
dev->vol.migr_state = 0; end_migration(dev, super, map_state);
set_migr_type(dev, 0); a->last_checkpoint = 0;
dev->vol.curr_migr_unit = 0; super->updates_pending++;
for (i = 0; i < map->num_members; i++) { for (i = 0; i < map->num_members; i++) {
int idx = get_imsm_ord_tbl_ent(dev, i, MAP_0); int idx = get_imsm_ord_tbl_ent(dev, i, MAP_0);
if (idx & IMSM_ORD_REBUILD) if (idx & IMSM_ORD_REBUILD)
map->failed_disk_num = i; map->failed_disk_num = i;
} }
super->updates_pending++; super->updates_pending++;
break; break;
} }
skipping to change at line 8649 skipping to change at line 8850
} }
static int store_imsm_mpb(int fd, struct imsm_super *mpb) static int store_imsm_mpb(int fd, struct imsm_super *mpb)
{ {
void *buf = mpb; void *buf = mpb;
__u32 mpb_size = __le32_to_cpu(mpb->mpb_size); __u32 mpb_size = __le32_to_cpu(mpb->mpb_size);
unsigned long long dsize; unsigned long long dsize;
unsigned long long sectors; unsigned long long sectors;
unsigned int sector_size; unsigned int sector_size;
get_dev_sector_size(fd, NULL, &sector_size); if (!get_dev_sector_size(fd, NULL, &sector_size))
return 1;
get_dev_size(fd, NULL, &dsize); get_dev_size(fd, NULL, &dsize);
if (mpb_size > sector_size) { if (mpb_size > sector_size) {
/* -1 to account for anchor */ /* -1 to account for anchor */
sectors = mpb_sectors(mpb, sector_size) - 1; sectors = mpb_sectors(mpb, sector_size) - 1;
/* write the extended mpb to the sectors preceeding the anchor */ /* write the extended mpb to the sectors preceeding the anchor */
if (lseek64(fd, dsize - (sector_size * (2 + sectors)), if (lseek64(fd, dsize - (sector_size * (2 + sectors)),
SEEK_SET) < 0) SEEK_SET) < 0)
return 1; return 1;
skipping to change at line 8729 skipping to change at line 8931
int i, j; int i, j;
int found; int found;
__u32 array_start = 0; __u32 array_start = 0;
__u32 array_end = 0; __u32 array_end = 0;
struct dl *dl; struct dl *dl;
struct mdinfo *test_list; struct mdinfo *test_list;
for (dl = super->disks; dl; dl = dl->next) { for (dl = super->disks; dl; dl = dl->next) {
/* If in this array, skip */ /* If in this array, skip */
for (d = a->info.devs ; d ; d = d->next) for (d = a->info.devs ; d ; d = d->next)
if (d->state_fd >= 0 && if (is_fd_valid(d->state_fd) &&
d->disk.major == dl->major && d->disk.major == dl->major &&
d->disk.minor == dl->minor) { d->disk.minor == dl->minor) {
dprintf("%x:%x already in array\n", dprintf("%x:%x already in array\n",
dl->major, dl->minor); dl->major, dl->minor);
break; break;
} }
if (d) if (d)
continue; continue;
test_list = additional_test_list; test_list = additional_test_list;
while (test_list) { while (test_list) {
skipping to change at line 8771 skipping to change at line 8973
*/ */
if (dl->index == -1 && !activate_new) if (dl->index == -1 && !activate_new)
continue; continue;
if (!drive_validate_sector_size(super, dl)) if (!drive_validate_sector_size(super, dl))
continue; continue;
/* Does this unused device have the requisite free space? /* Does this unused device have the requisite free space?
* It needs to be able to cover all member volumes * It needs to be able to cover all member volumes
*/ */
ex = get_extents(super, dl); ex = get_extents(super, dl, 1);
if (!ex) { if (!ex) {
dprintf("cannot get extents\n"); dprintf("cannot get extents\n");
continue; continue;
} }
for (i = 0; i < mpb->num_raid_devs; i++) { for (i = 0; i < mpb->num_raid_devs; i++) {
dev = get_imsm_dev(super, i); dev = get_imsm_dev(super, i);
map = get_imsm_map(dev, MAP_0); map = get_imsm_map(dev, MAP_0);
/* check if this disk is already a member of /* check if this disk is already a member of
* this array * this array
skipping to change at line 8889 skipping to change at line 9091
struct mdinfo *rv = NULL; struct mdinfo *rv = NULL;
struct mdinfo *d; struct mdinfo *d;
struct mdinfo *di; struct mdinfo *di;
struct metadata_update *mu; struct metadata_update *mu;
struct dl *dl; struct dl *dl;
struct imsm_update_activate_spare *u; struct imsm_update_activate_spare *u;
int num_spares = 0; int num_spares = 0;
int i; int i;
int allowed; int allowed;
for (d = a->info.devs ; d ; d = d->next) { for (d = a->info.devs ; d; d = d->next) {
if ((d->curr_state & DS_FAULTY) && if (!is_fd_valid(d->state_fd))
d->state_fd >= 0) continue;
if (d->curr_state & DS_FAULTY)
/* wait for Removal to happen */ /* wait for Removal to happen */
return NULL; return NULL;
if (d->state_fd >= 0)
failed--; failed--;
} }
dprintf("imsm: activate spare: inst=%d failed=%d (%d) level=%d\n", dprintf("imsm: activate spare: inst=%d failed=%d (%d) level=%d\n",
inst, failed, a->info.array.raid_disks, a->info.array.level); inst, failed, a->info.array.raid_disks, a->info.array.level);
if (imsm_reshape_blocks_arrays_changes(super)) if (imsm_reshape_blocks_arrays_changes(super))
return NULL; return NULL;
/* Cannot activate another spare if rebuild is in progress already /* Cannot activate another spare if rebuild is in progress already
*/ */
skipping to change at line 8951 skipping to change at line 9155
} }
} }
} }
/* For each slot, if it is not working, find a spare */ /* For each slot, if it is not working, find a spare */
for (i = 0; i < a->info.array.raid_disks; i++) { for (i = 0; i < a->info.array.raid_disks; i++) {
for (d = a->info.devs ; d ; d = d->next) for (d = a->info.devs ; d ; d = d->next)
if (d->disk.raid_disk == i) if (d->disk.raid_disk == i)
break; break;
dprintf("found %d: %p %x\n", i, d, d?d->curr_state:0); dprintf("found %d: %p %x\n", i, d, d?d->curr_state:0);
if (d && (d->state_fd >= 0)) if (d && is_fd_valid(d->state_fd))
continue; continue;
/* /*
* OK, this device needs recovery. Try to re-add the * OK, this device needs recovery. Try to re-add the
* previous occupant of this slot, if this fails see if * previous occupant of this slot, if this fails see if
* we can continue the assimilation of a spare that was * we can continue the assimilation of a spare that was
* partially assimilated, finally try to activate a new * partially assimilated, finally try to activate a new
* spare. * spare.
*/ */
dl = imsm_readd(super, i, a); dl = imsm_readd(super, i, a);
skipping to change at line 9081 skipping to change at line 9285
prev = NULL; prev = NULL;
for (dl = super->disks; dl; dl = dl->next) { for (dl = super->disks; dl; dl = dl->next) {
if (dl->major == major && dl->minor == minor) { if (dl->major == major && dl->minor == minor) {
/* remove */ /* remove */
if (prev) if (prev)
prev->next = dl->next; prev->next = dl->next;
else else
super->disks = dl->next; super->disks = dl->next;
dl->next = NULL; dl->next = NULL;
__free_imsm_disk(dl); __free_imsm_disk(dl, 1);
dprintf("removed %x:%x\n", major, minor); dprintf("removed %x:%x\n", major, minor);
break; break;
} }
prev = dl; prev = dl;
} }
return 0; return 0;
} }
static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind ex); static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind ex);
skipping to change at line 9125 skipping to change at line 9329
disk_cfg->major, disk_cfg->major,
disk_cfg->minor); disk_cfg->minor);
if (disk) { if (disk) {
/* store action status */ /* store action status */
disk->action = DISK_REMOVE; disk->action = DISK_REMOVE;
/* remove spare disks only */ /* remove spare disks only */
if (disk->index == -1) { if (disk->index == -1) {
remove_disk_super(super, remove_disk_super(super,
disk_cfg->major, disk_cfg->major,
disk_cfg->minor); disk_cfg->minor);
} else {
disk_cfg->fd = disk->fd;
disk->fd = -1;
} }
} }
/* release allocate disk structure */ /* release allocate disk structure */
__free_imsm_disk(disk_cfg); __free_imsm_disk(disk_cfg, 1);
} }
} }
return check_degraded; return check_degraded;
} }
static int apply_reshape_migration_update(struct imsm_update_reshape_migration * u, static int apply_reshape_migration_update(struct imsm_update_reshape_migration * u,
struct intel_super *super, struct intel_super *super,
void ***space_list) void ***space_list)
{ {
struct intel_dev *id; struct intel_dev *id;
skipping to change at line 9203 skipping to change at line 9410
set_imsm_ord_tbl_ent(map, set_imsm_ord_tbl_ent(map,
map->num_members - 1, map->num_members - 1,
ord); ord);
} }
id->dev = new_dev; id->dev = new_dev;
tofree = (void **)dev; tofree = (void **)dev;
/* update chunk size /* update chunk size
*/ */
if (u->new_chunksize > 0) { if (u->new_chunksize > 0) {
unsigned long long num_data_stripes;
struct imsm_map *dest_map = struct imsm_map *dest_map =
get_imsm_map(dev, MAP_0); get_imsm_map(dev, MAP_0);
int used_disks = int used_disks =
imsm_num_data_members(dest_map); imsm_num_data_members(dest_map);
if (used_disks == 0) if (used_disks == 0)
return ret_val; return ret_val;
map->blocks_per_strip = map->blocks_per_strip =
__cpu_to_le16(u->new_chunksize * 2); __cpu_to_le16(u->new_chunksize * 2);
num_data_stripes = update_num_data_stripes(map, imsm_dev_size(dev));
imsm_dev_size(dev) / used_disks;
num_data_stripes /= map->blocks_per_strip;
num_data_stripes /= map->num_domains;
set_num_data_stripes(map, num_data_stripes);
} }
/* ensure blocks_per_member has valid value /* ensure blocks_per_member has valid value
*/ */
set_blocks_per_member(map, set_blocks_per_member(map,
per_dev_array_size(map) + per_dev_array_size(map) +
NUM_BLOCKS_DIRTY_STRIPE_REGION); NUM_BLOCKS_DIRTY_STRIPE_REGION);
/* add disk /* add disk
*/ */
skipping to change at line 9292 skipping to change at line 9494
dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev); dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
return ret_val; return ret_val;
} }
for (id = super->devlist ; id; id = id->next) { for (id = super->devlist ; id; id = id->next) {
if (id->index == (unsigned)u->subdev) { if (id->index == (unsigned)u->subdev) {
struct imsm_dev *dev = get_imsm_dev(super, u->subdev); struct imsm_dev *dev = get_imsm_dev(super, u->subdev);
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
int used_disks = imsm_num_data_members(map); int used_disks = imsm_num_data_members(map);
unsigned long long blocks_per_member; unsigned long long blocks_per_member;
unsigned long long num_data_stripes;
unsigned long long new_size_per_disk; unsigned long long new_size_per_disk;
if (used_disks == 0) if (used_disks == 0)
return 0; return 0;
/* calculate new size /* calculate new size
*/ */
new_size_per_disk = u->new_size / used_disks; new_size_per_disk = u->new_size / used_disks;
blocks_per_member = new_size_per_disk + blocks_per_member = new_size_per_disk +
NUM_BLOCKS_DIRTY_STRIPE_REGION; NUM_BLOCKS_DIRTY_STRIPE_REGION;
num_data_stripes = new_size_per_disk /
map->blocks_per_strip;
num_data_stripes /= map->num_domains;
dprintf("(size: %llu, blocks per member: %llu, num_data_s
tipes: %llu)\n",
u->new_size, new_size_per_disk,
num_data_stripes);
set_blocks_per_member(map, blocks_per_member);
set_num_data_stripes(map, num_data_stripes);
imsm_set_array_size(dev, u->new_size);
imsm_set_array_size(dev, u->new_size);
set_blocks_per_member(map, blocks_per_member);
update_num_data_stripes(map, u->new_size);
ret_val = 1; ret_val = 1;
break; break;
} }
} }
return ret_val; return ret_val;
} }
static int prepare_spare_to_activate(struct supertype *st,
struct imsm_update_activate_spare *u)
{
struct intel_super *super = st->sb;
int prev_current_vol = super->current_vol;
struct active_array *a;
int ret = 1;
for (a = st->arrays; a; a = a->next)
/*
* Additional initialization (adding bitmap header, filling
* the bitmap area with '1's to force initial rebuild for a whole
* data-area) is required when adding the spare to the volume
* with write-intent bitmap.
*/
if (a->info.container_member == u->array &&
a->info.consistency_policy == CONSISTENCY_POLICY_BITMAP) {
struct dl *dl;
for (dl = super->disks; dl; dl = dl->next)
if (dl == u->dl)
break;
if (!dl)
break;
super->current_vol = u->array;
if (st->ss->write_bitmap(st, dl->fd, NoUpdate))
ret = 0;
super->current_vol = prev_current_vol;
}
return ret;
}
static int apply_update_activate_spare(struct imsm_update_activate_spare *u, static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
struct intel_super *super, struct intel_super *super,
struct active_array *active_array) struct active_array *active_array)
{ {
struct imsm_super *mpb = super->anchor; struct imsm_super *mpb = super->anchor;
struct imsm_dev *dev = get_imsm_dev(super, u->array); struct imsm_dev *dev = get_imsm_dev(super, u->array);
struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_map *map = get_imsm_map(dev, MAP_0);
struct imsm_map *migr_map; struct imsm_map *migr_map;
struct active_array *a; struct active_array *a;
struct imsm_disk *disk; struct imsm_disk *disk;
skipping to change at line 9505 skipping to change at line 9733
newmap = get_imsm_map(newdev, MAP_0); newmap = get_imsm_map(newdev, MAP_0);
/* Copy the current map */ /* Copy the current map */
memcpy(newmap, oldmap, sizeof_imsm_map(oldmap)); memcpy(newmap, oldmap, sizeof_imsm_map(oldmap));
/* update one device only /* update one device only
*/ */
if (devices_to_reshape) { if (devices_to_reshape) {
dprintf("imsm: modifying subdev: %i\n", dprintf("imsm: modifying subdev: %i\n",
id->index); id->index);
devices_to_reshape--; devices_to_reshape--;
newdev->vol.migr_state = 1; newdev->vol.migr_state = 1;
newdev->vol.curr_migr_unit = 0; set_vol_curr_migr_unit(newdev, 0);
set_migr_type(newdev, MIGR_GEN_MIGR); set_migr_type(newdev, MIGR_GEN_MIGR);
newmap->num_members = u->new_raid_disks; newmap->num_members = u->new_raid_disks;
for (i = 0; i < delta_disks; i++) { for (i = 0; i < delta_disks; i++) {
set_imsm_ord_tbl_ent(newmap, set_imsm_ord_tbl_ent(newmap,
u->old_raid_disks + i, u->old_raid_disks + i,
u->old_raid_disks + i); u->old_raid_disks + i);
} }
/* New map is correct, now need to save old map /* New map is correct, now need to save old map
*/ */
newmap = get_imsm_map(newdev, MAP_1); newmap = get_imsm_map(newdev, MAP_1);
skipping to change at line 9561 skipping to change at line 9789
dev = dv->dev; dev = dv->dev;
break; break;
} }
if (dev == NULL) if (dev == NULL)
return 0; return 0;
map = get_imsm_map(dev, MAP_0); map = get_imsm_map(dev, MAP_0);
if (u->direction == R10_TO_R0) { if (u->direction == R10_TO_R0) {
unsigned long long num_data_stripes;
/* Number of failed disks must be half of initial disk number */ /* Number of failed disks must be half of initial disk number */
if (imsm_count_failed(super, dev, MAP_0) != if (imsm_count_failed(super, dev, MAP_0) !=
(map->num_members / 2)) (map->num_members / 2))
return 0; return 0;
/* iterate through devices to mark removed disks as spare */ /* iterate through devices to mark removed disks as spare */
for (dm = super->disks; dm; dm = dm->next) { for (dm = super->disks; dm; dm = dm->next) {
if (dm->disk.status & FAILED_DISK) { if (dm->disk.status & FAILED_DISK) {
int idx = dm->index; int idx = dm->index;
/* update indexes on the disk list */ /* update indexes on the disk list */
/* FIXME this loop-with-the-loop looks wrong, I'm not convinced /* FIXME this loop-with-the-loop looks wrong, I'm not convinced
the index values will end up being correct.... NB */ the index values will end up being correct.... NB */
for (du = super->disks; du; du = du->next) for (du = super->disks; du; du = du->next)
if (du->index > idx) if (du->index > idx)
du->index--; du->index--;
/* mark as spare disk */ /* mark as spare disk */
mark_spare(dm); mark_spare(dm);
} }
} }
/* update map */ /* update map */
map->num_members = map->num_members / 2; map->num_members /= map->num_domains;
map->map_state = IMSM_T_STATE_NORMAL; map->map_state = IMSM_T_STATE_NORMAL;
map->num_domains = 1;
map->raid_level = 0; map->raid_level = 0;
set_num_domains(map);
update_num_data_stripes(map, imsm_dev_size(dev));
map->failed_disk_num = -1; map->failed_disk_num = -1;
num_data_stripes = imsm_dev_size(dev) / 2;
num_data_stripes /= map->blocks_per_strip;
set_num_data_stripes(map, num_data_stripes);
} }
if (u->direction == R0_TO_R10) { if (u->direction == R0_TO_R10) {
void **space; void **space;
unsigned long long num_data_stripes;
/* update slots in current disk list */ /* update slots in current disk list */
for (dm = super->disks; dm; dm = dm->next) { for (dm = super->disks; dm; dm = dm->next) {
if (dm->index >= 0) if (dm->index >= 0)
dm->index *= 2; dm->index *= 2;
} }
/* create new *missing* disks */ /* create new *missing* disks */
for (i = 0; i < map->num_members; i++) { for (i = 0; i < map->num_members; i++) {
space = *space_list; space = *space_list;
if (!space) if (!space)
skipping to change at line 9630 skipping to change at line 9853
} }
/* create new dev and map */ /* create new dev and map */
space = *space_list; space = *space_list;
if (!space) if (!space)
return 0; return 0;
*space_list = *space; *space_list = *space;
dev_new = (void *)space; dev_new = (void *)space;
memcpy(dev_new, dev, sizeof(*dev)); memcpy(dev_new, dev, sizeof(*dev));
/* update new map */ /* update new map */
map = get_imsm_map(dev_new, MAP_0); map = get_imsm_map(dev_new, MAP_0);
map->num_members = map->num_members * 2;
map->map_state = IMSM_T_STATE_DEGRADED; map->map_state = IMSM_T_STATE_DEGRADED;
map->num_domains = 2;
map->raid_level = 1; map->raid_level = 1;
num_data_stripes = imsm_dev_size(dev) / 2; set_num_domains(map);
num_data_stripes /= map->blocks_per_strip; map->num_members = map->num_members * map->num_domains;
num_data_stripes /= map->num_domains; update_num_data_stripes(map, imsm_dev_size(dev));
set_num_data_stripes(map, num_data_stripes);
/* replace dev<->dev_new */ /* replace dev<->dev_new */
dv->dev = dev_new; dv->dev = dev_new;
} }
/* update disk order table */ /* update disk order table */
for (du = super->disks; du; du = du->next) for (du = super->disks; du; du = du->next)
if (du->index >= 0) if (du->index >= 0)
set_imsm_ord_tbl_ent(map, du->index, du->index); set_imsm_ord_tbl_ent(map, du->index, du->index);
for (du = super->missing; du; du = du->next) for (du = super->missing; du; du = du->next)
if (du->index >= 0) { if (du->index >= 0) {
skipping to change at line 9707 skipping to change at line 9928
case update_general_migration_checkpoint: { case update_general_migration_checkpoint: {
struct intel_dev *id; struct intel_dev *id;
struct imsm_update_general_migration_checkpoint *u = struct imsm_update_general_migration_checkpoint *u =
(void *)update->buf; (void *)update->buf;
dprintf("called for update_general_migration_checkpoint\n"); dprintf("called for update_general_migration_checkpoint\n");
/* find device under general migration */ /* find device under general migration */
for (id = super->devlist ; id; id = id->next) { for (id = super->devlist ; id; id = id->next) {
if (is_gen_migration(id->dev)) { if (is_gen_migration(id->dev)) {
id->dev->vol.curr_migr_unit = set_vol_curr_migr_unit(id->dev,
__cpu_to_le32(u->curr_migr_unit); u->curr_migr_unit);
super->updates_pending++; super->updates_pending++;
} }
} }
break; break;
} }
case update_takeover: { case update_takeover: {
struct imsm_update_takeover *u = (void *)update->buf; struct imsm_update_takeover *u = (void *)update->buf;
if (apply_takeover_update(u, super, &update->space_list)) { if (apply_takeover_update(u, super, &update->space_list)) {
imsm_update_version_info(super); imsm_update_version_info(super);
super->updates_pending++; super->updates_pending++;
skipping to change at line 9745 skipping to change at line 9966
break; break;
} }
case update_size_change: { case update_size_change: {
struct imsm_update_size_change *u = (void *)update->buf; struct imsm_update_size_change *u = (void *)update->buf;
if (apply_size_change_update(u, super)) if (apply_size_change_update(u, super))
super->updates_pending++; super->updates_pending++;
break; break;
} }
case update_activate_spare: { 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))
if (prepare_spare_to_activate(st, u) &&
apply_update_activate_spare(u, super, st->arrays))
super->updates_pending++; super->updates_pending++;
break; break;
} }
case update_create_array: { case update_create_array: {
/* someone wants to create a new array, we need to be aware of /* someone wants to create a new array, we need to be aware of
* a few races/collisions: * a few races/collisions:
* 1/ 'Create' called by two separate instances of mdadm * 1/ 'Create' called by two separate instances of mdadm
* 2/ 'Create' versus 'activate_spare': mdadm has chosen * 2/ 'Create' versus 'activate_spare': mdadm has chosen
* devices that have since been assimilated via * devices that have since been assimilated via
* activate_spare. * activate_spare.
skipping to change at line 9959 skipping to change at line 10182
break; break;
} }
if (dev->rwh_policy != u->new_policy) { if (dev->rwh_policy != u->new_policy) {
dev->rwh_policy = u->new_policy; dev->rwh_policy = u->new_policy;
super->updates_pending++; super->updates_pending++;
} }
break; break;
} }
default: default:
pr_err("error: unsuported process update type:(type: %d)\n", t ype); pr_err("error: unsupported process update type:(type: %d)\n", t ype);
} }
} }
static struct mdinfo *get_spares_for_grow(struct supertype *st); static struct mdinfo *get_spares_for_grow(struct supertype *st);
static int imsm_prepare_update(struct supertype *st, static int imsm_prepare_update(struct supertype *st,
struct metadata_update *update) struct metadata_update *update)
{ {
/** /**
* Allocate space to hold new disk entries, raid-device entries or a new * Allocate space to hold new disk entries, raid-device entries or a new
skipping to change at line 10294 skipping to change at line 10517
continue; continue;
entry->disk_ordinal--; entry->disk_ordinal--;
} }
mpb->num_disks--; mpb->num_disks--;
super->updates_pending++; super->updates_pending++;
if (*dlp) { if (*dlp) {
struct dl *dl = *dlp; struct dl *dl = *dlp;
*dlp = (*dlp)->next; *dlp = (*dlp)->next;
__free_imsm_disk(dl); __free_imsm_disk(dl, 1);
}
}
static void close_targets(int *targets, int new_disks)
{
int i;
if (!targets)
return;
for (i = 0; i < new_disks; i++) {
if (targets[i] >= 0) {
close(targets[i]);
targets[i] = -1;
}
} }
} }
static int imsm_get_allowed_degradation(int level, int raid_disks, static int imsm_get_allowed_degradation(int level, int raid_disks,
struct intel_super *super, struct intel_super *super,
struct imsm_dev *dev) struct imsm_dev *dev)
{ {
switch (level) { switch (level) {
case 1: case 1:
case 10:{ case 10:{
skipping to change at line 10367 skipping to change at line 10575
case 5: case 5:
return 1; return 1;
case 6: case 6:
return 2; return 2;
default: default:
return 0; return 0;
} }
} }
/******************************************************************************* /*******************************************************************************
* Function: open_backup_targets
* Description: Function opens file descriptors for all devices given in
* info->devs
* Parameters:
* info : general array info
* raid_disks : number of disks
* raid_fds : table of device's file descriptors
* super : intel super for raid10 degradation check
* dev : intel device for raid10 degradation check
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
struct intel_super *super, struct imsm_dev *dev)
{
struct mdinfo *sd;
int i;
int opened = 0;
for (i = 0; i < raid_disks; i++)
raid_fds[i] = -1;
for (sd = info->devs ; sd ; sd = sd->next) {
char *dn;
if (sd->disk.state & (1<<MD_DISK_FAULTY)) {
dprintf("disk is faulty!!\n");
continue;
}
if (sd->disk.raid_disk >= raid_disks || sd->disk.raid_disk < 0)
continue;
dn = map_dev(sd->disk.major,
sd->disk.minor, 1);
raid_fds[sd->disk.raid_disk] = dev_open(dn, O_RDWR);
if (raid_fds[sd->disk.raid_disk] < 0) {
pr_err("cannot open component\n");
continue;
}
opened++;
}
/* check if maximum array degradation level is not exceeded
*/
if ((raid_disks - opened) >
imsm_get_allowed_degradation(info->new_level, raid_disks,
super, dev)) {
pr_err("Not enough disks can be opened.\n");
close_targets(raid_fds, raid_disks);
return -2;
}
return 0;
}
/*******************************************************************************
* Function: validate_container_imsm * Function: validate_container_imsm
* Description: This routine validates container after assemble, * Description: This routine validates container after assemble,
* eg. if devices in container are under the same controller. * eg. if devices in container are under the same controller.
* *
* Parameters: * Parameters:
* info : linked list with info about devices used in array * info : linked list with info about devices used in array
* Returns: * Returns:
* 1 : HBA mismatch * 1 : HBA mismatch
* 0 : Success * 0 : Success
******************************************************************************/ ******************************************************************************/
int validate_container_imsm(struct mdinfo *info) int validate_container_imsm(struct mdinfo *info)
{ {
if (check_env("IMSM_NO_PLATFORM")) if (check_env("IMSM_NO_PLATFORM"))
return 0; return 0;
struct sys_dev *idev; struct sys_dev *idev;
struct sys_dev *hba = NULL; struct sys_dev *hba = NULL;
struct sys_dev *intel_devices = find_intel_devices(); struct sys_dev *intel_devices = find_intel_devices();
char *dev_path = devt_to_devpath(makedev(info->disk.major, char *dev_path = devt_to_devpath(makedev(info->disk.major,
info->dis k.minor)); info->disk.minor), 1, NULL);
for (idev = intel_devices; idev; idev = idev->next) { for (idev = intel_devices; idev; idev = idev->next) {
if (dev_path && strstr(dev_path, idev->path)) { if (dev_path && strstr(dev_path, idev->path)) {
hba = idev; hba = idev;
break; break;
} }
} }
if (dev_path) if (dev_path)
free(dev_path); free(dev_path);
if (!hba) { if (!hba) {
pr_err("WARNING - Cannot detect HBA for device %s!\n", pr_err("WARNING - Cannot detect HBA for device %s!\n",
devid2kname(makedev(info->disk.major, info->disk. minor))); devid2kname(makedev(info->disk.major, info->disk. minor)));
return 1; return 1;
} }
const struct imsm_orom *orom = get_orom_by_device_id(hba->dev_id); const struct imsm_orom *orom = get_orom_by_device_id(hba->dev_id);
struct mdinfo *dev; struct mdinfo *dev;
for (dev = info->next; dev; dev = dev->next) { for (dev = info->next; dev; dev = dev->next) {
dev_path = devt_to_devpath(makedev(dev->disk.major, dev->disk.min dev_path = devt_to_devpath(makedev(dev->disk.major,
or)); dev->disk.minor), 1, NULL);
struct sys_dev *hba2 = NULL; struct sys_dev *hba2 = NULL;
for (idev = intel_devices; idev; idev = idev->next) { for (idev = intel_devices; idev; idev = idev->next) {
if (dev_path && strstr(dev_path, idev->path)) { if (dev_path && strstr(dev_path, idev->path)) {
hba2 = idev; hba2 = idev;
break; break;
} }
} }
if (dev_path) if (dev_path)
free(dev_path); free(dev_path);
skipping to change at line 10662 skipping to change at line 10815
* none * none
******************************************************************************/ ******************************************************************************/
void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev, void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
struct mdinfo *info) struct mdinfo *info)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
struct migr_record *migr_rec = super->migr_rec; struct migr_record *migr_rec = super->migr_rec;
int new_data_disks; int new_data_disks;
unsigned long long dsize, dev_sectors; unsigned long long dsize, dev_sectors;
long long unsigned min_dev_sectors = -1LLU; long long unsigned min_dev_sectors = -1LLU;
struct mdinfo *sd;
char nm[30];
int fd;
struct imsm_map *map_dest = get_imsm_map(dev, MAP_0); struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
struct imsm_map *map_src = get_imsm_map(dev, MAP_1); struct imsm_map *map_src = get_imsm_map(dev, MAP_1);
unsigned long long num_migr_units; unsigned long long num_migr_units;
unsigned long long array_blocks; unsigned long long array_blocks;
struct dl *dl_disk = NULL;
memset(migr_rec, 0, sizeof(struct migr_record)); memset(migr_rec, 0, sizeof(struct migr_record));
migr_rec->family_num = __cpu_to_le32(super->anchor->family_num); migr_rec->family_num = __cpu_to_le32(super->anchor->family_num);
/* only ascending reshape supported now */ /* only ascending reshape supported now */
migr_rec->ascending_migr = __cpu_to_le32(1); migr_rec->ascending_migr = __cpu_to_le32(1);
migr_rec->dest_depth_per_unit = GEN_MIGR_AREA_SIZE / migr_rec->dest_depth_per_unit = GEN_MIGR_AREA_SIZE /
max(map_dest->blocks_per_strip, map_src->blocks_per_strip); max(map_dest->blocks_per_strip, map_src->blocks_per_strip);
migr_rec->dest_depth_per_unit *= migr_rec->dest_depth_per_unit *=
skipping to change at line 10691 skipping to change at line 10842
migr_rec->blocks_per_unit = migr_rec->blocks_per_unit =
__cpu_to_le32(migr_rec->dest_depth_per_unit * new_data_disks); __cpu_to_le32(migr_rec->dest_depth_per_unit * new_data_disks);
migr_rec->dest_depth_per_unit = migr_rec->dest_depth_per_unit =
__cpu_to_le32(migr_rec->dest_depth_per_unit); __cpu_to_le32(migr_rec->dest_depth_per_unit);
array_blocks = info->component_size * new_data_disks; array_blocks = info->component_size * new_data_disks;
num_migr_units = num_migr_units =
array_blocks / __le32_to_cpu(migr_rec->blocks_per_unit); array_blocks / __le32_to_cpu(migr_rec->blocks_per_unit);
if (array_blocks % __le32_to_cpu(migr_rec->blocks_per_unit)) if (array_blocks % __le32_to_cpu(migr_rec->blocks_per_unit))
num_migr_units++; num_migr_units++;
migr_rec->num_migr_units = __cpu_to_le32(num_migr_units); set_num_migr_units(migr_rec, num_migr_units);
migr_rec->post_migr_vol_cap = dev->size_low; migr_rec->post_migr_vol_cap = dev->size_low;
migr_rec->post_migr_vol_cap_hi = dev->size_high; migr_rec->post_migr_vol_cap_hi = dev->size_high;
/* Find the smallest dev */ /* Find the smallest dev */
for (sd = info->devs ; sd ; sd = sd->next) { for (dl_disk = super->disks; dl_disk ; dl_disk = dl_disk->next) {
sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor); /* ignore spares in container */
fd = dev_open(nm, O_RDONLY); if (dl_disk->index < 0)
if (fd < 0)
continue; continue;
get_dev_size(fd, NULL, &dsize); get_dev_size(dl_disk->fd, NULL, &dsize);
dev_sectors = dsize / 512; dev_sectors = dsize / 512;
if (dev_sectors < min_dev_sectors) if (dev_sectors < min_dev_sectors)
min_dev_sectors = dev_sectors; min_dev_sectors = dev_sectors;
close(fd);
} }
migr_rec->ckpt_area_pba = __cpu_to_le32(min_dev_sectors - set_migr_chkp_area_pba(migr_rec, min_dev_sectors -
RAID_DISK_RESERVED_BLOCKS_IMSM_HI); RAID_DISK_RESERVED_BLOCKS_IMSM_HI);
write_imsm_migr_rec(st); write_imsm_migr_rec(st);
return; return;
} }
/******************************************************************************* /*******************************************************************************
* Function: save_backup_imsm * Function: save_backup_imsm
* Description: Function saves critical data stripes to Migration Copy Ar ea * Description: Function saves critical data stripes to Migration Copy Ar ea
skipping to change at line 10740 skipping to change at line 10889
*, -1 : fail *, -1 : fail
******************************************************************************/ ******************************************************************************/
int save_backup_imsm(struct supertype *st, int save_backup_imsm(struct supertype *st,
struct imsm_dev *dev, struct imsm_dev *dev,
struct mdinfo *info, struct mdinfo *info,
void *buf, void *buf,
int length) int length)
{ {
int rv = -1; int rv = -1;
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
unsigned long long *target_offsets;
int *targets;
int i; int i;
struct imsm_map *map_dest = get_imsm_map(dev, MAP_0); struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
int new_disks = map_dest->num_members; int new_disks = map_dest->num_members;
int dest_layout = 0; int dest_layout = 0;
int dest_chunk; int dest_chunk, targets[new_disks];
unsigned long long start; unsigned long long start, target_offsets[new_disks];
int data_disks = imsm_num_data_members(map_dest); int data_disks = imsm_num_data_members(map_dest);
targets = xmalloc(new_disks * sizeof(int)); for (i = 0; i < new_disks; i++) {
struct dl *dl_disk = get_imsm_dl_disk(super, i);
for (i = 0; i < new_disks; i++) if (dl_disk && is_fd_valid(dl_disk->fd))
targets[i] = -1; targets[i] = dl_disk->fd;
else
target_offsets = xcalloc(new_disks, sizeof(unsigned long long)); goto abort;
}
start = info->reshape_progress * 512; start = info->reshape_progress * 512;
for (i = 0; i < new_disks; i++) { for (i = 0; i < new_disks; i++) {
target_offsets[i] = (unsigned long long) target_offsets[i] = migr_chkp_area_pba(super->migr_rec) * 512;
__le32_to_cpu(super->migr_rec->ckpt_area_pba) * 512;
/* move back copy area adderss, it will be moved forward /* move back copy area adderss, it will be moved forward
* in restore_stripes() using start input variable * in restore_stripes() using start input variable
*/ */
target_offsets[i] -= start/data_disks; target_offsets[i] -= start/data_disks;
} }
if (open_backup_targets(info, new_disks, targets,
super, dev))
goto abort;
dest_layout = imsm_level_to_layout(map_dest->raid_level); dest_layout = imsm_level_to_layout(map_dest->raid_level);
dest_chunk = __le16_to_cpu(map_dest->blocks_per_strip) * 512; dest_chunk = __le16_to_cpu(map_dest->blocks_per_strip) * 512;
if (restore_stripes(targets, /* list of dest devices */ if (restore_stripes(targets, /* list of dest devices */
target_offsets, /* migration record offsets */ target_offsets, /* migration record offsets */
new_disks, new_disks,
dest_chunk, dest_chunk,
map_dest->raid_level, map_dest->raid_level,
dest_layout, dest_layout,
-1, /* source backup file descriptor */ -1, /* source backup file descriptor */
skipping to change at line 10793 skipping to change at line 10936
start, start,
length, length,
buf) != 0) { buf) != 0) {
pr_err("Error restoring stripes\n"); pr_err("Error restoring stripes\n");
goto abort; goto abort;
} }
rv = 0; rv = 0;
abort: abort:
if (targets) {
close_targets(targets, new_disks);
free(targets);
}
free(target_offsets);
return rv; return rv;
} }
/******************************************************************************* /*******************************************************************************
* Function: save_checkpoint_imsm * Function: save_checkpoint_imsm
* Description: Function called for current unit status update * Description: Function called for current unit status update
* in the migration record. It writes it to disk. * in the migration record. It writes it to disk.
* Parameters: * Parameters:
* super : imsm internal array info * super : imsm internal array info
* info : general array info * info : general array info
skipping to change at line 10821 skipping to change at line 10958
* 1: failure * 1: failure
* 2: failure, means no valid migration record * 2: failure, means no valid migration record
* / no general migration in progress / * / no general migration in progress /
******************************************************************************/ ******************************************************************************/
int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state) int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
unsigned long long blocks_per_unit; unsigned long long blocks_per_unit;
unsigned long long curr_migr_unit; unsigned long long curr_migr_unit;
if (load_imsm_migr_rec(super, info) != 0) { if (load_imsm_migr_rec(super) != 0) {
dprintf("imsm: ERROR: Cannot read migration record for checkpoint save.\n"); dprintf("imsm: ERROR: Cannot read migration record for checkpoint save.\n");
return 1; return 1;
} }
blocks_per_unit = __le32_to_cpu(super->migr_rec->blocks_per_unit); blocks_per_unit = __le32_to_cpu(super->migr_rec->blocks_per_unit);
if (blocks_per_unit == 0) { if (blocks_per_unit == 0) {
dprintf("imsm: no migration in progress.\n"); dprintf("imsm: no migration in progress.\n");
return 2; return 2;
} }
curr_migr_unit = info->reshape_progress / blocks_per_unit; curr_migr_unit = info->reshape_progress / blocks_per_unit;
/* check if array is alligned to copy area /* check if array is alligned to copy area
* if it is not alligned, add one to current migration unit value * if it is not alligned, add one to current migration unit value
* this can happend on array reshape finish only * this can happend on array reshape finish only
*/ */
if (info->reshape_progress % blocks_per_unit) if (info->reshape_progress % blocks_per_unit)
curr_migr_unit++; curr_migr_unit++;
super->migr_rec->curr_migr_unit = set_current_migr_unit(super->migr_rec, curr_migr_unit);
__cpu_to_le32(curr_migr_unit);
super->migr_rec->rec_status = __cpu_to_le32(state); super->migr_rec->rec_status = __cpu_to_le32(state);
super->migr_rec->dest_1st_member_lba = set_migr_dest_1st_member_lba(super->migr_rec,
__cpu_to_le32(curr_migr_unit * super->migr_rec->dest_depth_per_unit * curr_migr_unit);
__le32_to_cpu(super->migr_rec->dest_depth_per_unit)
);
if (write_imsm_migr_rec(st) < 0) { if (write_imsm_migr_rec(st) < 0) {
dprintf("imsm: Cannot write migration record outside backup area\ n"); dprintf("imsm: Cannot write migration record outside backup area\ n");
return 1; return 1;
} }
return 0; return 0;
} }
/******************************************************************************* /*******************************************************************************
* Function: recover_backup_imsm * Function: recover_backup_imsm
skipping to change at line 10873 skipping to change at line 11009
******************************************************************************/ ******************************************************************************/
int recover_backup_imsm(struct supertype *st, struct mdinfo *info) int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
{ {
struct intel_super *super = st->sb; struct intel_super *super = st->sb;
struct migr_record *migr_rec = super->migr_rec; struct migr_record *migr_rec = super->migr_rec;
struct imsm_map *map_dest; struct imsm_map *map_dest;
struct intel_dev *id = NULL; struct intel_dev *id = NULL;
unsigned long long read_offset; unsigned long long read_offset;
unsigned long long write_offset; unsigned long long write_offset;
unsigned unit_len; unsigned unit_len;
int *targets = NULL; int new_disks, err;
int new_disks, i, err;
char *buf = NULL; char *buf = NULL;
int retval = 1; int retval = 1;
unsigned int sector_size = super->sector_size; unsigned int sector_size = super->sector_size;
unsigned long curr_migr_unit = __le32_to_cpu(migr_rec->curr_migr_unit); unsigned long long curr_migr_unit = current_migr_unit(migr_rec);
unsigned long num_migr_units = __le32_to_cpu(migr_rec->num_migr_units); unsigned long long num_migr_units = get_num_migr_units(migr_rec);
char buffer[20]; char buffer[20];
int skipped_disks = 0; int skipped_disks = 0;
struct dl *dl_disk;
err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, 20); err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, 20);
if (err < 1) if (err < 1)
return 1; return 1;
/* recover data only during assemblation */ /* recover data only during assemblation */
if (strncmp(buffer, "inactive", 8) != 0) if (strncmp(buffer, "inactive", 8) != 0)
return 0; return 0;
/* no data to recover */ /* no data to recover */
if (__le32_to_cpu(migr_rec->rec_status) == UNIT_SRC_NORMAL) if (__le32_to_cpu(migr_rec->rec_status) == UNIT_SRC_NORMAL)
skipping to change at line 10906 skipping to change at line 11042
/* find device during reshape */ /* find device during reshape */
for (id = super->devlist; id; id = id->next) for (id = super->devlist; id; id = id->next)
if (is_gen_migration(id->dev)) if (is_gen_migration(id->dev))
break; break;
if (id == NULL) if (id == NULL)
return 1; return 1;
map_dest = get_imsm_map(id->dev, MAP_0); map_dest = get_imsm_map(id->dev, MAP_0);
new_disks = map_dest->num_members; new_disks = map_dest->num_members;
read_offset = (unsigned long long) read_offset = migr_chkp_area_pba(migr_rec) * 512;
__le32_to_cpu(migr_rec->ckpt_area_pba) * 512;
write_offset = ((unsigned long long) write_offset = (migr_dest_1st_member_lba(migr_rec) +
__le32_to_cpu(migr_rec->dest_1st_member_lba) +
pba_of_lba0(map_dest)) * 512; pba_of_lba0(map_dest)) * 512;
unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512; unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
if (posix_memalign((void **)&buf, sector_size, unit_len) != 0) if (posix_memalign((void **)&buf, sector_size, unit_len) != 0)
goto abort; goto abort;
targets = xcalloc(new_disks, sizeof(int));
if (open_backup_targets(info, new_disks, targets, super, id->dev)) { for (dl_disk = super->disks; dl_disk; dl_disk = dl_disk->next) {
pr_err("Cannot open some devices belonging to array.\n"); if (dl_disk->index < 0)
goto abort; continue;
}
for (i = 0; i < new_disks; i++) { if (!is_fd_valid(dl_disk->fd)) {
if (targets[i] < 0) {
skipped_disks++; skipped_disks++;
continue; continue;
} }
if (lseek64(targets[i], read_offset, SEEK_SET) < 0) { if (lseek64(dl_disk->fd, read_offset, SEEK_SET) < 0) {
pr_err("Cannot seek to block: %s\n", pr_err("Cannot seek to block: %s\n",
strerror(errno)); strerror(errno));
skipped_disks++; skipped_disks++;
continue; continue;
} }
if ((unsigned)read(targets[i], buf, unit_len) != unit_len) { if (read(dl_disk->fd, buf, unit_len) != (ssize_t)unit_len) {
pr_err("Cannot read copy area block: %s\n", pr_err("Cannot read copy area block: %s\n",
strerror(errno)); strerror(errno));
skipped_disks++; skipped_disks++;
continue; continue;
} }
if (lseek64(targets[i], write_offset, SEEK_SET) < 0) { if (lseek64(dl_disk->fd, write_offset, SEEK_SET) < 0) {
pr_err("Cannot seek to block: %s\n", pr_err("Cannot seek to block: %s\n",
strerror(errno)); strerror(errno));
skipped_disks++; skipped_disks++;
continue; continue;
} }
if ((unsigned)write(targets[i], buf, unit_len) != unit_len) { if (write(dl_disk->fd, buf, unit_len) != (ssize_t)unit_len) {
pr_err("Cannot restore block: %s\n", pr_err("Cannot restore block: %s\n",
strerror(errno)); strerror(errno));
skipped_disks++; skipped_disks++;
continue; continue;
} }
} }
if (skipped_disks > imsm_get_allowed_degradation(info->new_level, if (skipped_disks > imsm_get_allowed_degradation(info->new_level,
new_disks, new_disks,
super, super,
skipping to change at line 10970 skipping to change at line 11101
} }
if (save_checkpoint_imsm(st, info, UNIT_SRC_NORMAL)) { if (save_checkpoint_imsm(st, info, UNIT_SRC_NORMAL)) {
/* ignore error == 2, this can mean end of reshape here /* ignore error == 2, this can mean end of reshape here
*/ */
dprintf("imsm: Cannot write checkpoint to migration record (UNIT_ SRC_NORMAL) during restart\n"); dprintf("imsm: Cannot write checkpoint to migration record (UNIT_ SRC_NORMAL) during restart\n");
} else } else
retval = 0; retval = 0;
abort: abort:
if (targets) {
for (i = 0; i < new_disks; i++)
if (targets[i])
close(targets[i]);
free(targets);
}
free(buf); free(buf);
return retval; return retval;
} }
static char disk_by_path[] = "/dev/disk/by-path/"; static char disk_by_path[] = "/dev/disk/by-path/";
static const char *imsm_get_disk_controller_domain(const char *path) static const char *imsm_get_disk_controller_domain(const char *path)
{ {
char disk_path[PATH_MAX]; char disk_path[PATH_MAX];
char *drv=NULL; char *drv=NULL;
struct stat st; struct stat st;
strcpy(disk_path, disk_by_path); strcpy(disk_path, disk_by_path);
strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1); strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1);
if (stat(disk_path, &st) == 0) { if (stat(disk_path, &st) == 0) {
struct sys_dev* hba; struct sys_dev* hba;
char *path; char *path;
path = devt_to_devpath(st.st_rdev); path = devt_to_devpath(st.st_rdev, 1, NULL);
if (path == NULL) if (path == NULL)
return "unknown"; return "unknown";
hba = find_disk_attached_hba(-1, path); hba = find_disk_attached_hba(-1, path);
if (hba && hba->type == SYS_DEV_SAS) if (hba && hba->type == SYS_DEV_SAS)
drv = "isci"; drv = "isci";
else if (hba && hba->type == SYS_DEV_SATA) else if (hba && hba->type == SYS_DEV_SATA)
drv = "ahci"; drv = "ahci";
else if (hba && hba->type == SYS_DEV_VMD) else if (hba && hba->type == SYS_DEV_VMD)
drv = "vmd"; drv = "vmd";
else if (hba && hba->type == SYS_DEV_NVME) else if (hba && hba->type == SYS_DEV_NVME)
skipping to change at line 11605 skipping to change at line 11730
/* and possibly remotely */ /* and possibly remotely */
if (st->update_tail) if (st->update_tail)
append_metadata_update(st, u, append_metadata_update(st, u,
sizeof(struct imsm_update_takeover)); sizeof(struct imsm_update_takeover));
else else
free(u); free(u);
return 0; return 0;
} }
/* Flush size update if size calculated by num_data_stripes is higher than
* imsm_dev_size to eliminate differences during reshape.
* Mdmon will recalculate them correctly.
* If subarray index is not set then check whole container.
* Returns:
* 0 - no error occurred
* 1 - error detected
*/
static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
{
struct intel_super *super = st->sb;
int tmp = super->current_vol;
int ret_val = 1;
int i;
for (i = 0; i < super->anchor->num_raid_devs; i++) {
if (subarray_index >= 0 && i != subarray_index)
continue;
super->current_vol = i;
struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
struct imsm_map *map = get_imsm_map(dev, MAP_0);
unsigned int disc_count = imsm_num_data_members(map);
struct geo_params geo;
struct imsm_update_size_change *update;
unsigned long long calc_size = per_dev_array_size(map) * disc_cou
nt;
unsigned long long d_size = imsm_dev_size(dev);
int u_size;
if (calc_size == d_size || dev->vol.migr_type == MIGR_GEN_MIGR)
continue;
/* There is a difference, confirm that imsm_dev_size is
* smaller and push update.
*/
if (d_size > calc_size) {
pr_err("imsm: dev size of subarray %d is incorrect\n",
i);
goto exit;
}
memset(&geo, 0, sizeof(struct geo_params));
geo.size = d_size;
u_size = imsm_create_metadata_update_for_size_change(st, &geo,
&update);
if (u_size < 1) {
dprintf("imsm: Cannot prepare size change update\n");
goto exit;
}
imsm_update_metadata_locally(st, update, u_size);
if (st->update_tail) {
append_metadata_update(st, update, u_size);
flush_metadata_updates(st);
st->update_tail = &st->updates;
} else {
imsm_sync_metadata(st);
}
free(update);
}
ret_val = 0;
exit:
super->current_vol = tmp;
return ret_val;
}
static int imsm_reshape_super(struct supertype *st, unsigned long long size, static int imsm_reshape_super(struct supertype *st, unsigned long long size,
int level, int level,
int layout, int chunksize, int raid_disks, int layout, int chunksize, int raid_disks,
int delta_disks, char *backup, char *dev, int delta_disks, char *backup, char *dev,
int direction, int verbose) int direction, int verbose)
{ {
int ret_val = 1; int ret_val = 1;
struct geo_params geo; struct geo_params geo;
dprintf("(enter)\n"); dprintf("(enter)\n");
skipping to change at line 11641 skipping to change at line 11830
if (strcmp(st->container_devnm, st->devnm) == 0) { if (strcmp(st->container_devnm, st->devnm) == 0) {
/* On container level we can only increase number of devices. */ /* On container level we can only increase number of devices. */
dprintf("imsm: info: Container operation\n"); dprintf("imsm: info: Container operation\n");
int old_raid_disks = 0; int old_raid_disks = 0;
if (imsm_reshape_is_allowed_on_container( if (imsm_reshape_is_allowed_on_container(
st, &geo, &old_raid_disks, direction)) { st, &geo, &old_raid_disks, direction)) {
struct imsm_update_reshape *u = NULL; struct imsm_update_reshape *u = NULL;
int len; int len;
if (imsm_fix_size_mismatch(st, -1)) {
dprintf("imsm: Cannot fix size mismatch\n");
goto exit_imsm_reshape_super;
}
len = imsm_create_metadata_update_for_reshape( len = imsm_create_metadata_update_for_reshape(
st, &geo, old_raid_disks, &u); st, &geo, old_raid_disks, &u);
if (len <= 0) { if (len <= 0) {
dprintf("imsm: Cannot prepare update\n"); dprintf("imsm: Cannot prepare update\n");
goto exit_imsm_reshape_super; goto exit_imsm_reshape_super;
} }
ret_val = 0; ret_val = 0;
/* update metadata locally */ /* update metadata locally */
skipping to change at line 11787 skipping to change at line 11981
******************************************************************************/ ******************************************************************************/
int wait_for_reshape_imsm(struct mdinfo *sra, int ndata) int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
{ {
int fd = sysfs_get_fd(sra, NULL, "sync_completed"); int fd = sysfs_get_fd(sra, NULL, "sync_completed");
int retry = 3; int retry = 3;
unsigned long long completed; unsigned long long completed;
/* to_complete : new sync_max position */ /* to_complete : new sync_max position */
unsigned long long to_complete = sra->reshape_progress; unsigned long long to_complete = sra->reshape_progress;
unsigned long long position_to_set = to_complete / ndata; unsigned long long position_to_set = to_complete / ndata;
if (fd < 0) { if (!is_fd_valid(fd)) {
dprintf("cannot open reshape_position\n"); dprintf("cannot open reshape_position\n");
return 1; return 1;
} }
do { do {
if (sysfs_fd_get_ll(fd, &completed) < 0) { if (sysfs_fd_get_ll(fd, &completed) < 0) {
if (!retry) { if (!retry) {
dprintf("cannot read reshape_position (no reshape in progres)\n"); dprintf("cannot read reshape_position (no reshape in progres)\n");
close(fd); close(fd);
return 1; return 1;
skipping to change at line 11874 skipping to change at line 12068
rv = sysfs_get_ll(info, NULL, "degraded", &new_degraded); rv = sysfs_get_ll(info, NULL, "degraded", &new_degraded);
if (rv == -1 || (new_degraded != (unsigned long long)degraded)) { if (rv == -1 || (new_degraded != (unsigned long long)degraded)) {
/* check each device to ensure it is still working */ /* check each device to ensure it is still working */
struct mdinfo *sd; struct mdinfo *sd;
new_degraded = 0; new_degraded = 0;
for (sd = info->devs ; sd ; sd = sd->next) { for (sd = info->devs ; sd ; sd = sd->next) {
if (sd->disk.state & (1<<MD_DISK_FAULTY)) if (sd->disk.state & (1<<MD_DISK_FAULTY))
continue; continue;
if (sd->disk.state & (1<<MD_DISK_SYNC)) { if (sd->disk.state & (1<<MD_DISK_SYNC)) {
char sbuf[100]; char sbuf[100];
int raid_disk = sd->disk.raid_disk;
if (sysfs_get_str(info, if (sysfs_get_str(info,
sd, "state", sbuf, sizeof(sbuf)) < 0 || sd, "state", sbuf, sizeof(sbuf)) < 0 ||
strstr(sbuf, "faulty") || strstr(sbuf, "faulty") ||
strstr(sbuf, "in_sync") == NULL) { strstr(sbuf, "in_sync") == NULL) {
/* this device is dead */ /* this device is dead */
sd->disk.state = (1<<MD_DISK_FAULTY); sd->disk.state = (1<<MD_DISK_FAULTY);
if (sd->disk.raid_disk >= 0 && if (raid_disk >= 0)
sources[sd->disk.raid_disk] >= 0) { close_fd(&sources[raid_disk]);
close(sources[
sd->disk.raid_disk]);
sources[sd->disk.raid_disk] =
-1;
}
new_degraded++; new_degraded++;
} }
} }
} }
} }
return new_degraded; return new_degraded;
} }
/******************************************************************************* /*******************************************************************************
skipping to change at line 11943 skipping to change at line 12133
char *buf = NULL; char *buf = NULL;
unsigned int buf_size; /* [bytes] */ unsigned int buf_size; /* [bytes] */
unsigned long long max_position; /* array size [bytes] */ unsigned long long max_position; /* array size [bytes] */
unsigned long long next_step; /* [blocks]/[bytes] */ unsigned long long next_step; /* [blocks]/[bytes] */
unsigned long long old_data_stripe_length; unsigned long long old_data_stripe_length;
unsigned long long start_src; /* [bytes] */ unsigned long long start_src; /* [bytes] */
unsigned long long start; /* [bytes] */ unsigned long long start; /* [bytes] */
unsigned long long start_buf_shift; /* [bytes] */ unsigned long long start_buf_shift; /* [bytes] */
int degraded = 0; int degraded = 0;
int source_layout = 0; int source_layout = 0;
int subarray_index = -1;
if (!sra) if (!sra)
return ret_val; return ret_val;
if (!fds || !offsets) if (!fds || !offsets)
goto abort; goto abort;
/* Find volume during the reshape */ /* Find volume during the reshape */
for (dv = super->devlist; dv; dv = dv->next) { for (dv = super->devlist; dv; dv = dv->next) {
if (dv->dev->vol.migr_type == MIGR_GEN_MIGR && if (dv->dev->vol.migr_type == MIGR_GEN_MIGR &&
dv->dev->vol.migr_state == 1) { dv->dev->vol.migr_state == 1) {
dev = dv->dev; dev = dv->dev;
migr_vol_qan++; migr_vol_qan++;
subarray_index = dv->index;
} }
} }
/* Only one volume can migrate at the same time */ /* Only one volume can migrate at the same time */
if (migr_vol_qan != 1) { if (migr_vol_qan != 1) {
pr_err("%s", migr_vol_qan ? pr_err("%s", migr_vol_qan ?
"Number of migrating volumes greater than 1\n" : "Number of migrating volumes greater than 1\n" :
"There is no volume during migrationg\n"); "There is no volume during migrationg\n");
goto abort; goto abort;
} }
skipping to change at line 12013 skipping to change at line 12205
/* add space for stripe alignment */ /* add space for stripe alignment */
buf_size += old_data_stripe_length; buf_size += old_data_stripe_length;
if (posix_memalign((void **)&buf, MAX_SECTOR_SIZE, buf_size)) { if (posix_memalign((void **)&buf, MAX_SECTOR_SIZE, buf_size)) {
dprintf("imsm: Cannot allocate checkpoint buffer\n"); dprintf("imsm: Cannot allocate checkpoint buffer\n");
goto abort; goto abort;
} }
max_position = sra->component_size * ndata; max_position = sra->component_size * ndata;
source_layout = imsm_level_to_layout(map_src->raid_level); source_layout = imsm_level_to_layout(map_src->raid_level);
while (__le32_to_cpu(migr_rec->curr_migr_unit) < while (current_migr_unit(migr_rec) <
__le32_to_cpu(migr_rec->num_migr_units)) { get_num_migr_units(migr_rec)) {
/* current reshape position [blocks] */ /* current reshape position [blocks] */
unsigned long long current_position = unsigned long long current_position =
__le32_to_cpu(migr_rec->blocks_per_unit) __le32_to_cpu(migr_rec->blocks_per_unit)
* __le32_to_cpu(migr_rec->curr_migr_unit); * current_migr_unit(migr_rec);
unsigned long long border; unsigned long long border;
/* Check that array hasn't become failed. /* Check that array hasn't become failed.
*/ */
degraded = check_degradation_change(sra, fds, degraded); degraded = check_degradation_change(sra, fds, degraded);
if (degraded > 1) { if (degraded > 1) {
dprintf("imsm: Abort reshape due to degradation level (%i )\n", degraded); dprintf("imsm: Abort reshape due to degradation level (%i )\n", degraded);
goto abort; goto abort;
} }
skipping to change at line 12140 skipping to change at line 12332
SEEK_SET) >= 0) { SEEK_SET) >= 0) {
if ((unsigned int)write(d->fd, super->migr_rec_buf, if ((unsigned int)write(d->fd, super->migr_rec_buf,
MIGR_REC_BUF_SECTORS*sector_size) != MIGR_REC_BUF_SECTORS*sector_size) !=
MIGR_REC_BUF_SECTORS*sector_size) MIGR_REC_BUF_SECTORS*sector_size)
perror("Write migr_rec failed"); perror("Write migr_rec failed");
} }
} }
/* return '1' if done */ /* return '1' if done */
ret_val = 1; ret_val = 1;
/* After the reshape eliminate size mismatch in metadata.
* Don't update md/component_size here, volume hasn't
* to take whole space. It is allowed by kernel.
* md/component_size will be set propoperly after next assembly.
*/
imsm_fix_size_mismatch(st, subarray_index);
abort: abort:
free(buf); free(buf);
/* See Grow.c: abort_reshape() for further explanation */ /* See Grow.c: abort_reshape() for further explanation */
sysfs_set_num(sra, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL); sysfs_set_num(sra, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL);
sysfs_set_num(sra, NULL, "suspend_hi", 0); sysfs_set_num(sra, NULL, "suspend_hi", 0);
sysfs_set_num(sra, NULL, "suspend_lo", 0); sysfs_set_num(sra, NULL, "suspend_lo", 0);
return ret_val; return ret_val;
} }
/*******************************************************************************
* Function: calculate_bitmap_min_chunksize
* Description: Calculates the minimal valid bitmap chunk size
* Parameters:
* max_bits : indicate how many bits can be used for the bitmap
* data_area_size : the size of the data area covered by the bitmap
*
* Returns:
* The bitmap chunk size
******************************************************************************/
static unsigned long long
calculate_bitmap_min_chunksize(unsigned long long max_bits,
unsigned long long data_area_size)
{
unsigned long long min_chunk =
4096; /* sub-page chunks don't work yet.. */
unsigned long long bits = data_area_size / min_chunk + 1;
while (bits > max_bits) {
min_chunk *= 2;
bits = (bits + 1) / 2;
}
return min_chunk;
}
/*******************************************************************************
* Function: calculate_bitmap_chunksize
* Description: Calculates the bitmap chunk size for the given device
* Parameters:
* st : supertype information
* dev : device for the bitmap
*
* Returns:
* The bitmap chunk size
******************************************************************************/
static unsigned long long calculate_bitmap_chunksize(struct supertype *st,
struct imsm_dev *dev)
{
struct intel_super *super = st->sb;
unsigned long long min_chunksize;
unsigned long long result = IMSM_DEFAULT_BITMAP_CHUNKSIZE;
size_t dev_size = imsm_dev_size(dev);
min_chunksize = calculate_bitmap_min_chunksize(
IMSM_BITMAP_AREA_SIZE * super->sector_size, dev_size);
if (result < min_chunksize)
result = min_chunksize;
return result;
}
/*******************************************************************************
* Function: init_bitmap_header
* Description: Initialize the bitmap header structure
* Parameters:
* st : supertype information
* bms : bitmap header struct to initialize
* dev : device for the bitmap
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int init_bitmap_header(struct supertype *st, struct bitmap_super_s *bms,
struct imsm_dev *dev)
{
int vol_uuid[4];
if (!bms || !dev)
return -1;
bms->magic = __cpu_to_le32(BITMAP_MAGIC);
bms->version = __cpu_to_le32(BITMAP_MAJOR_HI);
bms->daemon_sleep = __cpu_to_le32(IMSM_DEFAULT_BITMAP_DAEMON_SLEEP);
bms->sync_size = __cpu_to_le64(IMSM_BITMAP_AREA_SIZE);
bms->write_behind = __cpu_to_le32(0);
uuid_from_super_imsm(st, vol_uuid);
memcpy(bms->uuid, vol_uuid, 16);
bms->chunksize = calculate_bitmap_chunksize(st, dev);
return 0;
}
/*******************************************************************************
* Function: validate_internal_bitmap_for_drive
* Description: Verify if the bitmap header for a given drive.
* Parameters:
* st : supertype information
* offset : The offset from the beginning of the drive where to look for
* the bitmap header.
* d : the drive info
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int validate_internal_bitmap_for_drive(struct supertype *st,
unsigned long long offset,
struct dl *d)
{
struct intel_super *super = st->sb;
int ret = -1;
int vol_uuid[4];
bitmap_super_t *bms;
int fd;
if (!d)
return -1;
void *read_buf;
if (posix_memalign(&read_buf, MAX_SECTOR_SIZE, IMSM_BITMAP_HEADER_SIZE))
return -1;
fd = d->fd;
if (!is_fd_valid(fd)) {
fd = open(d->devname, O_RDONLY, 0);
if (!is_fd_valid(fd)) {
dprintf("cannot open the device %s\n", d->devname);
goto abort;
}
}
if (lseek64(fd, offset * super->sector_size, SEEK_SET) < 0)
goto abort;
if (read(fd, read_buf, IMSM_BITMAP_HEADER_SIZE) !=
IMSM_BITMAP_HEADER_SIZE)
goto abort;
uuid_from_super_imsm(st, vol_uuid);
bms = read_buf;
if ((bms->magic != __cpu_to_le32(BITMAP_MAGIC)) ||
(bms->version != __cpu_to_le32(BITMAP_MAJOR_HI)) ||
(!same_uuid((int *)bms->uuid, vol_uuid, st->ss->swapuuid))) {
dprintf("wrong bitmap header detected\n");
goto abort;
}
ret = 0;
abort:
if (!is_fd_valid(d->fd))
close_fd(&fd);
if (read_buf)
free(read_buf);
return ret;
}
/*******************************************************************************
* Function: validate_internal_bitmap_imsm
* Description: Verify if the bitmap header is in place and with proper d
ata.
* Parameters:
* st : supertype information
*
* Returns:
* 0 : success or device w/o RWH_BITMAP
* -1 : fail
******************************************************************************/
static int validate_internal_bitmap_imsm(struct supertype *st)
{
struct intel_super *super = st->sb;
struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
unsigned long long offset;
struct dl *d;
if (!dev)
return -1;
if (dev->rwh_policy != RWH_BITMAP)
return 0;
offset = get_bitmap_header_sector(super, super->current_vol);
for (d = super->disks; d; d = d->next) {
if (d->index < 0 || is_failed(&d->disk))
continue;
if (validate_internal_bitmap_for_drive(st, offset, d)) {
pr_err("imsm: bitmap validation failed\n");
return -1;
}
}
return 0;
}
/*******************************************************************************
* Function: add_internal_bitmap_imsm
* Description: Mark the volume to use the bitmap and updates the chunk s
ize value.
* Parameters:
* st : supertype information
* chunkp : bitmap chunk size
* delay : not used for imsm
* write_behind : not used for imsm
* size : not used for imsm
* may_change : not used for imsm
* amajor : not used for imsm
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int add_internal_bitmap_imsm(struct supertype *st, int *chunkp,
int delay, int write_behind,
unsigned long long size, int may_change,
int amajor)
{
struct intel_super *super = st->sb;
int vol_idx = super->current_vol;
struct imsm_dev *dev;
if (!super->devlist || vol_idx == -1 || !chunkp)
return -1;
dev = get_imsm_dev(super, vol_idx);
if (!dev) {
dprintf("cannot find the device for volume index %d\n",
vol_idx);
return -1;
}
dev->rwh_policy = RWH_BITMAP;
*chunkp = calculate_bitmap_chunksize(st, dev);
return 0;
}
/*******************************************************************************
* Function: locate_bitmap_imsm
* Description: Seek 'fd' to start of write-intent-bitmap.
* Parameters:
* st : supertype information
* fd : file descriptor for the device
* node_num : not used for imsm
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int locate_bitmap_imsm(struct supertype *st, int fd, int node_num)
{
struct intel_super *super = st->sb;
unsigned long long offset;
int vol_idx = super->current_vol;
if (!super->devlist || vol_idx == -1)
return -1;
offset = get_bitmap_header_sector(super, super->current_vol);
dprintf("bitmap header offset is %llu\n", offset);
lseek64(fd, offset << 9, 0);
return 0;
}
/*******************************************************************************
* Function: write_init_bitmap_imsm
* Description: Write a bitmap header and prepares the area for the bitma
p.
* Parameters:
* st : supertype information
* fd : file descriptor for the device
* update : not used for imsm
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int write_init_bitmap_imsm(struct supertype *st, int fd,
enum bitmap_update update)
{
struct intel_super *super = st->sb;
int vol_idx = super->current_vol;
int ret = 0;
unsigned long long offset;
bitmap_super_t bms = { 0 };
size_t written = 0;
size_t to_write;
ssize_t rv_num;
void *buf;
if (!super->devlist || !super->sector_size || vol_idx == -1)
return -1;
struct imsm_dev *dev = get_imsm_dev(super, vol_idx);
/* first clear the space for bitmap header */
unsigned long long bitmap_area_start =
get_bitmap_header_sector(super, vol_idx);
dprintf("zeroing area start (%llu) and size (%u)\n", bitmap_area_start,
IMSM_BITMAP_AND_HEADER_SIZE / super->sector_size);
if (zero_disk_range(fd, bitmap_area_start,
IMSM_BITMAP_HEADER_SIZE / super->sector_size)) {
pr_err("imsm: cannot zeroing the space for the bitmap\n");
return -1;
}
/* The bitmap area should be filled with "1"s to perform initial
* synchronization.
*/
if (posix_memalign(&buf, MAX_SECTOR_SIZE, MAX_SECTOR_SIZE))
return -1;
memset(buf, 0xFF, MAX_SECTOR_SIZE);
offset = get_bitmap_sector(super, vol_idx);
lseek64(fd, offset << 9, 0);
while (written < IMSM_BITMAP_AREA_SIZE) {
to_write = IMSM_BITMAP_AREA_SIZE - written;
if (to_write > MAX_SECTOR_SIZE)
to_write = MAX_SECTOR_SIZE;
rv_num = write(fd, buf, MAX_SECTOR_SIZE);
if (rv_num != MAX_SECTOR_SIZE) {
ret = -1;
dprintf("cannot initialize bitmap area\n");
goto abort;
}
written += rv_num;
}
/* write a bitmap header */
init_bitmap_header(st, &bms, dev);
memset(buf, 0, MAX_SECTOR_SIZE);
memcpy(buf, &bms, sizeof(bitmap_super_t));
if (locate_bitmap_imsm(st, fd, 0)) {
ret = -1;
dprintf("cannot locate the bitmap\n");
goto abort;
}
if (write(fd, buf, MAX_SECTOR_SIZE) != MAX_SECTOR_SIZE) {
ret = -1;
dprintf("cannot write the bitmap header\n");
goto abort;
}
fsync(fd);
abort:
free(buf);
return ret;
}
/*******************************************************************************
* Function: is_vol_to_setup_bitmap
* Description: Checks if a bitmap should be activated on the dev.
* Parameters:
* info : info about the volume to setup the bitmap
* dev : the device to check against bitmap creation
*
* Returns:
* 0 : bitmap should be set up on the device
* -1 : otherwise
******************************************************************************/
static int is_vol_to_setup_bitmap(struct mdinfo *info, struct imsm_dev *dev)
{
if (!dev || !info)
return -1;
if ((strcmp((char *)dev->volume, info->name) == 0) &&
(dev->rwh_policy == RWH_BITMAP))
return -1;
return 0;
}
/*******************************************************************************
* Function: set_bitmap_sysfs
* Description: Set the sysfs atributes of a given volume to activate the
bitmap.
* Parameters:
* info : info about the volume where the bitmap should be setup
* chunksize : bitmap chunk size
* location : location of the bitmap
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int set_bitmap_sysfs(struct mdinfo *info, unsigned long long chunksize,
char *location)
{
/* The bitmap/metadata is set to external to allow changing of value for
* bitmap/location. When external is used, the kernel will treat an offse
t
* related to the device's first lba (in opposition to the "internal" cas
e
* when this value is related to the beginning of the superblock).
*/
if (sysfs_set_str(info, NULL, "bitmap/metadata", "external")) {
dprintf("failed to set bitmap/metadata\n");
return -1;
}
/* It can only be changed when no bitmap is active.
* Should be bigger than 512 and must be power of 2.
* It is expecting the value in bytes.
*/
if (sysfs_set_num(info, NULL, "bitmap/chunksize",
__cpu_to_le32(chunksize))) {
dprintf("failed to set bitmap/chunksize\n");
return -1;
}
/* It is expecting the value in sectors. */
if (sysfs_set_num(info, NULL, "bitmap/space",
__cpu_to_le64(IMSM_BITMAP_AREA_SIZE)))
{
dprintf("failed to set bitmap/space\n");
return -1;
}
/* Determines the delay between the bitmap updates.
* It is expecting the value in seconds.
*/
if (sysfs_set_num(info, NULL, "bitmap/time_base",
__cpu_to_le64(IMSM_DEFAULT_BITMAP_DAEMO
N_SLEEP))) {
dprintf("failed to set bitmap/time_base\n");
return -1;
}
/* It is expecting the value in sectors with a sign at the beginning. */
if (sysfs_set_str(info, NULL, "bitmap/location", location)) {
dprintf("failed to set bitmap/location\n");
return -1;
}
return 0;
}
/*******************************************************************************
* Function: set_bitmap_imsm
* Description: Setup the bitmap for the given volume
* Parameters:
* st : supertype information
* info : info about the volume where the bitmap should be setup
*
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
static int set_bitmap_imsm(struct supertype *st, struct mdinfo *info)
{
struct intel_super *super = st->sb;
int prev_current_vol = super->current_vol;
struct imsm_dev *dev;
int ret = -1;
char location[16] = "";
unsigned long long chunksize;
struct intel_dev *dev_it;
for (dev_it = super->devlist; dev_it; dev_it = dev_it->next) {
super->current_vol = dev_it->index;
dev = get_imsm_dev(super, super->current_vol);
if (is_vol_to_setup_bitmap(info, dev)) {
if (validate_internal_bitmap_imsm(st)) {
dprintf("bitmap header validation failed\n");
goto abort;
}
chunksize = calculate_bitmap_chunksize(st, dev);
dprintf("chunk size is %llu\n", chunksize);
snprintf(location, sizeof(location), "+%llu",
get_bitmap_sector(super, super->current_vol));
dprintf("bitmap offset is %s\n", location);
if (set_bitmap_sysfs(info, chunksize, location)) {
dprintf("cannot setup the bitmap\n");
goto abort;
}
}
}
ret = 0;
abort:
super->current_vol = prev_current_vol;
return ret;
}
struct superswitch super_imsm = { struct superswitch super_imsm = {
.examine_super = examine_super_imsm, .examine_super = examine_super_imsm,
.brief_examine_super = brief_examine_super_imsm, .brief_examine_super = brief_examine_super_imsm,
.brief_examine_subarrays = brief_examine_subarrays_imsm, .brief_examine_subarrays = brief_examine_subarrays_imsm,
.export_examine_super = export_examine_super_imsm, .export_examine_super = export_examine_super_imsm,
.detail_super = detail_super_imsm, .detail_super = detail_super_imsm,
.brief_detail_super = brief_detail_super_imsm, .brief_detail_super = brief_detail_super_imsm,
.write_init_super = write_init_super_imsm, .write_init_super = write_init_super_imsm,
.validate_geometry = validate_geometry_imsm, .validate_geometry = validate_geometry_imsm,
.add_to_super = add_to_super_imsm, .add_to_super = add_to_super_imsm,
skipping to change at line 12171 skipping to change at line 12850
.detail_platform = detail_platform_imsm, .detail_platform = detail_platform_imsm,
.export_detail_platform = export_detail_platform_imsm, .export_detail_platform = export_detail_platform_imsm,
.kill_subarray = kill_subarray_imsm, .kill_subarray = kill_subarray_imsm,
.update_subarray = update_subarray_imsm, .update_subarray = update_subarray_imsm,
.load_container = load_container_imsm, .load_container = load_container_imsm,
.default_geometry = default_geometry_imsm, .default_geometry = default_geometry_imsm,
.get_disk_controller_domain = imsm_get_disk_controller_domain, .get_disk_controller_domain = imsm_get_disk_controller_domain,
.reshape_super = imsm_reshape_super, .reshape_super = imsm_reshape_super,
.manage_reshape = imsm_manage_reshape, .manage_reshape = imsm_manage_reshape,
.recover_backup = recover_backup_imsm, .recover_backup = recover_backup_imsm,
.copy_metadata = copy_metadata_imsm,
.examine_badblocks = examine_badblocks_imsm, .examine_badblocks = examine_badblocks_imsm,
.match_home = match_home_imsm, .match_home = match_home_imsm,
.uuid_from_super= uuid_from_super_imsm, .uuid_from_super= uuid_from_super_imsm,
.getinfo_super = getinfo_super_imsm, .getinfo_super = getinfo_super_imsm,
.getinfo_super_disks = getinfo_super_disks_imsm, .getinfo_super_disks = getinfo_super_disks_imsm,
.update_super = update_super_imsm, .update_super = update_super_imsm,
.avail_size = avail_size_imsm, .avail_size = avail_size_imsm,
.get_spare_criteria = get_spare_criteria_imsm, .get_spare_criteria = get_spare_criteria_imsm,
.compare_super = compare_super_imsm, .compare_super = compare_super_imsm,
.load_super = load_super_imsm, .load_super = load_super_imsm,
.init_super = init_super_imsm, .init_super = init_super_imsm,
.store_super = store_super_imsm, .store_super = store_super_imsm,
.free_super = free_super_imsm, .free_super = free_super_imsm,
.match_metadata_desc = match_metadata_desc_imsm, .match_metadata_desc = match_metadata_desc_imsm,
.container_content = container_content_imsm, .container_content = container_content_imsm,
.validate_container = validate_container_imsm, .validate_container = validate_container_imsm,
.add_internal_bitmap = add_internal_bitmap_imsm,
.locate_bitmap = locate_bitmap_imsm,
.write_bitmap = write_init_bitmap_imsm,
.set_bitmap = set_bitmap_imsm,
.write_init_ppl = write_init_ppl_imsm, .write_init_ppl = write_init_ppl_imsm,
.validate_ppl = validate_ppl_imsm, .validate_ppl = validate_ppl_imsm,
.external = 1, .external = 1,
.name = "imsm", .name = "imsm",
/* for mdmon */ /* for mdmon */
.open_new = imsm_open_new, .open_new = imsm_open_new,
.set_array_state= imsm_set_array_state, .set_array_state= imsm_set_array_state,
.set_disk = imsm_set_disk, .set_disk = imsm_set_disk,
 End of changes. 324 change blocks. 
785 lines changed or deleted 1479 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)