|
89 | 89 | #include <linux/crc32.h> |
90 | 90 | #include <linux/freezer.h> |
91 | 91 | #include <linux/kthread.h> |
| 92 | +#include <linux/reboot.h> |
92 | 93 | #include "ubi.h" |
93 | 94 | #include "wl.h" |
94 | 95 |
|
@@ -127,6 +128,8 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, |
127 | 128 | struct ubi_wl_entry *e, struct rb_root *root); |
128 | 129 | static int self_check_in_pq(const struct ubi_device *ubi, |
129 | 130 | struct ubi_wl_entry *e); |
| 131 | +static int ubi_wl_reboot_notifier(struct notifier_block *n, |
| 132 | + unsigned long state, void *cmd); |
130 | 133 |
|
131 | 134 | /** |
132 | 135 | * wl_tree_add - add a wear-leveling entry to a WL RB-tree. |
@@ -683,7 +686,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, |
683 | 686 | ubi_assert(!ubi->move_to_put); |
684 | 687 |
|
685 | 688 | #ifdef CONFIG_MTD_UBI_FASTMAP |
686 | | - if (!next_peb_for_wl(ubi) || |
| 689 | + if (!next_peb_for_wl(ubi, true) || |
687 | 690 | #else |
688 | 691 | if (!ubi->free.rb_node || |
689 | 692 | #endif |
@@ -846,7 +849,14 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, |
846 | 849 | goto out_not_moved; |
847 | 850 | } |
848 | 851 | if (err == MOVE_RETRY) { |
849 | | - scrubbing = 1; |
| 852 | + /* |
| 853 | + * For source PEB: |
| 854 | + * 1. The scrubbing is set for scrub type PEB, it will |
| 855 | + * be put back into ubi->scrub list. |
| 856 | + * 2. Non-scrub type PEB will be put back into ubi->used |
| 857 | + * list. |
| 858 | + */ |
| 859 | + keep = 1; |
850 | 860 | dst_leb_clean = 1; |
851 | 861 | goto out_not_moved; |
852 | 862 | } |
@@ -1943,6 +1953,13 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) |
1943 | 1953 | if (!ubi->ro_mode && !ubi->fm_disabled) |
1944 | 1954 | ubi_ensure_anchor_pebs(ubi); |
1945 | 1955 | #endif |
| 1956 | + |
| 1957 | + if (!ubi->wl_reboot_notifier.notifier_call) { |
| 1958 | + ubi->wl_reboot_notifier.notifier_call = ubi_wl_reboot_notifier; |
| 1959 | + ubi->wl_reboot_notifier.priority = 1; /* Higher than MTD */ |
| 1960 | + register_reboot_notifier(&ubi->wl_reboot_notifier); |
| 1961 | + } |
| 1962 | + |
1946 | 1963 | return 0; |
1947 | 1964 |
|
1948 | 1965 | out_free: |
@@ -1988,6 +2005,17 @@ void ubi_wl_close(struct ubi_device *ubi) |
1988 | 2005 | kfree(ubi->lookuptbl); |
1989 | 2006 | } |
1990 | 2007 |
|
| 2008 | +static int ubi_wl_reboot_notifier(struct notifier_block *n, |
| 2009 | + unsigned long state, void *cmd) |
| 2010 | +{ |
| 2011 | + struct ubi_device *ubi; |
| 2012 | + |
| 2013 | + ubi = container_of(n, struct ubi_device, wl_reboot_notifier); |
| 2014 | + ubi_wl_close(ubi); |
| 2015 | + |
| 2016 | + return NOTIFY_DONE; |
| 2017 | +} |
| 2018 | + |
1991 | 2019 | /** |
1992 | 2020 | * self_check_ec - make sure that the erase counter of a PEB is correct. |
1993 | 2021 | * @ubi: UBI device description object |
|
0 commit comments