Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ubi: fastmap: Check wl_pool for free peb before wear leveling

UBI fetches free peb from wl_pool during wear leveling, so UBI should
check wl_pool's empty status before wear leveling. Otherwise, UBI will
miss wear leveling chances when free pebs are run out.

Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>

authored by

Zhihao Cheng and committed by
Richard Weinberger
14072ee3 d09e9a2b

+66 -2
+52
drivers/mtd/ubi/fastmap-wl.c
··· 275 275 return ret; 276 276 } 277 277 278 + /** 279 + * next_peb_for_wl - returns next PEB to be used internally by the 280 + * WL sub-system. 281 + * 282 + * @ubi: UBI device description object 283 + */ 284 + static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi) 285 + { 286 + struct ubi_fm_pool *pool = &ubi->fm_wl_pool; 287 + int pnum; 288 + 289 + if (pool->used == pool->size) 290 + return NULL; 291 + 292 + pnum = pool->pebs[pool->used]; 293 + return ubi->lookuptbl[pnum]; 294 + } 295 + 296 + /** 297 + * need_wear_leveling - checks whether to trigger a wear leveling work. 298 + * UBI fetches free PEB from wl_pool, we check free PEBs from both 'wl_pool' 299 + * and 'ubi->free', because free PEB in 'ubi->free' tree maybe moved into 300 + * 'wl_pool' by ubi_refill_pools(). 301 + * 302 + * @ubi: UBI device description object 303 + */ 304 + static bool need_wear_leveling(struct ubi_device *ubi) 305 + { 306 + int ec; 307 + struct ubi_wl_entry *e; 308 + 309 + if (!ubi->used.rb_node) 310 + return false; 311 + 312 + e = next_peb_for_wl(ubi); 313 + if (!e) { 314 + if (!ubi->free.rb_node) 315 + return false; 316 + e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); 317 + ec = e->ec; 318 + } else { 319 + ec = e->ec; 320 + if (ubi->free.rb_node) { 321 + e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); 322 + ec = max(ec, e->ec); 323 + } 324 + } 325 + e = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, u.rb); 326 + 327 + return ec - e->ec >= UBI_WL_THRESHOLD; 328 + } 329 + 278 330 /* get_peb_for_wl - returns a PEB to be used internally by the WL sub-system. 279 331 * 280 332 * @ubi: UBI device description object
+12 -2
drivers/mtd/ubi/wl.c
··· 670 670 ubi_assert(!ubi->move_from && !ubi->move_to); 671 671 ubi_assert(!ubi->move_to_put); 672 672 673 + #ifdef CONFIG_MTD_UBI_FASTMAP 674 + if (!next_peb_for_wl(ubi) || 675 + #else 673 676 if (!ubi->free.rb_node || 677 + #endif 674 678 (!ubi->used.rb_node && !ubi->scrub.rb_node)) { 675 679 /* 676 680 * No free physical eraseblocks? Well, they must be waiting in ··· 1007 1003 static int ensure_wear_leveling(struct ubi_device *ubi, int nested) 1008 1004 { 1009 1005 int err = 0; 1010 - struct ubi_wl_entry *e1; 1011 - struct ubi_wl_entry *e2; 1012 1006 struct ubi_work *wrk; 1013 1007 1014 1008 spin_lock(&ubi->wl_lock); ··· 1019 1017 * the WL worker has to be scheduled anyway. 1020 1018 */ 1021 1019 if (!ubi->scrub.rb_node) { 1020 + #ifdef CONFIG_MTD_UBI_FASTMAP 1021 + if (!need_wear_leveling(ubi)) 1022 + goto out_unlock; 1023 + #else 1024 + struct ubi_wl_entry *e1; 1025 + struct ubi_wl_entry *e2; 1026 + 1022 1027 if (!ubi->used.rb_node || !ubi->free.rb_node) 1023 1028 /* No physical eraseblocks - no deal */ 1024 1029 goto out_unlock; ··· 1041 1032 1042 1033 if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) 1043 1034 goto out_unlock; 1035 + #endif 1044 1036 dbg_wl("schedule wear-leveling"); 1045 1037 } else 1046 1038 dbg_wl("schedule scrubbing");
+2
drivers/mtd/ubi/wl.h
··· 5 5 static void update_fastmap_work_fn(struct work_struct *wrk); 6 6 static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root); 7 7 static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi); 8 + static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi); 9 + static bool need_wear_leveling(struct ubi_device *ubi); 8 10 static void ubi_fastmap_close(struct ubi_device *ubi); 9 11 static inline void ubi_fastmap_init(struct ubi_device *ubi, int *count) 10 12 {