aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2014-11-10 10:16:23 -0500
committerRichard Weinberger <richard@nod.at>2015-03-26 17:46:04 -0400
commitee59ba8b064f692a1dee99b6f3ba30b0e904b2c1 (patch)
tree365b8b071072ae08b59a5944fc14afd1674f53a5 /drivers
parent24b7a347c37f99c9d08d2d3ae9c6a56a8333429b (diff)
UBI: Fix stale pointers in ubi->lookuptbl
In some error paths the WL sub-system gives up on a PEB and frees it's ubi_wl_entry struct but does not set the entry in ubi->lookuptbl to NULL. Fastmap can stumble over such a stale pointer as it uses ubi->lookuptbl to find all PEBs. Fix this by introducing a new helper function which free()s a WL entry and removes the reference from the lookup table. Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/ubi/wl.c47
1 files changed, 31 insertions, 16 deletions
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 609b16d45406..83848324daa2 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -216,6 +216,20 @@ static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root)
216} 216}
217 217
218/** 218/**
219 * wl_tree_destroy - destroy a wear-leveling entry.
220 * @ubi: UBI device description object
221 * @e: the wear-leveling entry to add
222 *
223 * This function destroys a wear leveling entry and removes
224 * the reference from the lookup table.
225 */
226static void wl_entry_destroy(struct ubi_device *ubi, struct ubi_wl_entry *e)
227{
228 ubi->lookuptbl[e->pnum] = NULL;
229 kmem_cache_free(ubi_wl_entry_slab, e);
230}
231
232/**
219 * do_work - do one pending work. 233 * do_work - do one pending work.
220 * @ubi: UBI device description object 234 * @ubi: UBI device description object
221 * 235 *
@@ -1258,7 +1272,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
1258 err = do_sync_erase(ubi, e1, vol_id, lnum, 0); 1272 err = do_sync_erase(ubi, e1, vol_id, lnum, 0);
1259 if (err) { 1273 if (err) {
1260 if (e2) 1274 if (e2)
1261 kmem_cache_free(ubi_wl_entry_slab, e2); 1275 wl_entry_destroy(ubi, e2);
1262 goto out_ro; 1276 goto out_ro;
1263 } 1277 }
1264 1278
@@ -1326,8 +1340,8 @@ out_error:
1326 spin_unlock(&ubi->wl_lock); 1340 spin_unlock(&ubi->wl_lock);
1327 1341
1328 ubi_free_vid_hdr(ubi, vid_hdr); 1342 ubi_free_vid_hdr(ubi, vid_hdr);
1329 kmem_cache_free(ubi_wl_entry_slab, e1); 1343 wl_entry_destroy(ubi, e1);
1330 kmem_cache_free(ubi_wl_entry_slab, e2); 1344 wl_entry_destroy(ubi, e2);
1331 1345
1332out_ro: 1346out_ro:
1333 ubi_ro_mode(ubi); 1347 ubi_ro_mode(ubi);
@@ -1469,7 +1483,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
1469 if (shutdown) { 1483 if (shutdown) {
1470 dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); 1484 dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
1471 kfree(wl_wrk); 1485 kfree(wl_wrk);
1472 kmem_cache_free(ubi_wl_entry_slab, e); 1486 wl_entry_destroy(ubi, e);
1473 return 0; 1487 return 0;
1474 } 1488 }
1475 1489
@@ -1515,7 +1529,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
1515 return err; 1529 return err;
1516 } 1530 }
1517 1531
1518 kmem_cache_free(ubi_wl_entry_slab, e); 1532 wl_entry_destroy(ubi, e);
1519 if (err != -EIO) 1533 if (err != -EIO)
1520 /* 1534 /*
1521 * If this is not %-EIO, we have no idea what to do. Scheduling 1535 * If this is not %-EIO, we have no idea what to do. Scheduling
@@ -1807,9 +1821,10 @@ int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum)
1807 1821
1808/** 1822/**
1809 * tree_destroy - destroy an RB-tree. 1823 * tree_destroy - destroy an RB-tree.
1824 * @ubi: UBI device description object
1810 * @root: the root of the tree to destroy 1825 * @root: the root of the tree to destroy
1811 */ 1826 */
1812static void tree_destroy(struct rb_root *root) 1827static void tree_destroy(struct ubi_device *ubi, struct rb_root *root)
1813{ 1828{
1814 struct rb_node *rb; 1829 struct rb_node *rb;
1815 struct ubi_wl_entry *e; 1830 struct ubi_wl_entry *e;
@@ -1831,7 +1846,7 @@ static void tree_destroy(struct rb_root *root)
1831 rb->rb_right = NULL; 1846 rb->rb_right = NULL;
1832 } 1847 }
1833 1848
1834 kmem_cache_free(ubi_wl_entry_slab, e); 1849 wl_entry_destroy(ubi, e);
1835 } 1850 }
1836 } 1851 }
1837} 1852}
@@ -1962,7 +1977,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
1962 ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); 1977 ubi_assert(!ubi_is_fm_block(ubi, e->pnum));
1963 ubi->lookuptbl[e->pnum] = e; 1978 ubi->lookuptbl[e->pnum] = e;
1964 if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) { 1979 if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
1965 kmem_cache_free(ubi_wl_entry_slab, e); 1980 wl_entry_destroy(ubi, e);
1966 goto out_free; 1981 goto out_free;
1967 } 1982 }
1968 1983
@@ -2056,9 +2071,9 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
2056 2071
2057out_free: 2072out_free:
2058 shutdown_work(ubi); 2073 shutdown_work(ubi);
2059 tree_destroy(&ubi->used); 2074 tree_destroy(ubi, &ubi->used);
2060 tree_destroy(&ubi->free); 2075 tree_destroy(ubi, &ubi->free);
2061 tree_destroy(&ubi->scrub); 2076 tree_destroy(ubi, &ubi->scrub);
2062 kfree(ubi->lookuptbl); 2077 kfree(ubi->lookuptbl);
2063 return err; 2078 return err;
2064} 2079}
@@ -2075,7 +2090,7 @@ static void protection_queue_destroy(struct ubi_device *ubi)
2075 for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) { 2090 for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) {
2076 list_for_each_entry_safe(e, tmp, &ubi->pq[i], u.list) { 2091 list_for_each_entry_safe(e, tmp, &ubi->pq[i], u.list) {
2077 list_del(&e->u.list); 2092 list_del(&e->u.list);
2078 kmem_cache_free(ubi_wl_entry_slab, e); 2093 wl_entry_destroy(ubi, e);
2079 } 2094 }
2080 } 2095 }
2081} 2096}
@@ -2107,10 +2122,10 @@ void ubi_wl_close(struct ubi_device *ubi)
2107 ubi_fastmap_close(ubi); 2122 ubi_fastmap_close(ubi);
2108 shutdown_work(ubi); 2123 shutdown_work(ubi);
2109 protection_queue_destroy(ubi); 2124 protection_queue_destroy(ubi);
2110 tree_destroy(&ubi->used); 2125 tree_destroy(ubi, &ubi->used);
2111 tree_destroy(&ubi->erroneous); 2126 tree_destroy(ubi, &ubi->erroneous);
2112 tree_destroy(&ubi->free); 2127 tree_destroy(ubi, &ubi->free);
2113 tree_destroy(&ubi->scrub); 2128 tree_destroy(ubi, &ubi->scrub);
2114 kfree(ubi->lookuptbl); 2129 kfree(ubi->lookuptbl);
2115} 2130}
2116 2131