| .. | .. |
|---|
| 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; |
|---|