Skip to content

Commit c3481b6

Browse files
aeglrafaeljw
authored andcommitted
ACPI: APEI: Better fix to avoid spamming the console with old error logs
The fix in commit 3f8dec1 ("ACPI/APEI: Limit printable size of BERT table data") does not work as intended on systems where the BIOS has a fixed size block of memory for the BERT table, relying on s/w to quit when it finds a record with estatus->block_status == 0. On these systems all errors are suppressed because the check: if (region_len < ACPI_BERT_PRINT_MAX_LEN) always fails. New scheme skips individual CPER records that are too large, and also limits the total number of records that will be printed to 5. Fixes: 3f8dec1 ("ACPI/APEI: Limit printable size of BERT table data") Cc: All applicable <[email protected]> Signed-off-by: Tony Luck <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 55b3505 commit c3481b6

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

drivers/acpi/apei/bert.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,41 +29,53 @@
2929

3030
#undef pr_fmt
3131
#define pr_fmt(fmt) "BERT: " fmt
32+
33+
#define ACPI_BERT_PRINT_MAX_RECORDS 5
3234
#define ACPI_BERT_PRINT_MAX_LEN 1024
3335

3436
static int bert_disable;
3537

38+
/*
39+
* Print "all" the error records in the BERT table, but avoid huge spam to
40+
* the console if the BIOS included oversize records, or too many records.
41+
* Skipping some records here does not lose anything because the full
42+
* data is available to user tools in:
43+
* /sys/firmware/acpi/tables/data/BERT
44+
*/
3645
static void __init bert_print_all(struct acpi_bert_region *region,
3746
unsigned int region_len)
3847
{
3948
struct acpi_hest_generic_status *estatus =
4049
(struct acpi_hest_generic_status *)region;
4150
int remain = region_len;
51+
int printed = 0, skipped = 0;
4252
u32 estatus_len;
4353

4454
while (remain >= sizeof(struct acpi_bert_region)) {
4555
estatus_len = cper_estatus_len(estatus);
4656
if (remain < estatus_len) {
4757
pr_err(FW_BUG "Truncated status block (length: %u).\n",
4858
estatus_len);
49-
return;
59+
break;
5060
}
5161

5262
/* No more error records. */
5363
if (!estatus->block_status)
54-
return;
64+
break;
5565

5666
if (cper_estatus_check(estatus)) {
5767
pr_err(FW_BUG "Invalid error record.\n");
58-
return;
68+
break;
5969
}
6070

61-
pr_info_once("Error records from previous boot:\n");
62-
if (region_len < ACPI_BERT_PRINT_MAX_LEN)
71+
if (estatus_len < ACPI_BERT_PRINT_MAX_LEN &&
72+
printed < ACPI_BERT_PRINT_MAX_RECORDS) {
73+
pr_info_once("Error records from previous boot:\n");
6374
cper_estatus_print(KERN_INFO HW_ERR, estatus);
64-
else
65-
pr_info_once("Max print length exceeded, table data is available at:\n"
66-
"/sys/firmware/acpi/tables/data/BERT");
75+
printed++;
76+
} else {
77+
skipped++;
78+
}
6779

6880
/*
6981
* Because the boot error source is "one-time polled" type,
@@ -75,6 +87,9 @@ static void __init bert_print_all(struct acpi_bert_region *region,
7587
estatus = (void *)estatus + estatus_len;
7688
remain -= estatus_len;
7789
}
90+
91+
if (skipped)
92+
pr_info(HW_ERR "Skipped %d error records\n", skipped);
7893
}
7994

8095
static int __init setup_bert_disable(char *str)

0 commit comments

Comments
 (0)