[PATCH 07/11] UBI: Fastmap: Fix scan regression

From: Richard Weinberger
Date: Fri Jun 29 2012 - 11:14:44 EST


... resuse scan_peb(), don't rescan the first 64 PEBs.

Signed-off-by: Richard Weinberger <richard@xxxxxx>
---
drivers/mtd/ubi/attach.c | 134 ++++++++++++++++++++++++++++++---------------
drivers/mtd/ubi/fastmap.c | 64 ++--------------------
drivers/mtd/ubi/ubi.h | 2 +-
3 files changed, 95 insertions(+), 105 deletions(-)

diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
index 9878cc2..bc1e4bf 100644
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -817,10 +817,11 @@ out_unlock:
* successfully handled and a negative error code in case of failure.
*/
static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
- int pnum)
+ int pnum, int *vid, unsigned long long *sqnum,
+ int find_fastmap)
{
long long uninitialized_var(ec);
- int err, bitflips = 0, vol_id, ec_err = 0;
+ int err, bitflips = 0, vol_id = -1, ec_err = 0;

dbg_bld("scan PEB %d", pnum);

@@ -991,8 +992,13 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
}

vol_id = be32_to_cpu(vidh->vol_id);
+ if (vid)
+ *vid = vol_id;
+ if (sqnum)
+ *sqnum = be64_to_cpu(vidh->sqnum);

- if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
+ if (!find_fastmap &&
+ (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID)) {
int lnum = be32_to_cpu(vidh->lnum);

/* Unsupported internal volume */
@@ -1221,7 +1227,7 @@ static void destroy_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
* information about it in form of a "struct ubi_attach_info" object. In case
* of failure, an error code is returned.
*/
-static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai)
+static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai, int start)
{
int err, pnum;
struct rb_node *rb1, *rb2;
@@ -1229,11 +1235,6 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai)
struct ubi_ainf_peb *aeb;

err = -ENOMEM;
- ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
- sizeof(struct ubi_ainf_peb),
- 0, 0, NULL);
- if (!ai->aeb_slab_cache)
- goto out_ai;

ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ech)
@@ -1243,11 +1244,11 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai)
if (!vidh)
goto out_ech;

- for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+ for (pnum = start; pnum < ubi->peb_count; pnum++) {
cond_resched();

dbg_gen("process PEB %d", pnum);
- err = scan_peb(ubi, ai, pnum);
+ err = scan_peb(ubi, ai, pnum, NULL, NULL, 0);
if (err < 0)
goto out_vidh;
}
@@ -1303,17 +1304,77 @@ out_ai:
return err;
}

+/**
+ * scan_fastmap - try to find a fastmap and attach from it.
+ * @ubi: UBI device description object
+ * @ai: attach info object
+ */
+static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info *ai)
+{
+ int err, pnum, fm_anchor = -1;
+ unsigned long long max_sqnum = 0;
+
+ err = -ENOMEM;
+
+ ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ if (!ech)
+ goto out_ai;
+
+ vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+ if (!vidh)
+ goto out_ech;
+
+ for (pnum = 0; pnum < UBI_FM_MAX_START; pnum++) {
+ int vol_id = -1;
+ unsigned long long sqnum = -1;
+ cond_resched();
+
+ dbg_gen("process PEB %d", pnum);
+ err = scan_peb(ubi, ai, pnum, &vol_id, &sqnum, 1);
+ if (err < 0)
+ goto out_vidh;
+
+ if (vol_id == UBI_FM_SB_VOLUME_ID && sqnum > max_sqnum) {
+ max_sqnum = sqnum;
+ fm_anchor = pnum;
+ }
+ }
+
+ ubi_free_vid_hdr(ubi, vidh);
+ kfree(ech);
+
+ if (fm_anchor < 0)
+ return UBI_NO_FASTMAP;
+
+ return ubi_scan_fastmap(ubi, ai, fm_anchor);
+
+out_vidh:
+ ubi_free_vid_hdr(ubi, vidh);
+out_ech:
+ kfree(ech);
+out_ai:
+ destroy_ai(ubi, ai);
+ return err;
+}
static struct ubi_attach_info *alloc_ai(void)
{
- static struct ubi_attach_info *ai;
+ struct ubi_attach_info *ai;

ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
- if (ai) {
- INIT_LIST_HEAD(&ai->corr);
- INIT_LIST_HEAD(&ai->free);
- INIT_LIST_HEAD(&ai->erase);
- INIT_LIST_HEAD(&ai->alien);
- ai->volumes = RB_ROOT;
+ if (!ai)
+ return ai;
+
+ INIT_LIST_HEAD(&ai->corr);
+ INIT_LIST_HEAD(&ai->free);
+ INIT_LIST_HEAD(&ai->erase);
+ INIT_LIST_HEAD(&ai->alien);
+ ai->volumes = RB_ROOT;
+ ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
+ sizeof(struct ubi_ainf_peb),
+ 0, 0, NULL);
+ if (!ai->aeb_slab_cache) {
+ kfree(ai);
+ ai = NULL;
}

return ai;
@@ -1337,35 +1398,18 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
return -ENOMEM;

if (force_scan)
- err = scan_all(ubi, ai);
+ err = scan_all(ubi, ai, 0);
else {
- /* TODO: this is a regression. If I have an old image, and I do
- * not want to use fastmap, I will be forced to waste time for
- * useless scan of 64 first eraseblocks. Not good.
- *
- * Can you teach ubi_scan_fastmap() to use 'scan_peb()'
- * function for scanning and build normal ai information? If it
- * finds fastmap - it can destroy the collected ai. If it does
- * not find, it returns ai. Then you just confinue scanning.
- *
- * I buess what we'll need is:
- * 1. scan_all() -> scan_range(..., int pnum1, int pnum2);
- * 2. ubi_scan_fastmap() returns the pnum of the last scanned
- * eraseblock if fastmap was not found;
- * Also 'ubi_scan_fastmap()' uses scan_peb() for scanning.
- * 3. You call 'scan_range(..., pnum, c->peb_cnt - 1)' and
- * it continues.
- *
- * And no regressions.
- */
- err = ubi_scan_fastmap(ubi, ai);
+ err = scan_fast(ubi, ai);
if (err > 0) {
- destroy_ai(ubi, ai);
- ai = alloc_ai();
- if (!ai)
- return -ENOMEM;
+ if (err != UBI_NO_FASTMAP) {
+ destroy_ai(ubi, ai);
+ ai = alloc_ai();
+ if (!ai)
+ return -ENOMEM;
+ }

- err = scan_all(ubi, ai);
+ err = scan_all(ubi, ai, UBI_FM_MAX_START);
}
}

@@ -1398,7 +1442,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
if (!scan_ai)
goto out_wl;

- err = scan_all(ubi, scan_ai);
+ err = scan_all(ubi, scan_ai, 0);
if (err) {
kfree(scan_ai);
goto out_wl;
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index 9b4fd34..6276039 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -819,82 +819,28 @@ fail:
}

/**
- * ubi_find_fastmap - searches the first UBI_FM_MAX_START PEBs for the
- * fastmap super block.
- * @ubi: UBI device object
- * @fm_start: Pointer where the fastmap suber block PEB number will be stored.
- *
- * Returns:
- * - 0 on success: (fm_start contains suber block PEB number)
- * - < 0 on failure (fm_start is -1)
- */
-static int ubi_find_fastmap(struct ubi_device *ubi, int *fm_start)
-{
- int i, ret = -ENOENT;
- struct ubi_vid_hdr *vhdr;
- unsigned long long max_sqnum = 0, sqnum;
-
- vhdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
- if (!vhdr)
- return -ENOMEM;
-
- *fm_start = -1;
- for (i = 0; i < UBI_FM_MAX_START; i++) {
- if (ubi_io_is_bad(ubi, i))
- continue;
-
- ret = ubi_io_read_vid_hdr(ubi, i, vhdr, 0);
- if (ret < 0)
- goto out;
- else if (ret > 0 && ret != UBI_IO_BITFLIPS)
- continue;
-
- if (be32_to_cpu(vhdr->vol_id) == UBI_FM_SB_VOLUME_ID) {
- sqnum = be64_to_cpu(vhdr->sqnum);
- dbg_bld("found a fastmap super block at PEB %i " \
- "sqnum: %llu", i, sqnum);
-
- if (sqnum > max_sqnum) {
- max_sqnum = sqnum;
- *fm_start = i;
- }
- }
- }
-
- if (*fm_start > -1)
- ret = 0;
-out:
- ubi_free_vid_hdr(ubi, vhdr);
- return ret;
-}
-
-/**
* ubi_scan_fastmap - scan the fastmap.
* @ubi: UBI device object
* @ai: UBI attach info to be filled
+ * @fm_anchor: The fastmap starts at this PEB
*
* Returns 0 on success, UBI_NO_FASTMAP if no fastmap was found,
* UBI_BAD_FASTMAP if one was found but is not usable.
* < 0 indicates an internal error.
*/
-int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai)
+int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
+ int fm_anchor)
{
struct ubi_fm_sb *fmsb;
struct ubi_vid_hdr *vh;
struct ubi_ec_hdr *ech;
struct ubi_fastmap_layout *fm;
- int i, used_blocks, pnum, sb_pnum = 0, ret = 0;
+ int i, used_blocks, pnum, ret = 0;
void *fm_raw = NULL;
size_t fm_size;
__be32 crc, tmp_crc;
unsigned long long sqnum = 0;

- ret = ubi_find_fastmap(ubi, &sb_pnum);
- if (ret)
- return ret;
- if (sb_pnum == -1)
- return UBI_NO_FASTMAP;
-
fmsb = kmalloc(sizeof(*fmsb), GFP_KERNEL);
if (!fmsb) {
ret = -ENOMEM;
@@ -908,7 +854,7 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai)
goto free_raw;
}

- ret = ubi_io_read(ubi, fmsb, sb_pnum, ubi->leb_start, sizeof(*fmsb));
+ ret = ubi_io_read(ubi, fmsb, fm_anchor, ubi->leb_start, sizeof(*fmsb));
if (ret && ret != UBI_IO_BITFLIPS) {
kfree(fmsb);
kfree(fm);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 8e2592d..fef9e92 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -816,7 +816,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,

/* fastmap.c */
int ubi_update_fastmap(struct ubi_device *ubi);
-int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai);
+int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, int fm_anchor);

/*
* ubi_rb_for_each_entry - walk an RB-tree.
--
1.7.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/