.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2012 Linutronix GmbH |
---|
3 | 4 | * Copyright (c) 2014 sigma star gmbh |
---|
4 | 5 | * Author: Richard Weinberger <richard@nod.at> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; version 2. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, |
---|
11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
---|
13 | | - * the GNU General Public License for more details. |
---|
14 | | - * |
---|
15 | 6 | */ |
---|
16 | 7 | |
---|
17 | 8 | /** |
---|
.. | .. |
---|
106 | 97 | return e; |
---|
107 | 98 | } |
---|
108 | 99 | |
---|
| 100 | +/* |
---|
| 101 | + * has_enough_free_count - whether ubi has enough free pebs to fill fm pools |
---|
| 102 | + * @ubi: UBI device description object |
---|
| 103 | + * @is_wl_pool: whether UBI is filling wear leveling pool |
---|
| 104 | + * |
---|
| 105 | + * This helper function checks whether there are enough free pebs (deducted |
---|
| 106 | + * by fastmap pebs) to fill fm_pool and fm_wl_pool, above rule works after |
---|
| 107 | + * there is at least one of free pebs is filled into fm_wl_pool. |
---|
| 108 | + * For wear leveling pool, UBI should also reserve free pebs for bad pebs |
---|
| 109 | + * handling, because there maybe no enough free pebs for user volumes after |
---|
| 110 | + * producing new bad pebs. |
---|
| 111 | + */ |
---|
| 112 | +static bool has_enough_free_count(struct ubi_device *ubi, bool is_wl_pool) |
---|
| 113 | +{ |
---|
| 114 | + int fm_used = 0; // fastmap non anchor pebs. |
---|
| 115 | + int beb_rsvd_pebs; |
---|
| 116 | + |
---|
| 117 | + if (!ubi->free.rb_node) |
---|
| 118 | + return false; |
---|
| 119 | + |
---|
| 120 | + beb_rsvd_pebs = is_wl_pool ? ubi->beb_rsvd_pebs : 0; |
---|
| 121 | + if (ubi->fm_wl_pool.size > 0 && !(ubi->ro_mode || ubi->fm_disabled)) |
---|
| 122 | + fm_used = ubi->fm_size / ubi->leb_size - 1; |
---|
| 123 | + |
---|
| 124 | + return ubi->free_count - beb_rsvd_pebs > fm_used; |
---|
| 125 | +} |
---|
| 126 | + |
---|
109 | 127 | /** |
---|
110 | 128 | * ubi_refill_pools - refills all fastmap PEB pools. |
---|
111 | 129 | * @ubi: UBI device description object |
---|
.. | .. |
---|
125 | 143 | wl_pool->size = 0; |
---|
126 | 144 | pool->size = 0; |
---|
127 | 145 | |
---|
| 146 | + if (ubi->fm_anchor) { |
---|
| 147 | + wl_tree_add(ubi->fm_anchor, &ubi->free); |
---|
| 148 | + ubi->free_count++; |
---|
| 149 | + ubi->fm_anchor = NULL; |
---|
| 150 | + } |
---|
| 151 | + |
---|
| 152 | + if (!ubi->fm_disabled) |
---|
| 153 | + /* |
---|
| 154 | + * All available PEBs are in ubi->free, now is the time to get |
---|
| 155 | + * the best anchor PEBs. |
---|
| 156 | + */ |
---|
| 157 | + ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1); |
---|
| 158 | + |
---|
128 | 159 | for (;;) { |
---|
129 | 160 | enough = 0; |
---|
130 | 161 | if (pool->size < pool->max_size) { |
---|
131 | | - if (!ubi->free.rb_node) |
---|
| 162 | + if (!has_enough_free_count(ubi, false)) |
---|
132 | 163 | break; |
---|
133 | 164 | |
---|
134 | 165 | e = wl_get_wle(ubi); |
---|
.. | .. |
---|
141 | 172 | enough++; |
---|
142 | 173 | |
---|
143 | 174 | if (wl_pool->size < wl_pool->max_size) { |
---|
144 | | - if (!ubi->free.rb_node || |
---|
145 | | - (ubi->free_count - ubi->beb_rsvd_pebs < 5)) |
---|
| 175 | + if (!has_enough_free_count(ubi, true)) |
---|
146 | 176 | break; |
---|
147 | 177 | |
---|
148 | 178 | e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); |
---|
.. | .. |
---|
199 | 229 | */ |
---|
200 | 230 | int ubi_wl_get_peb(struct ubi_device *ubi) |
---|
201 | 231 | { |
---|
202 | | - int ret, retried = 0; |
---|
| 232 | + int ret, attempts = 0; |
---|
203 | 233 | struct ubi_fm_pool *pool = &ubi->fm_pool; |
---|
204 | 234 | struct ubi_fm_pool *wl_pool = &ubi->fm_wl_pool; |
---|
205 | 235 | |
---|
.. | .. |
---|
224 | 254 | |
---|
225 | 255 | if (pool->used == pool->size) { |
---|
226 | 256 | spin_unlock(&ubi->wl_lock); |
---|
227 | | - if (retried) { |
---|
| 257 | + attempts++; |
---|
| 258 | + if (attempts == 10) { |
---|
228 | 259 | ubi_err(ubi, "Unable to get a free PEB from user WL pool"); |
---|
229 | 260 | ret = -ENOSPC; |
---|
230 | 261 | goto out; |
---|
231 | 262 | } |
---|
232 | | - retried = 1; |
---|
233 | 263 | up_read(&ubi->fm_eba_sem); |
---|
234 | 264 | ret = produce_free_peb(ubi); |
---|
235 | 265 | if (ret < 0) { |
---|
.. | .. |
---|
298 | 328 | return 0; |
---|
299 | 329 | } |
---|
300 | 330 | |
---|
301 | | - /* No luck, trigger wear leveling to produce a new anchor PEB */ |
---|
302 | 331 | ubi->fm_do_produce_anchor = 1; |
---|
| 332 | + /* No luck, trigger wear leveling to produce a new anchor PEB. */ |
---|
303 | 333 | if (ubi->wl_scheduled) { |
---|
304 | 334 | spin_unlock(&ubi->wl_lock); |
---|
305 | 335 | return 0; |
---|