--- zzzz-none-000/linux-3.10.107/drivers/mtd/ubi/wl.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/mtd/ubi/wl.c 2021-02-04 17:41:59.000000000 +0000 @@ -103,6 +103,7 @@ #include #include #include "ubi.h" +#include "wl.h" /* Number of physical eraseblocks reserved for wear-leveling purposes */ #define WL_RESERVED_PEBS 1 @@ -140,42 +141,6 @@ static int self_check_in_pq(const struct ubi_device *ubi, struct ubi_wl_entry *e); -#ifdef CONFIG_MTD_UBI_FASTMAP -/** - * update_fastmap_work_fn - calls ubi_update_fastmap from a work queue - * @wrk: the work description object - */ -static void update_fastmap_work_fn(struct work_struct *wrk) -{ - struct ubi_device *ubi = container_of(wrk, struct ubi_device, fm_work); - ubi_update_fastmap(ubi); -} - -/** - * ubi_ubi_is_fm_block - returns 1 if a PEB is currently used in a fastmap. - * @ubi: UBI device description object - * @pnum: the to be checked PEB - */ -static int ubi_is_fm_block(struct ubi_device *ubi, int pnum) -{ - int i; - - if (!ubi->fm) - return 0; - - for (i = 0; i < ubi->fm->used_blocks; i++) - if (ubi->fm->e[i]->pnum == pnum) - return 1; - - return 0; -} -#else -static int ubi_is_fm_block(struct ubi_device *ubi, int pnum) -{ - return 0; -} -#endif - /** * wl_tree_add - add a wear-leveling entry to a WL RB-tree. * @e: the wear-leveling entry to add @@ -213,6 +178,20 @@ } /** + * wl_tree_destroy - destroy a wear-leveling entry. + * @ubi: UBI device description object + * @e: the wear-leveling entry to add + * + * This function destroys a wear leveling entry and removes + * the reference from the lookup table. + */ +static void wl_entry_destroy(struct ubi_device *ubi, struct ubi_wl_entry *e) +{ + ubi->lookuptbl[e->pnum] = NULL; + kmem_cache_free(ubi_wl_entry_slab, e); +} + +/** * do_work - do one pending work. * @ubi: UBI device description object * @@ -253,40 +232,13 @@ */ err = wrk->func(ubi, wrk, 0); if (err) - ubi_err("work failed with error code %d", err); + ubi_err(ubi, "work failed with error code %d", err); up_read(&ubi->work_sem); return err; } /** - * produce_free_peb - produce a free physical eraseblock. - * @ubi: UBI device description object - * - * This function tries to make a free PEB by means of synchronous execution of - * pending works. This may be needed if, for example the background thread is - * disabled. Returns zero in case of success and a negative error code in case - * of failure. - */ -static int produce_free_peb(struct ubi_device *ubi) -{ - int err; - - while (!ubi->free.rb_node) { - spin_unlock(&ubi->wl_lock); - - dbg_wl("do one work synchronously"); - err = do_work(ubi); - - spin_lock(&ubi->wl_lock); - if (err) - return err; - } - - return 0; -} - -/** * in_wl_tree - check if wear-leveling entry is present in a WL RB-tree. * @e: the wear-leveling entry to check * @root: the root of the tree @@ -409,119 +361,32 @@ if (last->ec - first->ec < WL_FREE_MAX_DIFF) { e = rb_entry(root->rb_node, struct ubi_wl_entry, u.rb); -#ifdef CONFIG_MTD_UBI_FASTMAP /* If no fastmap has been written and this WL entry can be used * as anchor PEB, hold it back and return the second best * WL entry such that fastmap can use the anchor PEB later. */ - if (e && !ubi->fm_disabled && !ubi->fm && - e->pnum < UBI_FM_MAX_START) - e = rb_entry(rb_next(root->rb_node), - struct ubi_wl_entry, u.rb); -#endif + e = may_reserve_for_fm(ubi, e, root); } else e = find_wl_entry(ubi, root, WL_FREE_MAX_DIFF/2); return e; } -#ifdef CONFIG_MTD_UBI_FASTMAP /** - * find_anchor_wl_entry - find wear-leveling entry to used as anchor PEB. - * @root: the RB-tree where to look for - */ -static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root) -{ - struct rb_node *p; - struct ubi_wl_entry *e, *victim = NULL; - int max_ec = UBI_MAX_ERASECOUNTER; - - ubi_rb_for_each_entry(p, e, root, u.rb) { - if (e->pnum < UBI_FM_MAX_START && e->ec < max_ec) { - victim = e; - max_ec = e->ec; - } - } - - return victim; -} - -static int anchor_pebs_avalible(struct rb_root *root) -{ - struct rb_node *p; - struct ubi_wl_entry *e; - - ubi_rb_for_each_entry(p, e, root, u.rb) - if (e->pnum < UBI_FM_MAX_START) - return 1; - - return 0; -} - -/** - * ubi_wl_get_fm_peb - find a physical erase block with a given maximal number. + * wl_get_wle - get a mean wl entry to be used by ubi_wl_get_peb() or + * refill_wl_user_pool(). * @ubi: UBI device description object - * @anchor: This PEB will be used as anchor PEB by fastmap * - * The function returns a physical erase block with a given maximal number - * and removes it from the wl subsystem. - * Must be called with wl_lock held! - */ -struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor) -{ - struct ubi_wl_entry *e = NULL; - - if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) - goto out; - - if (anchor) - e = find_anchor_wl_entry(&ubi->free); - else - e = find_mean_wl_entry(ubi, &ubi->free); - - if (!e) - goto out; - - self_check_in_wl_tree(ubi, e, &ubi->free); - - /* remove it from the free list, - * the wl subsystem does no longer know this erase block */ - rb_erase(&e->u.rb, &ubi->free); - ubi->free_count--; -out: - return e; -} -#endif - -/** - * __wl_get_peb - get a physical eraseblock. - * @ubi: UBI device description object - * - * This function returns a physical eraseblock in case of success and a - * negative error code in case of failure. + * This function returns a a wear leveling entry in case of success and + * NULL in case of failure. */ -static int __wl_get_peb(struct ubi_device *ubi) +static struct ubi_wl_entry *wl_get_wle(struct ubi_device *ubi) { - int err; struct ubi_wl_entry *e; -retry: - if (!ubi->free.rb_node) { - if (ubi->works_count == 0) { - ubi_err("no free eraseblocks"); - ubi_assert(list_empty(&ubi->works)); - return -ENOSPC; - } - - err = produce_free_peb(ubi); - if (err < 0) - return err; - goto retry; - } - e = find_mean_wl_entry(ubi, &ubi->free); if (!e) { - ubi_err("no free eraseblocks"); - return -ENOSPC; + ubi_err(ubi, "no free eraseblocks"); + return NULL; } self_check_in_wl_tree(ubi, e, &ubi->free); @@ -533,172 +398,10 @@ rb_erase(&e->u.rb, &ubi->free); ubi->free_count--; dbg_wl("PEB %d EC %d", e->pnum, e->ec); -#ifndef CONFIG_MTD_UBI_FASTMAP - /* We have to enqueue e only if fastmap is disabled, - * is fastmap enabled prot_queue_add() will be called by - * ubi_wl_get_peb() after removing e from the pool. */ - prot_queue_add(ubi, e); -#endif - return e->pnum; -} - -#ifdef CONFIG_MTD_UBI_FASTMAP -/** - * return_unused_pool_pebs - returns unused PEB to the free tree. - * @ubi: UBI device description object - * @pool: fastmap pool description object - */ -static void return_unused_pool_pebs(struct ubi_device *ubi, - struct ubi_fm_pool *pool) -{ - int i; - struct ubi_wl_entry *e; - - for (i = pool->used; i < pool->size; i++) { - e = ubi->lookuptbl[pool->pebs[i]]; - wl_tree_add(e, &ubi->free); - ubi->free_count++; - } -} - -/** - * refill_wl_pool - refills all the fastmap pool used by the - * WL sub-system. - * @ubi: UBI device description object - */ -static void refill_wl_pool(struct ubi_device *ubi) -{ - struct ubi_wl_entry *e; - struct ubi_fm_pool *pool = &ubi->fm_wl_pool; - - return_unused_pool_pebs(ubi, pool); - - for (pool->size = 0; pool->size < pool->max_size; pool->size++) { - if (!ubi->free.rb_node || - (ubi->free_count - ubi->beb_rsvd_pebs < 5)) - break; - - e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); - self_check_in_wl_tree(ubi, e, &ubi->free); - rb_erase(&e->u.rb, &ubi->free); - ubi->free_count--; - - pool->pebs[pool->size] = e->pnum; - } - pool->used = 0; -} - -/** - * refill_wl_user_pool - refills all the fastmap pool used by ubi_wl_get_peb. - * @ubi: UBI device description object - */ -static void refill_wl_user_pool(struct ubi_device *ubi) -{ - struct ubi_fm_pool *pool = &ubi->fm_pool; - - return_unused_pool_pebs(ubi, pool); - - for (pool->size = 0; pool->size < pool->max_size; pool->size++) { - if (!ubi->free.rb_node || - (ubi->free_count - ubi->beb_rsvd_pebs < 1)) - break; - - pool->pebs[pool->size] = __wl_get_peb(ubi); - if (pool->pebs[pool->size] < 0) - break; - } - pool->used = 0; -} - -/** - * ubi_refill_pools - refills all fastmap PEB pools. - * @ubi: UBI device description object - */ -void ubi_refill_pools(struct ubi_device *ubi) -{ - spin_lock(&ubi->wl_lock); - refill_wl_pool(ubi); - refill_wl_user_pool(ubi); - spin_unlock(&ubi->wl_lock); -} - -/* ubi_wl_get_peb - works exaclty like __wl_get_peb but keeps track of - * the fastmap pool. - */ -int ubi_wl_get_peb(struct ubi_device *ubi) -{ - int ret; - struct ubi_fm_pool *pool = &ubi->fm_pool; - struct ubi_fm_pool *wl_pool = &ubi->fm_wl_pool; - - if (!pool->size || !wl_pool->size || pool->used == pool->size || - wl_pool->used == wl_pool->size) - ubi_update_fastmap(ubi); - - /* we got not a single free PEB */ - if (!pool->size) - ret = -ENOSPC; - else { - spin_lock(&ubi->wl_lock); - ret = pool->pebs[pool->used++]; - prot_queue_add(ubi, ubi->lookuptbl[ret]); - spin_unlock(&ubi->wl_lock); - } - - return ret; -} - -/* get_peb_for_wl - returns a PEB to be used internally by the WL sub-system. - * - * @ubi: UBI device description object - */ -static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi) -{ - struct ubi_fm_pool *pool = &ubi->fm_wl_pool; - int pnum; - - if (pool->used == pool->size || !pool->size) { - /* We cannot update the fastmap here because this - * function is called in atomic context. - * Let's fail here and refill/update it as soon as possible. */ - schedule_work(&ubi->fm_work); - return NULL; - } else { - pnum = pool->pebs[pool->used++]; - return ubi->lookuptbl[pnum]; - } -} -#else -static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi) -{ - struct ubi_wl_entry *e; - - e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); - self_check_in_wl_tree(ubi, e, &ubi->free); - rb_erase(&e->u.rb, &ubi->free); return e; } -int ubi_wl_get_peb(struct ubi_device *ubi) -{ - int peb, err; - - spin_lock(&ubi->wl_lock); - peb = __wl_get_peb(ubi); - spin_unlock(&ubi->wl_lock); - - err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset, - ubi->peb_size - ubi->vid_hdr_aloffset); - if (err) { - ubi_err("new PEB %d does not contain all 0xFF bytes", peb); - return err; - } - - return peb; -} -#endif - /** * prot_queue_del - remove a physical eraseblock from the protection queue. * @ubi: UBI device description object @@ -759,7 +462,7 @@ * Erase counter overflow. Upgrade UBI and use 64-bit * erase counters internally. */ - ubi_err("erase counter overflow at PEB %d, EC %llu", + ubi_err(ubi, "erase counter overflow at PEB %d, EC %llu", e->pnum, ec); err = -EINVAL; goto out_free; @@ -834,7 +537,7 @@ * @wrk: the work to schedule * * This function adds a work defined by @wrk to the tail of the pending works - * list. Can only be used of ubi->work_sem is already held in read mode! + * list. Can only be used if ubi->work_sem is already held in read mode! */ static void __schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) { @@ -863,18 +566,7 @@ } static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, - int cancel); - -#ifdef CONFIG_MTD_UBI_FASTMAP -/** - * ubi_is_erase_work - checks whether a work is erase work. - * @wrk: The work object to be checked - */ -int ubi_is_erase_work(struct ubi_work *wrk) -{ - return wrk->func == erase_worker; -} -#endif + int shutdown); /** * schedule_erase - schedule an erase work. @@ -893,7 +585,6 @@ struct ubi_work *wl_wrk; ubi_assert(e); - ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); dbg_wl("schedule erasure of PEB %d, EC %d, torture %d", e->pnum, e->ec, torture); @@ -912,6 +603,7 @@ return 0; } +static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk); /** * do_sync_erase - run the erase worker synchronously. * @ubi: UBI device description object @@ -924,82 +616,34 @@ static int do_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int vol_id, int lnum, int torture) { - struct ubi_work *wl_wrk; + struct ubi_work wl_wrk; dbg_wl("sync erase of PEB %i", e->pnum); - wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); - if (!wl_wrk) - return -ENOMEM; - - wl_wrk->e = e; - wl_wrk->vol_id = vol_id; - wl_wrk->lnum = lnum; - wl_wrk->torture = torture; - - return erase_worker(ubi, wl_wrk, 0); -} - -#ifdef CONFIG_MTD_UBI_FASTMAP -/** - * ubi_wl_put_fm_peb - returns a PEB used in a fastmap to the wear-leveling - * sub-system. - * see: ubi_wl_put_peb() - * - * @ubi: UBI device description object - * @fm_e: physical eraseblock to return - * @lnum: the last used logical eraseblock number for the PEB - * @torture: if this physical eraseblock has to be tortured - */ -int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e, - int lnum, int torture) -{ - struct ubi_wl_entry *e; - int vol_id, pnum = fm_e->pnum; - - dbg_wl("PEB %d", pnum); - - ubi_assert(pnum >= 0); - ubi_assert(pnum < ubi->peb_count); - - spin_lock(&ubi->wl_lock); - e = ubi->lookuptbl[pnum]; - - /* This can happen if we recovered from a fastmap the very - * first time and writing now a new one. In this case the wl system - * has never seen any PEB used by the original fastmap. - */ - if (!e) { - e = fm_e; - ubi_assert(e->ec >= 0); - ubi->lookuptbl[pnum] = e; - } else { - e->ec = fm_e->ec; - kfree(fm_e); - } - - spin_unlock(&ubi->wl_lock); + wl_wrk.e = e; + wl_wrk.vol_id = vol_id; + wl_wrk.lnum = lnum; + wl_wrk.torture = torture; - vol_id = lnum ? UBI_FM_DATA_VOLUME_ID : UBI_FM_SB_VOLUME_ID; - return schedule_erase(ubi, e, vol_id, lnum, torture); + return __erase_worker(ubi, &wl_wrk); } -#endif /** * wear_leveling_worker - wear-leveling worker function. * @ubi: UBI device description object * @wrk: the work object - * @cancel: non-zero if the worker has to free memory and exit + * @shutdown: non-zero if the worker has to free memory and exit + * because the WL-subsystem is shutting down * * This function copies a more worn out physical eraseblock to a less worn out * one. Returns zero in case of success and a negative error code in case of * failure. */ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, - int cancel) + int shutdown) { int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0; - int vol_id = -1, lnum = -1; + int erase = 0, keep = 0, vol_id = -1, lnum = -1; #ifdef CONFIG_MTD_UBI_FASTMAP int anchor = wrk->anchor; #endif @@ -1007,7 +651,7 @@ struct ubi_vid_hdr *vid_hdr; kfree(wrk); - if (cancel) + if (shutdown) return 0; vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); @@ -1072,6 +716,7 @@ /* Give the unused PEB back */ wl_tree_add(e2, &ubi->free); + ubi->free_count++; goto out_cancel; } self_check_in_wl_tree(ubi, e1, &ubi->used); @@ -1132,9 +777,19 @@ e1->pnum); scrubbing = 1; goto out_not_moved; + } else if (ubi->fast_attach && err == UBI_IO_BAD_HDR_EBADMSG) { + /* + * While a full scan would detect interrupted erasures + * at attach time we can face them here when attached from + * Fastmap. + */ + dbg_wl("PEB %d has ECC errors, maybe from an interrupted erasure", + e1->pnum); + erase = 1; + goto out_not_moved; } - ubi_err("error %d while reading VID header from PEB %d", + ubi_err(ubi, "error %d while reading VID header from PEB %d", err, e1->pnum); goto out_error; } @@ -1165,6 +820,7 @@ * Target PEB had bit-flips or write error - torture it. */ torture = 1; + keep = 1; goto out_not_moved; } @@ -1178,7 +834,7 @@ * UBI from trying to move it over and over again. */ if (ubi->erroneous_peb_count > ubi->max_erroneous) { - ubi_err("too many erroneous eraseblocks (%d)", + ubi_err(ubi, "too many erroneous eraseblocks (%d)", ubi->erroneous_peb_count); goto out_error; } @@ -1194,7 +850,7 @@ /* The PEB has been successfully moved */ if (scrubbing) - ubi_msg("scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", + ubi_msg(ubi, "scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", e1->pnum, vol_id, lnum, e2->pnum); ubi_free_vid_hdr(ubi, vid_hdr); @@ -1210,7 +866,7 @@ err = do_sync_erase(ubi, e1, vol_id, lnum, 0); if (err) { if (e2) - kmem_cache_free(ubi_wl_entry_slab, e2); + wl_entry_destroy(ubi, e2); goto out_ro; } @@ -1250,7 +906,7 @@ ubi->erroneous_peb_count += 1; } else if (scrubbing) wl_tree_add(e1, &ubi->scrub); - else + else if (keep) wl_tree_add(e1, &ubi->used); ubi_assert(!ubi->move_to_put); ubi->move_from = ubi->move_to = NULL; @@ -1262,15 +918,21 @@ if (err) goto out_ro; + if (erase) { + err = do_sync_erase(ubi, e1, vol_id, lnum, 1); + if (err) + goto out_ro; + } + mutex_unlock(&ubi->move_mutex); return 0; out_error: if (vol_id != -1) - ubi_err("error %d while moving PEB %d to PEB %d", + ubi_err(ubi, "error %d while moving PEB %d to PEB %d", err, e1->pnum, e2->pnum); else - ubi_err("error %d while moving PEB %d (LEB %d:%d) to PEB %d", + ubi_err(ubi, "error %d while moving PEB %d (LEB %d:%d) to PEB %d", err, e1->pnum, vol_id, lnum, e2->pnum); spin_lock(&ubi->wl_lock); ubi->move_from = ubi->move_to = NULL; @@ -1278,8 +940,8 @@ spin_unlock(&ubi->wl_lock); ubi_free_vid_hdr(ubi, vid_hdr); - kmem_cache_free(ubi_wl_entry_slab, e1); - kmem_cache_free(ubi_wl_entry_slab, e2); + wl_entry_destroy(ubi, e1); + wl_entry_destroy(ubi, e2); out_ro: ubi_ro_mode(ubi); @@ -1365,51 +1027,19 @@ return err; } -#ifdef CONFIG_MTD_UBI_FASTMAP /** - * ubi_ensure_anchor_pebs - schedule wear-leveling to produce an anchor PEB. - * @ubi: UBI device description object - */ -int ubi_ensure_anchor_pebs(struct ubi_device *ubi) -{ - struct ubi_work *wrk; - - spin_lock(&ubi->wl_lock); - if (ubi->wl_scheduled) { - spin_unlock(&ubi->wl_lock); - return 0; - } - ubi->wl_scheduled = 1; - spin_unlock(&ubi->wl_lock); - - wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); - if (!wrk) { - spin_lock(&ubi->wl_lock); - ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - return -ENOMEM; - } - - wrk->anchor = 1; - wrk->func = &wear_leveling_worker; - schedule_ubi_work(ubi, wrk); - return 0; -} -#endif - -/** - * erase_worker - physical eraseblock erase worker function. + * __erase_worker - physical eraseblock erase worker function. * @ubi: UBI device description object * @wl_wrk: the work object - * @cancel: non-zero if the worker has to free memory and exit + * @shutdown: non-zero if the worker has to free memory and exit + * because the WL sub-system is shutting down * * This function erases a physical eraseblock and perform torture testing if * needed. It also takes care about marking the physical eraseblock bad if * needed. Returns zero in case of success and a negative error code in case of * failure. */ -static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, - int cancel) +static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk) { struct ubi_wl_entry *e = wl_wrk->e; int pnum = e->pnum; @@ -1417,23 +1047,11 @@ int lnum = wl_wrk->lnum; int err, available_consumed = 0; - if (cancel) { - dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); - kfree(wl_wrk); - kmem_cache_free(ubi_wl_entry_slab, e); - return 0; - } - dbg_wl("erase PEB %d EC %d LEB %d:%d", pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum); - ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); - err = sync_erase(ubi, e, wl_wrk->torture); if (!err) { - /* Fine, we've erased it successfully */ - kfree(wl_wrk); - spin_lock(&ubi->wl_lock); wl_tree_add(e, &ubi->free); ubi->free_count++; @@ -1450,8 +1068,7 @@ return err; } - ubi_err("failed to erase PEB %d, error %d", pnum, err); - kfree(wl_wrk); + ubi_err(ubi, "failed to erase PEB %d, error %d", pnum, err); if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || err == -EBUSY) { @@ -1460,13 +1077,14 @@ /* Re-schedule the LEB for erasure */ err1 = schedule_erase(ubi, e, vol_id, lnum, 0); if (err1) { + wl_entry_destroy(ubi, e); err = err1; goto out_ro; } return err; } - kmem_cache_free(ubi_wl_entry_slab, e); + wl_entry_destroy(ubi, e); if (err != -EIO) /* * If this is not %-EIO, we have no idea what to do. Scheduling @@ -1478,7 +1096,7 @@ /* It is %-EIO, the PEB went bad */ if (!ubi->bad_allowed) { - ubi_err("bad physical eraseblock %d detected", pnum); + ubi_err(ubi, "bad physical eraseblock %d detected", pnum); goto out_ro; } @@ -1486,7 +1104,7 @@ if (ubi->beb_rsvd_pebs == 0) { if (ubi->avail_pebs == 0) { spin_unlock(&ubi->volumes_lock); - ubi_err("no reserved/available physical eraseblocks"); + ubi_err(ubi, "no reserved/available physical eraseblocks"); goto out_ro; } ubi->avail_pebs -= 1; @@ -1494,7 +1112,7 @@ } spin_unlock(&ubi->volumes_lock); - ubi_msg("mark PEB %d as bad", pnum); + ubi_msg(ubi, "mark PEB %d as bad", pnum); err = ubi_io_mark_bad(ubi, pnum); if (err) goto out_ro; @@ -1515,11 +1133,12 @@ ubi->good_peb_count -= 1; ubi_calculate_reserved(ubi); if (available_consumed) - ubi_warn("no PEBs in the reserved pool, used an available PEB"); + ubi_warn(ubi, "no PEBs in the reserved pool, used an available PEB"); else if (ubi->beb_rsvd_pebs) - ubi_msg("%d PEBs left in the reserve", ubi->beb_rsvd_pebs); + ubi_msg(ubi, "%d PEBs left in the reserve", + ubi->beb_rsvd_pebs); else - ubi_warn("last PEB from the reserve was used"); + ubi_warn(ubi, "last PEB from the reserve was used"); spin_unlock(&ubi->volumes_lock); return err; @@ -1534,6 +1153,25 @@ return err; } +static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, + int shutdown) +{ + int ret; + + if (shutdown) { + struct ubi_wl_entry *e = wl_wrk->e; + + dbg_wl("cancel erasure of PEB %d EC %d", e->pnum, e->ec); + kfree(wl_wrk); + wl_entry_destroy(ubi, e); + return 0; + } + + ret = __erase_worker(ubi, wl_wrk); + kfree(wl_wrk); + return ret; +} + /** * ubi_wl_put_peb - return a PEB to the wear-leveling sub-system. * @ubi: UBI device description object @@ -1557,6 +1195,8 @@ ubi_assert(pnum >= 0); ubi_assert(pnum < ubi->peb_count); + down_read(&ubi->fm_protect); + retry: spin_lock(&ubi->wl_lock); e = ubi->lookuptbl[pnum]; @@ -1587,6 +1227,7 @@ ubi_assert(!ubi->move_to_put); ubi->move_to_put = 1; spin_unlock(&ubi->wl_lock); + up_read(&ubi->fm_protect); return 0; } else { if (in_wl_tree(e, &ubi->used)) { @@ -1605,9 +1246,10 @@ } else { err = prot_queue_del(ubi, e->pnum); if (err) { - ubi_err("PEB %d not found", pnum); + ubi_err(ubi, "PEB %d not found", pnum); ubi_ro_mode(ubi); spin_unlock(&ubi->wl_lock); + up_read(&ubi->fm_protect); return err; } } @@ -1621,6 +1263,7 @@ spin_unlock(&ubi->wl_lock); } + up_read(&ubi->fm_protect); return err; } @@ -1638,7 +1281,7 @@ { struct ubi_wl_entry *e; - ubi_msg("schedule PEB %d for scrubbing", pnum); + ubi_msg(ubi, "schedule PEB %d for scrubbing", pnum); retry: spin_lock(&ubi->wl_lock); @@ -1670,7 +1313,7 @@ err = prot_queue_del(ubi, e->pnum); if (err) { - ubi_err("PEB %d not found", pnum); + ubi_err(ubi, "PEB %d not found", pnum); ubi_ro_mode(ubi); spin_unlock(&ubi->wl_lock); return err; @@ -1712,12 +1355,12 @@ vol_id, lnum, ubi->works_count); while (found) { - struct ubi_work *wrk; + struct ubi_work *wrk, *tmp; found = 0; down_read(&ubi->work_sem); spin_lock(&ubi->wl_lock); - list_for_each_entry(wrk, &ubi->works, list) { + list_for_each_entry_safe(wrk, tmp, &ubi->works, list) { if ((vol_id == UBI_ALL || wrk->vol_id == vol_id) && (lnum == UBI_ALL || wrk->lnum == lnum)) { list_del(&wrk->list); @@ -1752,9 +1395,10 @@ /** * tree_destroy - destroy an RB-tree. + * @ubi: UBI device description object * @root: the root of the tree to destroy */ -static void tree_destroy(struct rb_root *root) +static void tree_destroy(struct ubi_device *ubi, struct rb_root *root) { struct rb_node *rb; struct ubi_wl_entry *e; @@ -1776,7 +1420,7 @@ rb->rb_right = NULL; } - kmem_cache_free(ubi_wl_entry_slab, e); + wl_entry_destroy(ubi, e); } } } @@ -1790,7 +1434,7 @@ int failures = 0; struct ubi_device *ubi = u; - ubi_msg("background thread \"%s\" started, PID %d", + ubi_msg(ubi, "background thread \"%s\" started, PID %d", ubi->bgt_name, task_pid_nr(current)); set_freezable(); @@ -1815,14 +1459,14 @@ err = do_work(ubi); if (err) { - ubi_err("%s: work failed with error code %d", + ubi_err(ubi, "%s: work failed with error code %d", ubi->bgt_name, err); if (failures++ > WL_MAX_FAILURES) { /* * Too many failures, disable the thread and * switch to read-only mode. */ - ubi_msg("%s: %d consecutive failures", + ubi_msg(ubi, "%s: %d consecutive failures", ubi->bgt_name, WL_MAX_FAILURES); ubi_ro_mode(ubi); ubi->thread_enabled = 0; @@ -1839,11 +1483,14 @@ } /** - * cancel_pending - cancel all pending works. + * shutdown_work - shutdown all pending works. * @ubi: UBI device description object */ -static void cancel_pending(struct ubi_device *ubi) +static void shutdown_work(struct ubi_device *ubi) { +#ifdef CONFIG_MTD_UBI_FASTMAP + flush_work(&ubi->fm_work); +#endif while (!list_empty(&ubi->works)) { struct ubi_work *wrk; @@ -1877,9 +1524,6 @@ init_rwsem(&ubi->work_sem); ubi->max_ec = ai->max_ec; INIT_LIST_HEAD(&ubi->works); -#ifdef CONFIG_MTD_UBI_FASTMAP - INIT_WORK(&ubi->fm_work, update_fastmap_work_fn); -#endif sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num); @@ -1901,10 +1545,9 @@ e->pnum = aeb->pnum; e->ec = aeb->ec; - ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); ubi->lookuptbl[e->pnum] = e; if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) { - kmem_cache_free(ubi_wl_entry_slab, e); + wl_entry_destroy(ubi, e); goto out_free; } @@ -1922,7 +1565,6 @@ e->pnum = aeb->pnum; e->ec = aeb->ec; ubi_assert(e->ec >= 0); - ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); wl_tree_add(e, &ubi->free); ubi->free_count++; @@ -1960,23 +1602,26 @@ dbg_wl("found %i PEBs", found_pebs); - if (ubi->fm) - ubi_assert(ubi->good_peb_count == \ + if (ubi->fm) { + ubi_assert(ubi->good_peb_count == found_pebs + ubi->fm->used_blocks); + + for (i = 0; i < ubi->fm->used_blocks; i++) { + e = ubi->fm->e[i]; + ubi->lookuptbl[e->pnum] = e; + } + } else ubi_assert(ubi->good_peb_count == found_pebs); reserved_pebs = WL_RESERVED_PEBS; -#ifdef CONFIG_MTD_UBI_FASTMAP - /* Reserve enough LEBs to store two fastmaps. */ - reserved_pebs += (ubi->fm_size / ubi->leb_size) * 2; -#endif + ubi_fastmap_init(ubi, &reserved_pebs); if (ubi->avail_pebs < reserved_pebs) { - ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi_err(ubi, "no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, reserved_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi, "%d PEBs are corrupted and not used", ubi->corr_peb_count); err = -ENOSPC; goto out_free; @@ -1992,10 +1637,10 @@ return 0; out_free: - cancel_pending(ubi); - tree_destroy(&ubi->used); - tree_destroy(&ubi->free); - tree_destroy(&ubi->scrub); + shutdown_work(ubi); + tree_destroy(ubi, &ubi->used); + tree_destroy(ubi, &ubi->free); + tree_destroy(ubi, &ubi->scrub); kfree(ubi->lookuptbl); return err; } @@ -2012,7 +1657,7 @@ for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) { list_for_each_entry_safe(e, tmp, &ubi->pq[i], u.list) { list_del(&e->u.list); - kmem_cache_free(ubi_wl_entry_slab, e); + wl_entry_destroy(ubi, e); } } } @@ -2024,12 +1669,13 @@ void ubi_wl_close(struct ubi_device *ubi) { dbg_wl("close the WL sub-system"); - cancel_pending(ubi); + ubi_fastmap_close(ubi); + shutdown_work(ubi); protection_queue_destroy(ubi); - tree_destroy(&ubi->used); - tree_destroy(&ubi->erroneous); - tree_destroy(&ubi->free); - tree_destroy(&ubi->scrub); + tree_destroy(ubi, &ubi->used); + tree_destroy(ubi, &ubi->erroneous); + tree_destroy(ubi, &ubi->free); + tree_destroy(ubi, &ubi->scrub); kfree(ubi->lookuptbl); } @@ -2065,8 +1711,8 @@ read_ec = be64_to_cpu(ec_hdr->ec); if (ec != read_ec && read_ec - ec > 1) { - ubi_err("self-check failed for PEB %d", pnum); - ubi_err("read EC is %lld, should be %d", read_ec, ec); + ubi_err(ubi, "self-check failed for PEB %d", pnum); + ubi_err(ubi, "read EC is %lld, should be %d", read_ec, ec); dump_stack(); err = 1; } else @@ -2095,7 +1741,7 @@ if (in_wl_tree(e, root)) return 0; - ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ", + ubi_err(ubi, "self-check failed for PEB %d, EC %d, RB-tree %p ", e->pnum, e->ec, root); dump_stack(); return -EINVAL; @@ -2123,8 +1769,99 @@ if (p == e) return 0; - ubi_err("self-check failed for PEB %d, EC %d, Protect queue", + ubi_err(ubi, "self-check failed for PEB %d, EC %d, Protect queue", e->pnum, e->ec); dump_stack(); return -EINVAL; } +#ifndef CONFIG_MTD_UBI_FASTMAP +static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi) +{ + struct ubi_wl_entry *e; + + e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); + self_check_in_wl_tree(ubi, e, &ubi->free); + ubi->free_count--; + ubi_assert(ubi->free_count >= 0); + rb_erase(&e->u.rb, &ubi->free); + + return e; +} + +/** + * produce_free_peb - produce a free physical eraseblock. + * @ubi: UBI device description object + * + * This function tries to make a free PEB by means of synchronous execution of + * pending works. This may be needed if, for example the background thread is + * disabled. Returns zero in case of success and a negative error code in case + * of failure. + */ +static int produce_free_peb(struct ubi_device *ubi) +{ + int err; + + while (!ubi->free.rb_node && ubi->works_count) { + spin_unlock(&ubi->wl_lock); + + dbg_wl("do one work synchronously"); + err = do_work(ubi); + + spin_lock(&ubi->wl_lock); + if (err) + return err; + } + + return 0; +} + +/** + * ubi_wl_get_peb - get a physical eraseblock. + * @ubi: UBI device description object + * + * This function returns a physical eraseblock in case of success and a + * negative error code in case of failure. + * Returns with ubi->fm_eba_sem held in read mode! + */ +int ubi_wl_get_peb(struct ubi_device *ubi) +{ + int err; + struct ubi_wl_entry *e; + +retry: + down_read(&ubi->fm_eba_sem); + spin_lock(&ubi->wl_lock); + if (!ubi->free.rb_node) { + if (ubi->works_count == 0) { + ubi_err(ubi, "no free eraseblocks"); + ubi_assert(list_empty(&ubi->works)); + spin_unlock(&ubi->wl_lock); + return -ENOSPC; + } + + err = produce_free_peb(ubi); + if (err < 0) { + spin_unlock(&ubi->wl_lock); + return err; + } + spin_unlock(&ubi->wl_lock); + up_read(&ubi->fm_eba_sem); + goto retry; + + } + e = wl_get_wle(ubi); + prot_queue_add(ubi, e); + spin_unlock(&ubi->wl_lock); + + err = ubi_self_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset, + ubi->peb_size - ubi->vid_hdr_aloffset); + if (err) { + ubi_err(ubi, "new PEB %d does not contain all 0xFF bytes", e->pnum); + return err; + } + + return e->pnum; +} +#else +#include "fastmap-wl.c" +#endif