diff options
| -rw-r--r-- | drivers/mtd/ubi/eba.c | 4 | ||||
| -rw-r--r-- | drivers/mtd/ubi/fastmap-wl.c | 6 | ||||
| -rw-r--r-- | drivers/mtd/ubi/fastmap.c | 14 | ||||
| -rw-r--r-- | drivers/mtd/ubi/wl.c | 20 |
4 files changed, 30 insertions, 14 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index ddf4e63eed76..95c4048a371e 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
| @@ -1210,6 +1210,8 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
| 1210 | struct ubi_volume *vol; | 1210 | struct ubi_volume *vol; |
| 1211 | uint32_t crc; | 1211 | uint32_t crc; |
| 1212 | 1212 | ||
| 1213 | ubi_assert(rwsem_is_locked(&ubi->fm_eba_sem)); | ||
| 1214 | |||
| 1213 | vol_id = be32_to_cpu(vid_hdr->vol_id); | 1215 | vol_id = be32_to_cpu(vid_hdr->vol_id); |
| 1214 | lnum = be32_to_cpu(vid_hdr->lnum); | 1216 | lnum = be32_to_cpu(vid_hdr->lnum); |
| 1215 | 1217 | ||
| @@ -1352,9 +1354,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
| 1352 | } | 1354 | } |
| 1353 | 1355 | ||
| 1354 | ubi_assert(vol->eba_tbl->entries[lnum].pnum == from); | 1356 | ubi_assert(vol->eba_tbl->entries[lnum].pnum == from); |
| 1355 | down_read(&ubi->fm_eba_sem); | ||
| 1356 | vol->eba_tbl->entries[lnum].pnum = to; | 1357 | vol->eba_tbl->entries[lnum].pnum = to; |
| 1357 | up_read(&ubi->fm_eba_sem); | ||
| 1358 | 1358 | ||
| 1359 | out_unlock_buf: | 1359 | out_unlock_buf: |
| 1360 | mutex_unlock(&ubi->buf_mutex); | 1360 | mutex_unlock(&ubi->buf_mutex); |
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 30d3999dddba..4f0bd6b4422a 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c | |||
| @@ -262,6 +262,8 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi) | |||
| 262 | struct ubi_fm_pool *pool = &ubi->fm_wl_pool; | 262 | struct ubi_fm_pool *pool = &ubi->fm_wl_pool; |
| 263 | int pnum; | 263 | int pnum; |
| 264 | 264 | ||
| 265 | ubi_assert(rwsem_is_locked(&ubi->fm_eba_sem)); | ||
| 266 | |||
| 265 | if (pool->used == pool->size) { | 267 | if (pool->used == pool->size) { |
| 266 | /* We cannot update the fastmap here because this | 268 | /* We cannot update the fastmap here because this |
| 267 | * function is called in atomic context. | 269 | * function is called in atomic context. |
| @@ -303,7 +305,7 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi) | |||
| 303 | 305 | ||
| 304 | wrk->anchor = 1; | 306 | wrk->anchor = 1; |
| 305 | wrk->func = &wear_leveling_worker; | 307 | wrk->func = &wear_leveling_worker; |
| 306 | schedule_ubi_work(ubi, wrk); | 308 | __schedule_ubi_work(ubi, wrk); |
| 307 | return 0; | 309 | return 0; |
| 308 | } | 310 | } |
| 309 | 311 | ||
| @@ -344,7 +346,7 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e, | |||
| 344 | spin_unlock(&ubi->wl_lock); | 346 | spin_unlock(&ubi->wl_lock); |
| 345 | 347 | ||
| 346 | vol_id = lnum ? UBI_FM_DATA_VOLUME_ID : UBI_FM_SB_VOLUME_ID; | 348 | vol_id = lnum ? UBI_FM_DATA_VOLUME_ID : UBI_FM_SB_VOLUME_ID; |
| 347 | return schedule_erase(ubi, e, vol_id, lnum, torture); | 349 | return schedule_erase(ubi, e, vol_id, lnum, torture, true); |
| 348 | } | 350 | } |
| 349 | 351 | ||
| 350 | /** | 352 | /** |
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 4adffb893376..8bd468332ec0 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c | |||
| @@ -1492,22 +1492,30 @@ int ubi_update_fastmap(struct ubi_device *ubi) | |||
| 1492 | struct ubi_wl_entry *tmp_e; | 1492 | struct ubi_wl_entry *tmp_e; |
| 1493 | 1493 | ||
| 1494 | down_write(&ubi->fm_protect); | 1494 | down_write(&ubi->fm_protect); |
| 1495 | down_write(&ubi->work_sem); | ||
| 1496 | down_write(&ubi->fm_eba_sem); | ||
| 1495 | 1497 | ||
| 1496 | ubi_refill_pools(ubi); | 1498 | ubi_refill_pools(ubi); |
| 1497 | 1499 | ||
| 1498 | if (ubi->ro_mode || ubi->fm_disabled) { | 1500 | if (ubi->ro_mode || ubi->fm_disabled) { |
| 1501 | up_write(&ubi->fm_eba_sem); | ||
| 1502 | up_write(&ubi->work_sem); | ||
| 1499 | up_write(&ubi->fm_protect); | 1503 | up_write(&ubi->fm_protect); |
| 1500 | return 0; | 1504 | return 0; |
| 1501 | } | 1505 | } |
| 1502 | 1506 | ||
| 1503 | ret = ubi_ensure_anchor_pebs(ubi); | 1507 | ret = ubi_ensure_anchor_pebs(ubi); |
| 1504 | if (ret) { | 1508 | if (ret) { |
| 1509 | up_write(&ubi->fm_eba_sem); | ||
| 1510 | up_write(&ubi->work_sem); | ||
| 1505 | up_write(&ubi->fm_protect); | 1511 | up_write(&ubi->fm_protect); |
| 1506 | return ret; | 1512 | return ret; |
| 1507 | } | 1513 | } |
| 1508 | 1514 | ||
| 1509 | new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL); | 1515 | new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL); |
| 1510 | if (!new_fm) { | 1516 | if (!new_fm) { |
| 1517 | up_write(&ubi->fm_eba_sem); | ||
| 1518 | up_write(&ubi->work_sem); | ||
| 1511 | up_write(&ubi->fm_protect); | 1519 | up_write(&ubi->fm_protect); |
| 1512 | return -ENOMEM; | 1520 | return -ENOMEM; |
| 1513 | } | 1521 | } |
| @@ -1616,16 +1624,14 @@ int ubi_update_fastmap(struct ubi_device *ubi) | |||
| 1616 | new_fm->e[0] = tmp_e; | 1624 | new_fm->e[0] = tmp_e; |
| 1617 | } | 1625 | } |
| 1618 | 1626 | ||
| 1619 | down_write(&ubi->work_sem); | ||
| 1620 | down_write(&ubi->fm_eba_sem); | ||
| 1621 | ret = ubi_write_fastmap(ubi, new_fm); | 1627 | ret = ubi_write_fastmap(ubi, new_fm); |
| 1622 | up_write(&ubi->fm_eba_sem); | ||
| 1623 | up_write(&ubi->work_sem); | ||
| 1624 | 1628 | ||
| 1625 | if (ret) | 1629 | if (ret) |
| 1626 | goto err; | 1630 | goto err; |
| 1627 | 1631 | ||
| 1628 | out_unlock: | 1632 | out_unlock: |
| 1633 | up_write(&ubi->fm_eba_sem); | ||
| 1634 | up_write(&ubi->work_sem); | ||
| 1629 | up_write(&ubi->fm_protect); | 1635 | up_write(&ubi->fm_protect); |
| 1630 | kfree(old_fm); | 1636 | kfree(old_fm); |
| 1631 | return ret; | 1637 | return ret; |
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 19206ad677b2..b5b8cd6f481c 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c | |||
| @@ -580,7 +580,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | |||
| 580 | * failure. | 580 | * failure. |
| 581 | */ | 581 | */ |
| 582 | static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, | 582 | static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, |
| 583 | int vol_id, int lnum, int torture) | 583 | int vol_id, int lnum, int torture, bool nested) |
| 584 | { | 584 | { |
| 585 | struct ubi_work *wl_wrk; | 585 | struct ubi_work *wl_wrk; |
| 586 | 586 | ||
| @@ -599,7 +599,10 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, | |||
| 599 | wl_wrk->lnum = lnum; | 599 | wl_wrk->lnum = lnum; |
| 600 | wl_wrk->torture = torture; | 600 | wl_wrk->torture = torture; |
| 601 | 601 | ||
| 602 | schedule_ubi_work(ubi, wl_wrk); | 602 | if (nested) |
| 603 | __schedule_ubi_work(ubi, wl_wrk); | ||
| 604 | else | ||
| 605 | schedule_ubi_work(ubi, wl_wrk); | ||
| 603 | return 0; | 606 | return 0; |
| 604 | } | 607 | } |
| 605 | 608 | ||
| @@ -663,6 +666,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
| 663 | 666 | ||
| 664 | vid_hdr = ubi_get_vid_hdr(vidb); | 667 | vid_hdr = ubi_get_vid_hdr(vidb); |
| 665 | 668 | ||
| 669 | down_read(&ubi->fm_eba_sem); | ||
| 666 | mutex_lock(&ubi->move_mutex); | 670 | mutex_lock(&ubi->move_mutex); |
| 667 | spin_lock(&ubi->wl_lock); | 671 | spin_lock(&ubi->wl_lock); |
| 668 | ubi_assert(!ubi->move_from && !ubi->move_to); | 672 | ubi_assert(!ubi->move_from && !ubi->move_to); |
| @@ -893,6 +897,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
| 893 | 897 | ||
| 894 | dbg_wl("done"); | 898 | dbg_wl("done"); |
| 895 | mutex_unlock(&ubi->move_mutex); | 899 | mutex_unlock(&ubi->move_mutex); |
| 900 | up_read(&ubi->fm_eba_sem); | ||
| 896 | return 0; | 901 | return 0; |
| 897 | 902 | ||
| 898 | /* | 903 | /* |
| @@ -943,6 +948,7 @@ out_not_moved: | |||
| 943 | } | 948 | } |
| 944 | 949 | ||
| 945 | mutex_unlock(&ubi->move_mutex); | 950 | mutex_unlock(&ubi->move_mutex); |
| 951 | up_read(&ubi->fm_eba_sem); | ||
| 946 | return 0; | 952 | return 0; |
| 947 | 953 | ||
| 948 | out_error: | 954 | out_error: |
| @@ -964,6 +970,7 @@ out_error: | |||
| 964 | out_ro: | 970 | out_ro: |
| 965 | ubi_ro_mode(ubi); | 971 | ubi_ro_mode(ubi); |
| 966 | mutex_unlock(&ubi->move_mutex); | 972 | mutex_unlock(&ubi->move_mutex); |
| 973 | up_read(&ubi->fm_eba_sem); | ||
| 967 | ubi_assert(err != 0); | 974 | ubi_assert(err != 0); |
| 968 | return err < 0 ? err : -EIO; | 975 | return err < 0 ? err : -EIO; |
| 969 | 976 | ||
| @@ -971,6 +978,7 @@ out_cancel: | |||
| 971 | ubi->wl_scheduled = 0; | 978 | ubi->wl_scheduled = 0; |
| 972 | spin_unlock(&ubi->wl_lock); | 979 | spin_unlock(&ubi->wl_lock); |
| 973 | mutex_unlock(&ubi->move_mutex); | 980 | mutex_unlock(&ubi->move_mutex); |
| 981 | up_read(&ubi->fm_eba_sem); | ||
| 974 | ubi_free_vid_buf(vidb); | 982 | ubi_free_vid_buf(vidb); |
| 975 | return 0; | 983 | return 0; |
| 976 | } | 984 | } |
| @@ -1093,7 +1101,7 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk) | |||
| 1093 | int err1; | 1101 | int err1; |
| 1094 | 1102 | ||
| 1095 | /* Re-schedule the LEB for erasure */ | 1103 | /* Re-schedule the LEB for erasure */ |
| 1096 | err1 = schedule_erase(ubi, e, vol_id, lnum, 0); | 1104 | err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false); |
| 1097 | if (err1) { | 1105 | if (err1) { |
| 1098 | wl_entry_destroy(ubi, e); | 1106 | wl_entry_destroy(ubi, e); |
| 1099 | err = err1; | 1107 | err = err1; |
| @@ -1274,7 +1282,7 @@ retry: | |||
| 1274 | } | 1282 | } |
| 1275 | spin_unlock(&ubi->wl_lock); | 1283 | spin_unlock(&ubi->wl_lock); |
| 1276 | 1284 | ||
| 1277 | err = schedule_erase(ubi, e, vol_id, lnum, torture); | 1285 | err = schedule_erase(ubi, e, vol_id, lnum, torture, false); |
| 1278 | if (err) { | 1286 | if (err) { |
| 1279 | spin_lock(&ubi->wl_lock); | 1287 | spin_lock(&ubi->wl_lock); |
| 1280 | wl_tree_add(e, &ubi->used); | 1288 | wl_tree_add(e, &ubi->used); |
| @@ -1565,7 +1573,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) | |||
| 1565 | e->pnum = aeb->pnum; | 1573 | e->pnum = aeb->pnum; |
| 1566 | e->ec = aeb->ec; | 1574 | e->ec = aeb->ec; |
| 1567 | ubi->lookuptbl[e->pnum] = e; | 1575 | ubi->lookuptbl[e->pnum] = e; |
| 1568 | if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) { | 1576 | if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) { |
| 1569 | wl_entry_destroy(ubi, e); | 1577 | wl_entry_destroy(ubi, e); |
| 1570 | goto out_free; | 1578 | goto out_free; |
| 1571 | } | 1579 | } |
| @@ -1644,7 +1652,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) | |||
| 1644 | e->ec = aeb->ec; | 1652 | e->ec = aeb->ec; |
| 1645 | ubi_assert(!ubi->lookuptbl[e->pnum]); | 1653 | ubi_assert(!ubi->lookuptbl[e->pnum]); |
| 1646 | ubi->lookuptbl[e->pnum] = e; | 1654 | ubi->lookuptbl[e->pnum] = e; |
| 1647 | if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) { | 1655 | if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) { |
| 1648 | wl_entry_destroy(ubi, e); | 1656 | wl_entry_destroy(ubi, e); |
| 1649 | goto out_free; | 1657 | goto out_free; |
| 1650 | } | 1658 | } |
