*/
#include <linux/crc32.h>
+#include <linux/bitmap.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)
+static inline unsigned long *init_seen(struct ubi_device *ubi)
{
- int *ret;
+ unsigned long *ret;
if (!ubi_dbg_chk_fastmap(ubi))
return NULL;
- ret = kcalloc(ubi->peb_count, sizeof(int), GFP_KERNEL);
+ ret = kcalloc(BITS_TO_LONGS(ubi->peb_count), sizeof(unsigned long),
+ GFP_KERNEL);
if (!ret)
return ERR_PTR(-ENOMEM);
* free_seen - free the seen logic integer array.
* @seen: integer array of @ubi->peb_count size
*/
-static inline void free_seen(int *seen)
+static inline void free_seen(unsigned long *seen)
{
kfree(seen);
}
* @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)
+static inline void set_seen(struct ubi_device *ubi, int pnum, unsigned long *seen)
{
if (!ubi_dbg_chk_fastmap(ubi) || !seen)
return;
- seen[pnum] = 1;
+ set_bit(pnum, seen);
}
/**
* @ubi: UBI device description object
* @seen: integer array of @ubi->peb_count size
*/
-static int self_check_seen(struct ubi_device *ubi, int *seen)
+static int self_check_seen(struct ubi_device *ubi, unsigned long *seen)
{
int pnum, ret = 0;
return 0;
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
- if (!seen[pnum] && ubi->lookuptbl[pnum]) {
+ if (test_bit(pnum, seen) && ubi->lookuptbl[pnum]) {
ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum);
ret = -EINVAL;
}
{
struct ubi_ainf_peb *aeb;
- aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+ aeb = ubi_alloc_aeb(ai, pnum, ec);
if (!aeb)
return -ENOMEM;
- aeb->pnum = pnum;
- aeb->ec = ec;
aeb->lnum = -1;
aeb->scrub = scrub;
aeb->copy_flag = aeb->sqnum = 0;
int last_eb_bytes)
{
struct ubi_ainf_volume *av;
- struct rb_node **p = &ai->volumes.rb_node, *parent = NULL;
-
- while (*p) {
- parent = *p;
- av = rb_entry(parent, struct ubi_ainf_volume, rb);
-
- if (vol_id > av->vol_id)
- p = &(*p)->rb_left;
- else if (vol_id < av->vol_id)
- p = &(*p)->rb_right;
- else
- return ERR_PTR(-EINVAL);
- }
- av = kmalloc(sizeof(struct ubi_ainf_volume), GFP_KERNEL);
- if (!av)
- goto out;
+ av = ubi_add_av(ai, vol_id);
+ if (IS_ERR(av))
+ return av;
- av->highest_lnum = av->leb_count = av->used_ebs = 0;
- av->vol_id = vol_id;
av->data_pad = data_pad;
av->last_data_size = last_eb_bytes;
av->compat = 0;
av->vol_type = vol_type;
- av->root = RB_ROOT;
if (av->vol_type == UBI_STATIC_VOLUME)
av->used_ebs = used_ebs;
dbg_bld("found volume (ID %i)", vol_id);
-
- rb_link_node(&av->rb, parent, p);
- rb_insert_color(&av->rb, &ai->volumes);
-
-out:
return av;
}
*/
if (aeb->pnum == new_aeb->pnum) {
ubi_assert(aeb->lnum == new_aeb->lnum);
- kmem_cache_free(ai->aeb_slab_cache, new_aeb);
+ ubi_free_aeb(ai, new_aeb);
return 0;
}
/* new_aeb is newer */
if (cmp_res & 1) {
- victim = kmem_cache_alloc(ai->aeb_slab_cache,
- GFP_KERNEL);
+ victim = ubi_alloc_aeb(ai, aeb->ec, aeb->pnum);
if (!victim)
return -ENOMEM;
- victim->ec = aeb->ec;
- victim->pnum = aeb->pnum;
list_add_tail(&victim->u.list, &ai->erase);
if (av->highest_lnum == be32_to_cpu(new_vh->lnum))
aeb->pnum = new_aeb->pnum;
aeb->copy_flag = new_vh->copy_flag;
aeb->scrub = new_aeb->scrub;
- kmem_cache_free(ai->aeb_slab_cache, new_aeb);
+ ubi_free_aeb(ai, new_aeb);
/* new_aeb is older */
} else {
struct ubi_vid_hdr *new_vh,
struct ubi_ainf_peb *new_aeb)
{
- struct ubi_ainf_volume *av, *tmp_av = NULL;
- struct rb_node **p = &ai->volumes.rb_node, *parent = NULL;
- int found = 0;
+ int vol_id = be32_to_cpu(new_vh->vol_id);
+ struct ubi_ainf_volume *av;
- if (be32_to_cpu(new_vh->vol_id) == UBI_FM_SB_VOLUME_ID ||
- be32_to_cpu(new_vh->vol_id) == UBI_FM_DATA_VOLUME_ID) {
- kmem_cache_free(ai->aeb_slab_cache, new_aeb);
+ if (vol_id == UBI_FM_SB_VOLUME_ID || vol_id == UBI_FM_DATA_VOLUME_ID) {
+ ubi_free_aeb(ai, new_aeb);
return 0;
}
/* Find the volume this SEB belongs to */
- while (*p) {
- parent = *p;
- tmp_av = rb_entry(parent, struct ubi_ainf_volume, rb);
-
- if (be32_to_cpu(new_vh->vol_id) > tmp_av->vol_id)
- p = &(*p)->rb_left;
- else if (be32_to_cpu(new_vh->vol_id) < tmp_av->vol_id)
- p = &(*p)->rb_right;
- else {
- found = 1;
- break;
- }
- }
-
- if (found)
- av = tmp_av;
- else {
+ av = ubi_find_av(ai, vol_id);
+ if (!av) {
ubi_err(ubi, "orphaned volume in fastmap pool!");
- kmem_cache_free(ai->aeb_slab_cache, new_aeb);
+ ubi_free_aeb(ai, new_aeb);
return UBI_BAD_FASTMAP;
}
- ubi_assert(be32_to_cpu(new_vh->vol_id) == av->vol_id);
+ ubi_assert(vol_id == av->vol_id);
return update_vol(ubi, ai, av, new_vh, new_aeb);
}
struct rb_node *node, *node2;
struct ubi_ainf_peb *aeb;
- for (node = rb_first(&ai->volumes); node; node = rb_next(node)) {
- av = rb_entry(node, struct ubi_ainf_volume, rb);
-
- for (node2 = rb_first(&av->root); node2;
- node2 = rb_next(node2)) {
- aeb = rb_entry(node2, struct ubi_ainf_peb, u.rb);
+ ubi_rb_for_each_entry(node, av, &ai->volumes, rb) {
+ ubi_rb_for_each_entry(node2, aeb, &av->root, u.rb) {
if (aeb->pnum == pnum) {
rb_erase(&aeb->u.rb, &av->root);
av->leb_count--;
- kmem_cache_free(ai->aeb_slab_cache, aeb);
+ ubi_free_aeb(ai, aeb);
return;
}
}
unsigned long long ec = be64_to_cpu(ech->ec);
unmap_peb(ai, pnum);
dbg_bld("Adding PEB to free: %i", pnum);
+
if (err == UBI_IO_FF_BITFLIPS)
- add_aeb(ai, free, pnum, ec, 1);
- else
- add_aeb(ai, free, pnum, ec, 0);
+ scrub = 1;
+
+ add_aeb(ai, free, pnum, ec, scrub);
continue;
} else if (err == 0 || err == UBI_IO_BITFLIPS) {
dbg_bld("Found non empty PEB:%i in pool", pnum);
if (err == UBI_IO_BITFLIPS)
scrub = 1;
- new_aeb = kmem_cache_alloc(ai->aeb_slab_cache,
- GFP_KERNEL);
+ new_aeb = ubi_alloc_aeb(ai, pnum, be64_to_cpu(ech->ec));
if (!new_aeb) {
ret = -ENOMEM;
goto out;
}
- new_aeb->ec = be64_to_cpu(ech->ec);
- new_aeb->pnum = pnum;
new_aeb->lnum = be32_to_cpu(vh->lnum);
new_aeb->sqnum = be64_to_cpu(vh->sqnum);
new_aeb->copy_flag = vh->copy_flag;
list_for_each_entry(aeb, &ai->free, u.list)
n++;
- ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb)
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb)
ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
n++;
fail:
list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) {
list_del(&tmp_aeb->u.list);
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
+ ubi_free_aeb(ai, tmp_aeb);
}
list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) {
list_del(&tmp_aeb->u.list);
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
+ ubi_free_aeb(ai, tmp_aeb);
+ }
+
+ return ret;
+}
+
+/**
+ * find_fm_anchor - find the most recent Fastmap superblock (anchor)
+ * @ai: UBI attach info to be filled
+ */
+static int find_fm_anchor(struct ubi_attach_info *ai)
+{
+ int ret = -1;
+ struct ubi_ainf_peb *aeb;
+ unsigned long long max_sqnum = 0;
+
+ list_for_each_entry(aeb, &ai->fastmap, u.list) {
+ if (aeb->vol_id == UBI_FM_SB_VOLUME_ID && aeb->sqnum > max_sqnum) {
+ max_sqnum = aeb->sqnum;
+ ret = aeb->pnum;
+ }
}
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
+ * @scan_ai: UBI attach info from the first 64 PEBs,
+ * used to find the most recent Fastmap data structure
*
* 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 fm_anchor)
+ struct ubi_attach_info *scan_ai)
{
struct ubi_fm_sb *fmsb, *fmsb2;
struct ubi_vid_hdr *vh;
struct ubi_ec_hdr *ech;
struct ubi_fastmap_layout *fm;
- int i, used_blocks, pnum, ret = 0;
+ struct ubi_ainf_peb *tmp_aeb, *aeb;
+ int i, used_blocks, pnum, fm_anchor, ret = 0;
size_t fm_size;
__be32 crc, tmp_crc;
unsigned long long sqnum = 0;
+ fm_anchor = find_fm_anchor(scan_ai);
+ if (fm_anchor < 0)
+ return UBI_NO_FASTMAP;
+
+ /* Move all (possible) fastmap blocks into our new attach structure. */
+ list_for_each_entry_safe(aeb, tmp_aeb, &scan_ai->fastmap, u.list)
+ list_move_tail(&aeb->u.list, &ai->fastmap);
+
down_write(&ubi->fm_protect);
memset(ubi->fm_buf, 0, ubi->fm_size);
goto out;
}
- ret = ubi_io_read(ubi, fmsb, fm_anchor, ubi->leb_start, sizeof(*fmsb));
+ ret = ubi_io_read_data(ubi, fmsb, fm_anchor, 0, sizeof(*fmsb));
if (ret && ret != UBI_IO_BITFLIPS)
goto free_fm_sb;
else if (ret == UBI_IO_BITFLIPS)
goto free_hdr;
}
+ if (i == 0 && pnum != fm_anchor) {
+ ubi_err(ubi, "Fastmap anchor PEB mismatch: PEB: %i vs. %i",
+ pnum, fm_anchor);
+ ret = UBI_BAD_FASTMAP;
+ goto free_hdr;
+ }
+
ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
if (ret && ret != UBI_IO_BITFLIPS) {
ubi_err(ubi, "unable to read fastmap block# %i EC (PEB: %i)",
if (sqnum < be64_to_cpu(vh->sqnum))
sqnum = be64_to_cpu(vh->sqnum);
- ret = ubi_io_read(ubi, ubi->fm_buf + (ubi->leb_size * i), pnum,
- ubi->leb_start, ubi->leb_size);
+ ret = ubi_io_read_data(ubi, ubi->fm_buf + (ubi->leb_size * i),
+ pnum, 0, ubi->leb_size);
if (ret && ret != UBI_IO_BITFLIPS) {
ubi_err(ubi, "unable to read fastmap block# %i (PEB: %i, "
"err: %i)", i, pnum, ret);
struct rb_node *tmp_rb;
int ret, i, j, free_peb_count, used_peb_count, vol_count;
int scrub_peb_count, erase_peb_count;
- int *seen_pebs = NULL;
+ unsigned long *seen_pebs = NULL;
fm_raw = ubi->fm_buf;
memset(ubi->fm_buf, 0, ubi->fm_size);
fm_pos += sizeof(*feba) + (sizeof(__be32) * vol->reserved_pebs);
ubi_assert(fm_pos <= ubi->fm_size);
- for (j = 0; j < vol->reserved_pebs; j++)
- feba->pnum[j] = cpu_to_be32(vol->eba_tbl[j]);
+ for (j = 0; j < vol->reserved_pebs; j++) {
+ struct ubi_eba_leb_desc ldesc;
+
+ ubi_eba_get_ldesc(vol, j, &ldesc);
+ feba->pnum[j] = cpu_to_be32(ldesc.pnum);
+ }
feba->reserved_pebs = cpu_to_be32(j);
feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC);
}
for (i = 0; i < new_fm->used_blocks; i++) {
- ret = ubi_io_write(ubi, fm_raw + (i * ubi->leb_size),
- new_fm->e[i]->pnum, ubi->leb_start, ubi->leb_size);
+ ret = ubi_io_write_data(ubi, fm_raw + (i * ubi->leb_size),
+ new_fm->e[i]->pnum, 0, ubi->leb_size);
if (ret) {
ubi_err(ubi, "unable to write fastmap to PEB %i!",
new_fm->e[i]->pnum);