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, §or_size); | if (!get_dev_sector_size(fd, NULL, §or_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 |