UBI: Fastmap: Add self check to detect absent PEBs
This self check allows Fastmap to detect absent PEBs while writing a new fastmap to the MTD device. It will help to find implementation issues in Fastmap. Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
ee59ba8b06
commit
daef3dd1f0
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012 Linutronix GmbH
|
* Copyright (c) 2012 Linutronix GmbH
|
||||||
|
* Copyright (c) 2014 sigma star gmbh
|
||||||
* Author: Richard Weinberger <richard@nod.at>
|
* Author: Richard Weinberger <richard@nod.at>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -16,6 +17,69 @@
|
||||||
#include <linux/crc32.h>
|
#include <linux/crc32.h>
|
||||||
#include "ubi.h"
|
#include "ubi.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init_seen - allocate memory for used for debugging.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
*/
|
||||||
|
static inline int *init_seen(struct ubi_device *ubi)
|
||||||
|
{
|
||||||
|
int *ret;
|
||||||
|
|
||||||
|
if (!ubi_dbg_chk_fastmap(ubi))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret = kcalloc(ubi->peb_count, sizeof(int), GFP_KERNEL);
|
||||||
|
if (!ret)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* free_seen - free the seen logic integer array.
|
||||||
|
* @seen: integer array of @ubi->peb_count size
|
||||||
|
*/
|
||||||
|
static inline void free_seen(int *seen)
|
||||||
|
{
|
||||||
|
kfree(seen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set_seen - mark a PEB as seen.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
* @pnum: The PEB to be makred as seen
|
||||||
|
* @seen: integer array of @ubi->peb_count size
|
||||||
|
*/
|
||||||
|
static inline void set_seen(struct ubi_device *ubi, int pnum, int *seen)
|
||||||
|
{
|
||||||
|
if (!ubi_dbg_chk_fastmap(ubi) || !seen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
seen[pnum] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* self_check_seen - check whether all PEB have been seen by fastmap.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
* @seen: integer array of @ubi->peb_count size
|
||||||
|
*/
|
||||||
|
static int self_check_seen(struct ubi_device *ubi, int *seen)
|
||||||
|
{
|
||||||
|
int pnum, ret = 0;
|
||||||
|
|
||||||
|
if (!ubi_dbg_chk_fastmap(ubi) || !seen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
|
||||||
|
if (!seen[pnum] && ubi->lookuptbl[pnum]) {
|
||||||
|
ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ubi_calc_fm_size - calculates the fastmap size in bytes for an UBI device.
|
* ubi_calc_fm_size - calculates the fastmap size in bytes for an UBI device.
|
||||||
* @ubi: UBI device description object
|
* @ubi: UBI device description object
|
||||||
|
@ -1030,6 +1094,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
struct ubi_work *ubi_wrk;
|
struct ubi_work *ubi_wrk;
|
||||||
int ret, i, j, free_peb_count, used_peb_count, vol_count;
|
int ret, i, j, free_peb_count, used_peb_count, vol_count;
|
||||||
int scrub_peb_count, erase_peb_count;
|
int scrub_peb_count, erase_peb_count;
|
||||||
|
int *seen_pebs = NULL;
|
||||||
|
|
||||||
fm_raw = ubi->fm_buf;
|
fm_raw = ubi->fm_buf;
|
||||||
memset(ubi->fm_buf, 0, ubi->fm_size);
|
memset(ubi->fm_buf, 0, ubi->fm_size);
|
||||||
|
@ -1046,6 +1111,12 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seen_pebs = init_seen(ubi);
|
||||||
|
if (IS_ERR(seen_pebs)) {
|
||||||
|
ret = PTR_ERR(seen_pebs);
|
||||||
|
goto out_kfree;
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock(&ubi->volumes_lock);
|
spin_lock(&ubi->volumes_lock);
|
||||||
spin_lock(&ubi->wl_lock);
|
spin_lock(&ubi->wl_lock);
|
||||||
|
|
||||||
|
@ -1076,8 +1147,10 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
fmpl1->size = cpu_to_be16(ubi->fm_pool.size);
|
fmpl1->size = cpu_to_be16(ubi->fm_pool.size);
|
||||||
fmpl1->max_size = cpu_to_be16(ubi->fm_pool.max_size);
|
fmpl1->max_size = cpu_to_be16(ubi->fm_pool.max_size);
|
||||||
|
|
||||||
for (i = 0; i < ubi->fm_pool.size; i++)
|
for (i = 0; i < ubi->fm_pool.size; i++) {
|
||||||
fmpl1->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]);
|
fmpl1->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]);
|
||||||
|
set_seen(ubi, ubi->fm_pool.pebs[i], seen_pebs);
|
||||||
|
}
|
||||||
|
|
||||||
fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
|
fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
|
||||||
fm_pos += sizeof(*fmpl2);
|
fm_pos += sizeof(*fmpl2);
|
||||||
|
@ -1085,14 +1158,17 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
fmpl2->size = cpu_to_be16(ubi->fm_wl_pool.size);
|
fmpl2->size = cpu_to_be16(ubi->fm_wl_pool.size);
|
||||||
fmpl2->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size);
|
fmpl2->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size);
|
||||||
|
|
||||||
for (i = 0; i < ubi->fm_wl_pool.size; i++)
|
for (i = 0; i < ubi->fm_wl_pool.size; i++) {
|
||||||
fmpl2->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]);
|
fmpl2->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]);
|
||||||
|
set_seen(ubi, ubi->fm_wl_pool.pebs[i], seen_pebs);
|
||||||
|
}
|
||||||
|
|
||||||
for (node = rb_first(&ubi->free); node; node = rb_next(node)) {
|
for (node = rb_first(&ubi->free); node; node = rb_next(node)) {
|
||||||
wl_e = rb_entry(node, struct ubi_wl_entry, u.rb);
|
wl_e = rb_entry(node, struct ubi_wl_entry, u.rb);
|
||||||
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
|
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
|
||||||
|
|
||||||
fec->pnum = cpu_to_be32(wl_e->pnum);
|
fec->pnum = cpu_to_be32(wl_e->pnum);
|
||||||
|
set_seen(ubi, wl_e->pnum, seen_pebs);
|
||||||
fec->ec = cpu_to_be32(wl_e->ec);
|
fec->ec = cpu_to_be32(wl_e->ec);
|
||||||
|
|
||||||
free_peb_count++;
|
free_peb_count++;
|
||||||
|
@ -1106,6 +1182,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
|
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
|
||||||
|
|
||||||
fec->pnum = cpu_to_be32(wl_e->pnum);
|
fec->pnum = cpu_to_be32(wl_e->pnum);
|
||||||
|
set_seen(ubi, wl_e->pnum, seen_pebs);
|
||||||
fec->ec = cpu_to_be32(wl_e->ec);
|
fec->ec = cpu_to_be32(wl_e->ec);
|
||||||
|
|
||||||
used_peb_count++;
|
used_peb_count++;
|
||||||
|
@ -1132,6 +1209,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
|
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
|
||||||
|
|
||||||
fec->pnum = cpu_to_be32(wl_e->pnum);
|
fec->pnum = cpu_to_be32(wl_e->pnum);
|
||||||
|
set_seen(ubi, wl_e->pnum, seen_pebs);
|
||||||
fec->ec = cpu_to_be32(wl_e->ec);
|
fec->ec = cpu_to_be32(wl_e->ec);
|
||||||
|
|
||||||
scrub_peb_count++;
|
scrub_peb_count++;
|
||||||
|
@ -1149,6 +1227,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
|
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
|
||||||
|
|
||||||
fec->pnum = cpu_to_be32(wl_e->pnum);
|
fec->pnum = cpu_to_be32(wl_e->pnum);
|
||||||
|
set_seen(ubi, wl_e->pnum, seen_pebs);
|
||||||
fec->ec = cpu_to_be32(wl_e->ec);
|
fec->ec = cpu_to_be32(wl_e->ec);
|
||||||
|
|
||||||
erase_peb_count++;
|
erase_peb_count++;
|
||||||
|
@ -1208,6 +1287,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
|
|
||||||
for (i = 0; i < new_fm->used_blocks; i++) {
|
for (i = 0; i < new_fm->used_blocks; i++) {
|
||||||
fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i]->pnum);
|
fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i]->pnum);
|
||||||
|
set_seen(ubi, new_fm->e[i]->pnum, seen_pebs);
|
||||||
fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i]->ec);
|
fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i]->ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1241,11 +1321,13 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
|
||||||
ubi_assert(new_fm);
|
ubi_assert(new_fm);
|
||||||
ubi->fm = new_fm;
|
ubi->fm = new_fm;
|
||||||
|
|
||||||
|
ret = self_check_seen(ubi, seen_pebs);
|
||||||
dbg_bld("fastmap written!");
|
dbg_bld("fastmap written!");
|
||||||
|
|
||||||
out_kfree:
|
out_kfree:
|
||||||
ubi_free_vid_hdr(ubi, avhdr);
|
ubi_free_vid_hdr(ubi, avhdr);
|
||||||
ubi_free_vid_hdr(ubi, dvhdr);
|
ubi_free_vid_hdr(ubi, dvhdr);
|
||||||
|
free_seen(seen_pebs);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue