mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 13:51:44 +00:00
9aa272b492
Running mtd-utils/tests/ubi-tests/io_basic.c could cause soft lockup or watchdog reset. It is because *updatevol* will perform ubi_check_volume() after updating finish and this function will full scan the updated lebs if the volume is initialized as STATIC_VOLUME. This patch adds *cond_resched()* in the loop of lebs scan to avoid soft lockup. Helped by Richard Weinberger <richard@nod.at> [ 2158.067096] INFO: rcu_sched self-detected stall on CPU { 1} (t=2101 jiffies g=1606 c=1605 q=56) [ 2158.172867] CPU: 1 PID: 2073 Comm: io_basic Tainted: G O 3.10.53 #21 [ 2158.172898] [<c000f624>] (unwind_backtrace+0x0/0x120) from [<c000c294>] (show_stack+0x10/0x14) [ 2158.172918] [<c000c294>] (show_stack+0x10/0x14) from [<c008ac3c>] (rcu_check_callbacks+0x1c0/0x660) [ 2158.172936] [<c008ac3c>] (rcu_check_callbacks+0x1c0/0x660) from [<c002b480>] (update_process_times+0x38/0x64) [ 2158.172953] [<c002b480>] (update_process_times+0x38/0x64) from [<c005ff38>] (tick_sched_handle+0x54/0x60) [ 2158.172966] [<c005ff38>] (tick_sched_handle+0x54/0x60) from [<c00601ac>] (tick_sched_timer+0x44/0x74) [ 2158.172978] [<c00601ac>] (tick_sched_timer+0x44/0x74) from [<c003f348>] (__run_hrtimer+0xc8/0x1b8) [ 2158.172992] [<c003f348>] (__run_hrtimer+0xc8/0x1b8) from [<c003fd9c>] (hrtimer_interrupt+0x128/0x2a4) [ 2158.173007] [<c003fd9c>] (hrtimer_interrupt+0x128/0x2a4) from [<c0246f1c>] (arch_timer_handler_virt+0x28/0x30) [ 2158.173022] [<c0246f1c>] (arch_timer_handler_virt+0x28/0x30) from [<c0086214>] (handle_percpu_devid_irq+0x9c/0x124) [ 2158.173036] [<c0086214>] (handle_percpu_devid_irq+0x9c/0x124) from [<c0082bd8>] (generic_handle_irq+0x20/0x30) [ 2158.173049] [<c0082bd8>] (generic_handle_irq+0x20/0x30) from [<c000969c>] (handle_IRQ+0x64/0x8c) [ 2158.173060] [<c000969c>] (handle_IRQ+0x64/0x8c) from [<c0008544>] (gic_handle_irq+0x3c/0x60) [ 2158.173074] [<c0008544>] (gic_handle_irq+0x3c/0x60) from [<c02f0f80>] (__irq_svc+0x40/0x50) [ 2158.173083] Exception stack(0xc4043c98 to 0xc4043ce0) [ 2158.173092] 3c80: c4043ce4 00000019 [ 2158.173102] 3ca0: 1f8a865f c050ad10 1f8a864c 00000031 c04b5970 0003ebce 00000000 f3550000 [ 2158.173113] 3cc0: bf00bc68 00000800 0003ebce c4043ce0 c0186d14 c0186cb8 80000013 ffffffff [ 2158.173130] [<c02f0f80>] (__irq_svc+0x40/0x50) from [<c0186cb8>] (read_current_timer+0x4/0x38) [ 2158.173145] [<c0186cb8>] (read_current_timer+0x4/0x38) from [<1f8a865f>] (0x1f8a865f) [ 2183.927097] BUG: soft lockup - CPU#1 stuck for 22s! [io_basic:2073] [ 2184.002229] Modules linked in: nandflash(O) [last unloaded: nandflash] Signed-off-by: Wang Kai <morgan.wang@huawei.com> Signed-off-by: hujianyang <hujianyang@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at>
156 lines
4.5 KiB
C
156 lines
4.5 KiB
C
/*
|
|
* Copyright (c) International Business Machines Corp., 2006
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
|
* the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Author: Artem Bityutskiy (Битюцкий Артём)
|
|
*/
|
|
|
|
/* Here we keep miscellaneous functions which are used all over the UBI code */
|
|
|
|
#include "ubi.h"
|
|
|
|
/**
|
|
* calc_data_len - calculate how much real data is stored in a buffer.
|
|
* @ubi: UBI device description object
|
|
* @buf: a buffer with the contents of the physical eraseblock
|
|
* @length: the buffer length
|
|
*
|
|
* This function calculates how much "real data" is stored in @buf and returnes
|
|
* the length. Continuous 0xFF bytes at the end of the buffer are not
|
|
* considered as "real data".
|
|
*/
|
|
int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf,
|
|
int length)
|
|
{
|
|
int i;
|
|
|
|
ubi_assert(!(length & (ubi->min_io_size - 1)));
|
|
|
|
for (i = length - 1; i >= 0; i--)
|
|
if (((const uint8_t *)buf)[i] != 0xFF)
|
|
break;
|
|
|
|
/* The resulting length must be aligned to the minimum flash I/O size */
|
|
length = ALIGN(i + 1, ubi->min_io_size);
|
|
return length;
|
|
}
|
|
|
|
/**
|
|
* ubi_check_volume - check the contents of a static volume.
|
|
* @ubi: UBI device description object
|
|
* @vol_id: ID of the volume to check
|
|
*
|
|
* This function checks if static volume @vol_id is corrupted by fully reading
|
|
* it and checking data CRC. This function returns %0 if the volume is not
|
|
* corrupted, %1 if it is corrupted and a negative error code in case of
|
|
* failure. Dynamic volumes are not checked and zero is returned immediately.
|
|
*/
|
|
int ubi_check_volume(struct ubi_device *ubi, int vol_id)
|
|
{
|
|
void *buf;
|
|
int err = 0, i;
|
|
struct ubi_volume *vol = ubi->volumes[vol_id];
|
|
|
|
if (vol->vol_type != UBI_STATIC_VOLUME)
|
|
return 0;
|
|
|
|
buf = vmalloc(vol->usable_leb_size);
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < vol->used_ebs; i++) {
|
|
int size;
|
|
|
|
cond_resched();
|
|
|
|
if (i == vol->used_ebs - 1)
|
|
size = vol->last_eb_bytes;
|
|
else
|
|
size = vol->usable_leb_size;
|
|
|
|
err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
|
|
if (err) {
|
|
if (mtd_is_eccerr(err))
|
|
err = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
vfree(buf);
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* ubi_update_reserved - update bad eraseblock handling accounting data.
|
|
* @ubi: UBI device description object
|
|
*
|
|
* This function calculates the gap between current number of PEBs reserved for
|
|
* bad eraseblock handling and the required level of PEBs that must be
|
|
* reserved, and if necessary, reserves more PEBs to fill that gap, according
|
|
* to availability. Should be called with ubi->volumes_lock held.
|
|
*/
|
|
void ubi_update_reserved(struct ubi_device *ubi)
|
|
{
|
|
int need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
|
|
|
|
if (need <= 0 || ubi->avail_pebs == 0)
|
|
return;
|
|
|
|
need = min_t(int, need, ubi->avail_pebs);
|
|
ubi->avail_pebs -= need;
|
|
ubi->rsvd_pebs += need;
|
|
ubi->beb_rsvd_pebs += need;
|
|
ubi_msg(ubi, "reserved more %d PEBs for bad PEB handling", need);
|
|
}
|
|
|
|
/**
|
|
* ubi_calculate_reserved - calculate how many PEBs must be reserved for bad
|
|
* eraseblock handling.
|
|
* @ubi: UBI device description object
|
|
*/
|
|
void ubi_calculate_reserved(struct ubi_device *ubi)
|
|
{
|
|
/*
|
|
* Calculate the actual number of PEBs currently needed to be reserved
|
|
* for future bad eraseblock handling.
|
|
*/
|
|
ubi->beb_rsvd_level = ubi->bad_peb_limit - ubi->bad_peb_count;
|
|
if (ubi->beb_rsvd_level < 0) {
|
|
ubi->beb_rsvd_level = 0;
|
|
ubi_warn(ubi, "number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)",
|
|
ubi->bad_peb_count, ubi->bad_peb_limit);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ubi_check_pattern - check if buffer contains only a certain byte pattern.
|
|
* @buf: buffer to check
|
|
* @patt: the pattern to check
|
|
* @size: buffer size in bytes
|
|
*
|
|
* This function returns %1 in there are only @patt bytes in @buf, and %0 if
|
|
* something else was also found.
|
|
*/
|
|
int ubi_check_pattern(const void *buf, uint8_t patt, int size)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < size; i++)
|
|
if (((const uint8_t *)buf)[i] != patt)
|
|
return 0;
|
|
return 1;
|
|
}
|