imsm: record new bad block in bad block log
Check for a duplicate first or try to merge it with existing bad block. If block range exceeds BBM_LOG_MAX_LBA_ENTRY_VAL (256) blocks, it must be split into multiple ranges. Fail if maximum number of bad blocks has been already reached. Signed-off-by: Tomasz Majchrzak <tomasz.majchrzak@intel.com> Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
This commit is contained in:
parent
b12796be0c
commit
6f50473f25
142
super-intel.c
142
super-intel.c
|
@ -824,6 +824,86 @@ static __u32 get_imsm_bbm_log_size(struct bbm_log *log)
|
|||
sizeof(log->entry_count) +
|
||||
log->entry_count * sizeof(struct bbm_log_entry);
|
||||
}
|
||||
|
||||
/* check if bad block is not partially stored in bbm log */
|
||||
static int is_stored_in_bbm(struct bbm_log *log, const __u8 idx, const unsigned
|
||||
long long sector, const int length, __u32 *pos)
|
||||
{
|
||||
__u32 i;
|
||||
|
||||
for (i = *pos; i < log->entry_count; i++) {
|
||||
struct bbm_log_entry *entry = &log->marked_block_entries[i];
|
||||
unsigned long long bb_start;
|
||||
unsigned long long bb_end;
|
||||
|
||||
bb_start = __le48_to_cpu(&entry->defective_block_start);
|
||||
bb_end = bb_start + (entry->marked_count + 1);
|
||||
|
||||
if ((entry->disk_ordinal == idx) && (bb_start >= sector) &&
|
||||
(bb_end <= sector + length)) {
|
||||
*pos = i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* record new bad block in bbm log */
|
||||
static int record_new_badblock(struct bbm_log *log, const __u8 idx, unsigned
|
||||
long long sector, int length)
|
||||
{
|
||||
int new_bb = 0;
|
||||
__u32 pos = 0;
|
||||
struct bbm_log_entry *entry = NULL;
|
||||
|
||||
while (is_stored_in_bbm(log, idx, sector, length, &pos)) {
|
||||
struct bbm_log_entry *e = &log->marked_block_entries[pos];
|
||||
|
||||
if ((e->marked_count + 1 == BBM_LOG_MAX_LBA_ENTRY_VAL) &&
|
||||
(__le48_to_cpu(&e->defective_block_start) == sector)) {
|
||||
sector += BBM_LOG_MAX_LBA_ENTRY_VAL;
|
||||
length -= BBM_LOG_MAX_LBA_ENTRY_VAL;
|
||||
pos = pos + 1;
|
||||
continue;
|
||||
}
|
||||
entry = e;
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
int cnt = (length <= BBM_LOG_MAX_LBA_ENTRY_VAL) ? length :
|
||||
BBM_LOG_MAX_LBA_ENTRY_VAL;
|
||||
entry->defective_block_start = __cpu_to_le48(sector);
|
||||
entry->marked_count = cnt - 1;
|
||||
if (cnt == length)
|
||||
return 1;
|
||||
sector += cnt;
|
||||
length -= cnt;
|
||||
}
|
||||
|
||||
new_bb = ROUND_UP(length, BBM_LOG_MAX_LBA_ENTRY_VAL) /
|
||||
BBM_LOG_MAX_LBA_ENTRY_VAL;
|
||||
if (log->entry_count + new_bb > BBM_LOG_MAX_ENTRIES)
|
||||
return 0;
|
||||
|
||||
while (length > 0) {
|
||||
int cnt = (length <= BBM_LOG_MAX_LBA_ENTRY_VAL) ? length :
|
||||
BBM_LOG_MAX_LBA_ENTRY_VAL;
|
||||
struct bbm_log_entry *entry =
|
||||
&log->marked_block_entries[log->entry_count];
|
||||
|
||||
entry->defective_block_start = __cpu_to_le48(sector);
|
||||
entry->marked_count = cnt - 1;
|
||||
entry->disk_ordinal = idx;
|
||||
|
||||
sector += cnt;
|
||||
length -= cnt;
|
||||
|
||||
log->entry_count++;
|
||||
}
|
||||
|
||||
return new_bb;
|
||||
}
|
||||
#endif /* MDASSEMBLE */
|
||||
|
||||
/* allocate and load BBM log from metadata */
|
||||
|
@ -7726,6 +7806,25 @@ skip_mark_checkpoint:
|
|||
return consistent;
|
||||
}
|
||||
|
||||
static int imsm_disk_slot_to_ord(struct active_array *a, int slot)
|
||||
{
|
||||
int inst = a->info.container_member;
|
||||
struct intel_super *super = a->container->sb;
|
||||
struct imsm_dev *dev = get_imsm_dev(super, inst);
|
||||
struct imsm_map *map = get_imsm_map(dev, MAP_0);
|
||||
|
||||
if (slot > map->num_members) {
|
||||
pr_err("imsm: imsm_disk_slot_to_ord %d out of range 0..%d\n",
|
||||
slot, map->num_members - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (slot < 0)
|
||||
return -1;
|
||||
|
||||
return get_imsm_ord_tbl_ent(dev, slot, MAP_0);
|
||||
}
|
||||
|
||||
static void imsm_set_disk(struct active_array *a, int n, int state)
|
||||
{
|
||||
int inst = a->info.container_member;
|
||||
|
@ -7736,19 +7835,14 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
|
|||
struct mdinfo *mdi;
|
||||
int recovery_not_finished = 0;
|
||||
int failed;
|
||||
__u32 ord;
|
||||
int ord;
|
||||
__u8 map_state;
|
||||
|
||||
if (n > map->num_members)
|
||||
pr_err("imsm: set_disk %d out of range 0..%d\n",
|
||||
n, map->num_members - 1);
|
||||
|
||||
if (n < 0)
|
||||
ord = imsm_disk_slot_to_ord(a, n);
|
||||
if (ord < 0)
|
||||
return;
|
||||
|
||||
dprintf("imsm: set_disk %d:%x\n", n, state);
|
||||
|
||||
ord = get_imsm_ord_tbl_ent(dev, n, MAP_0);
|
||||
disk = get_imsm_disk(super, ord_to_idx(ord));
|
||||
|
||||
/* check for new failures */
|
||||
|
@ -9672,6 +9766,37 @@ int validate_container_imsm(struct mdinfo *info)
|
|||
return 0;
|
||||
}
|
||||
#ifndef MDASSEMBLE
|
||||
/*******************************************************************************
|
||||
* Function: imsm_record_badblock
|
||||
* Description: This routine stores new bad block record in BBM log
|
||||
*
|
||||
* Parameters:
|
||||
* a : array containing a bad block
|
||||
* slot : disk number containing a bad block
|
||||
* sector : bad block sector
|
||||
* length : bad block sectors range
|
||||
* Returns:
|
||||
* 1 : Success
|
||||
* 0 : Error
|
||||
******************************************************************************/
|
||||
static int imsm_record_badblock(struct active_array *a, int slot,
|
||||
unsigned long long sector, int length)
|
||||
{
|
||||
struct intel_super *super = a->container->sb;
|
||||
int ord;
|
||||
int ret;
|
||||
|
||||
ord = imsm_disk_slot_to_ord(a, slot);
|
||||
if (ord < 0)
|
||||
return 0;
|
||||
|
||||
ret = record_new_badblock(super->bbm_log, ord_to_idx(ord), sector,
|
||||
length);
|
||||
if (ret)
|
||||
super->updates_pending++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* Function: init_migr_record_imsm
|
||||
* Description: Function inits imsm migration record
|
||||
|
@ -11225,5 +11350,6 @@ struct superswitch super_imsm = {
|
|||
.activate_spare = imsm_activate_spare,
|
||||
.process_update = imsm_process_update,
|
||||
.prepare_update = imsm_prepare_update,
|
||||
.record_bad_block = imsm_record_badblock,
|
||||
#endif /* MDASSEMBLE */
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue