struct ubi_fm_pool *pool = &ubi->fm_wl_pool;
        int pnum;
 
+       ubi_assert(rwsem_is_locked(&ubi->fm_eba_sem));
+
        if (pool->used == pool->size) {
                /* We cannot update the fastmap here because this
                 * function is called in atomic context.
 
        wrk->anchor = 1;
        wrk->func = &wear_leveling_worker;
-       schedule_ubi_work(ubi, wrk);
+       __schedule_ubi_work(ubi, wrk);
        return 0;
 }
 
        spin_unlock(&ubi->wl_lock);
 
        vol_id = lnum ? UBI_FM_DATA_VOLUME_ID : UBI_FM_SB_VOLUME_ID;
-       return schedule_erase(ubi, e, vol_id, lnum, torture);
+       return schedule_erase(ubi, e, vol_id, lnum, torture, true);
 }
 
 /**
 
        struct ubi_wl_entry *tmp_e;
 
        down_write(&ubi->fm_protect);
+       down_write(&ubi->work_sem);
+       down_write(&ubi->fm_eba_sem);
 
        ubi_refill_pools(ubi);
 
        if (ubi->ro_mode || ubi->fm_disabled) {
+               up_write(&ubi->fm_eba_sem);
+               up_write(&ubi->work_sem);
                up_write(&ubi->fm_protect);
                return 0;
        }
 
        ret = ubi_ensure_anchor_pebs(ubi);
        if (ret) {
+               up_write(&ubi->fm_eba_sem);
+               up_write(&ubi->work_sem);
                up_write(&ubi->fm_protect);
                return ret;
        }
 
        new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL);
        if (!new_fm) {
+               up_write(&ubi->fm_eba_sem);
+               up_write(&ubi->work_sem);
                up_write(&ubi->fm_protect);
                return -ENOMEM;
        }
                new_fm->e[0] = tmp_e;
        }
 
-       down_write(&ubi->work_sem);
-       down_write(&ubi->fm_eba_sem);
        ret = ubi_write_fastmap(ubi, new_fm);
-       up_write(&ubi->fm_eba_sem);
-       up_write(&ubi->work_sem);
 
        if (ret)
                goto err;
 
 out_unlock:
+       up_write(&ubi->fm_eba_sem);
+       up_write(&ubi->work_sem);
        up_write(&ubi->fm_protect);
        kfree(old_fm);
        return ret;
 
  * failure.
  */
 static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
-                         int vol_id, int lnum, int torture)
+                         int vol_id, int lnum, int torture, bool nested)
 {
        struct ubi_work *wl_wrk;
 
        wl_wrk->lnum = lnum;
        wl_wrk->torture = torture;
 
-       schedule_ubi_work(ubi, wl_wrk);
+       if (nested)
+               __schedule_ubi_work(ubi, wl_wrk);
+       else
+               schedule_ubi_work(ubi, wl_wrk);
        return 0;
 }
 
 
        vid_hdr = ubi_get_vid_hdr(vidb);
 
+       down_read(&ubi->fm_eba_sem);
        mutex_lock(&ubi->move_mutex);
        spin_lock(&ubi->wl_lock);
        ubi_assert(!ubi->move_from && !ubi->move_to);
 
        dbg_wl("done");
        mutex_unlock(&ubi->move_mutex);
+       up_read(&ubi->fm_eba_sem);
        return 0;
 
        /*
        }
 
        mutex_unlock(&ubi->move_mutex);
+       up_read(&ubi->fm_eba_sem);
        return 0;
 
 out_error:
 out_ro:
        ubi_ro_mode(ubi);
        mutex_unlock(&ubi->move_mutex);
+       up_read(&ubi->fm_eba_sem);
        ubi_assert(err != 0);
        return err < 0 ? err : -EIO;
 
        ubi->wl_scheduled = 0;
        spin_unlock(&ubi->wl_lock);
        mutex_unlock(&ubi->move_mutex);
+       up_read(&ubi->fm_eba_sem);
        ubi_free_vid_buf(vidb);
        return 0;
 }
                int err1;
 
                /* Re-schedule the LEB for erasure */
-               err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
+               err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false);
                if (err1) {
                        wl_entry_destroy(ubi, e);
                        err = err1;
        }
        spin_unlock(&ubi->wl_lock);
 
-       err = schedule_erase(ubi, e, vol_id, lnum, torture);
+       err = schedule_erase(ubi, e, vol_id, lnum, torture, false);
        if (err) {
                spin_lock(&ubi->wl_lock);
                wl_tree_add(e, &ubi->used);
                e->pnum = aeb->pnum;
                e->ec = aeb->ec;
                ubi->lookuptbl[e->pnum] = e;
-               if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
+               if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
                        wl_entry_destroy(ubi, e);
                        goto out_free;
                }
                        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)) {
+                       if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
                                wl_entry_destroy(ubi, e);
                                goto out_free;
                        }