|
@@ -1528,6 +1528,46 @@ static void shutdown_work(struct ubi_device *ubi)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * erase_aeb - erase a PEB given in UBI attach info PEB
|
|
|
+ * @ubi: UBI device description object
|
|
|
+ * @aeb: UBI attach info PEB
|
|
|
+ * @sync: If true, erase synchronously. Otherwise schedule for erasure
|
|
|
+ */
|
|
|
+static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync)
|
|
|
+{
|
|
|
+ struct ubi_wl_entry *e;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
|
|
|
+ if (!e)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ e->pnum = aeb->pnum;
|
|
|
+ e->ec = aeb->ec;
|
|
|
+ ubi->lookuptbl[e->pnum] = e;
|
|
|
+
|
|
|
+ if (sync) {
|
|
|
+ err = sync_erase(ubi, e, false);
|
|
|
+ if (err)
|
|
|
+ goto out_free;
|
|
|
+
|
|
|
+ wl_tree_add(e, &ubi->free);
|
|
|
+ ubi->free_count++;
|
|
|
+ } else {
|
|
|
+ err = schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false);
|
|
|
+ if (err)
|
|
|
+ goto out_free;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out_free:
|
|
|
+ wl_entry_destroy(ubi, e);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ubi_wl_init - initialize the WL sub-system using attaching information.
|
|
|
* @ubi: UBI device description object
|
|
@@ -1566,18 +1606,10 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
|
|
|
list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) {
|
|
|
cond_resched();
|
|
|
|
|
|
- e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
|
|
|
- if (!e)
|
|
|
+ err = erase_aeb(ubi, aeb, false);
|
|
|
+ if (err)
|
|
|
goto out_free;
|
|
|
|
|
|
- e->pnum = aeb->pnum;
|
|
|
- e->ec = aeb->ec;
|
|
|
- ubi->lookuptbl[e->pnum] = e;
|
|
|
- if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
|
|
|
- wl_entry_destroy(ubi, e);
|
|
|
- goto out_free;
|
|
|
- }
|
|
|
-
|
|
|
found_pebs++;
|
|
|
}
|
|
|
|
|
@@ -1635,6 +1667,8 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
|
|
|
ubi_assert(!ubi->lookuptbl[e->pnum]);
|
|
|
ubi->lookuptbl[e->pnum] = e;
|
|
|
} else {
|
|
|
+ bool sync = false;
|
|
|
+
|
|
|
/*
|
|
|
* Usually old Fastmap PEBs are scheduled for erasure
|
|
|
* and we don't have to care about them but if we face
|
|
@@ -1644,18 +1678,21 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
|
|
|
if (ubi->lookuptbl[aeb->pnum])
|
|
|
continue;
|
|
|
|
|
|
- e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
|
|
|
- if (!e)
|
|
|
- goto out_free;
|
|
|
+ /*
|
|
|
+ * The fastmap update code might not find a free PEB for
|
|
|
+ * writing the fastmap anchor to and then reuses the
|
|
|
+ * current fastmap anchor PEB. When this PEB gets erased
|
|
|
+ * and a power cut happens before it is written again we
|
|
|
+ * must make sure that the fastmap attach code doesn't
|
|
|
+ * find any outdated fastmap anchors, hence we erase the
|
|
|
+ * outdated fastmap anchor PEBs synchronously here.
|
|
|
+ */
|
|
|
+ if (aeb->vol_id == UBI_FM_SB_VOLUME_ID)
|
|
|
+ sync = true;
|
|
|
|
|
|
- e->pnum = aeb->pnum;
|
|
|
- e->ec = aeb->ec;
|
|
|
- ubi_assert(!ubi->lookuptbl[e->pnum]);
|
|
|
- ubi->lookuptbl[e->pnum] = e;
|
|
|
- if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
|
|
|
- wl_entry_destroy(ubi, e);
|
|
|
+ err = erase_aeb(ubi, aeb, sync);
|
|
|
+ if (err)
|
|
|
goto out_free;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
found_pebs++;
|