Skip to content

Commit a090931

Browse files
liuxp11rafaeljw
authored andcommitted
ACPI: APEI: Fix missing ERST record id
Read a record is cleared by others, but the deleted record cache entry is still created by erst_get_record_id_next. When next enumerate the records, get the cached deleted record, then erst_read() return -ENOENT and try to get next record, loop back to first ID will return 0 in function __erst_record_id_cache_add_one and then set record_id as APEI_ERST_INVALID_RECORD_ID, finished this time read operation. It will result in read the records just in the cache hereafter. This patch cleared the deleted record cache, fix the issue that "./erst-inject -p" shows record counts not equal to "./erst-inject -n". A reproducer of the problem(retry many times): [root@localhost erst-inject]# ./erst-inject -c 0xaaaaa00011 [root@localhost erst-inject]# ./erst-inject -p rc: 273 rcd sig: CPER rcd id: 0xaaaaa00012 rc: 273 rcd sig: CPER rcd id: 0xaaaaa00013 rc: 273 rcd sig: CPER rcd id: 0xaaaaa00014 [root@localhost erst-inject]# ./erst-inject -i 0xaaaaa000006 [root@localhost erst-inject]# ./erst-inject -i 0xaaaaa000007 [root@localhost erst-inject]# ./erst-inject -i 0xaaaaa000008 [root@localhost erst-inject]# ./erst-inject -p rc: 273 rcd sig: CPER rcd id: 0xaaaaa00012 rc: 273 rcd sig: CPER rcd id: 0xaaaaa00013 rc: 273 rcd sig: CPER rcd id: 0xaaaaa00014 [root@localhost erst-inject]# ./erst-inject -n total error record count: 6 Signed-off-by: Liu Xinpeng <[email protected]> Reviewed-by: Tony Luck <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent ce522ba commit a090931

File tree

4 files changed

+78
-12
lines changed

4 files changed

+78
-12
lines changed

arch/x86/kernel/cpu/mce/apei.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,14 @@ ssize_t apei_read_mce(struct mce *m, u64 *record_id)
177177
/* no more record */
178178
if (*record_id == APEI_ERST_INVALID_RECORD_ID)
179179
goto out;
180-
rc = erst_read(*record_id, &rcd.hdr, sizeof(rcd));
180+
rc = erst_read_record(*record_id, &rcd.hdr, sizeof(rcd), sizeof(rcd),
181+
&CPER_CREATOR_MCE);
181182
/* someone else has cleared the record, try next one */
182183
if (rc == -ENOENT)
183184
goto retry;
184185
else if (rc < 0)
185186
goto out;
186-
/* try to skip other type records in storage */
187-
else if (rc != sizeof(rcd) ||
188-
!guid_equal(&rcd.hdr.creator_id, &CPER_CREATOR_MCE))
189-
goto retry;
187+
190188
memcpy(m, &rcd.mce, sizeof(*m));
191189
rc = sizeof(*m);
192190
out:

drivers/acpi/apei/erst-dbg.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf,
111111
goto out;
112112
}
113113
retry:
114-
rc = len = erst_read(id, erst_dbg_buf, erst_dbg_buf_len);
114+
rc = len = erst_read_record(id, erst_dbg_buf, erst_dbg_buf_len,
115+
erst_dbg_buf_len, NULL);
115116
/* The record may be cleared by others, try read next record */
116117
if (rc == -ENOENT)
117118
goto retry_next;

drivers/acpi/apei/erst.c

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,74 @@ ssize_t erst_read(u64 record_id, struct cper_record_header *record,
856856
}
857857
EXPORT_SYMBOL_GPL(erst_read);
858858

859+
static void erst_clear_cache(u64 record_id)
860+
{
861+
int i;
862+
u64 *entries;
863+
864+
mutex_lock(&erst_record_id_cache.lock);
865+
866+
entries = erst_record_id_cache.entries;
867+
for (i = 0; i < erst_record_id_cache.len; i++) {
868+
if (entries[i] == record_id)
869+
entries[i] = APEI_ERST_INVALID_RECORD_ID;
870+
}
871+
__erst_record_id_cache_compact();
872+
873+
mutex_unlock(&erst_record_id_cache.lock);
874+
}
875+
876+
ssize_t erst_read_record(u64 record_id, struct cper_record_header *record,
877+
size_t buflen, size_t recordlen, const guid_t *creatorid)
878+
{
879+
ssize_t len;
880+
881+
/*
882+
* if creatorid is NULL, read any record for erst-dbg module
883+
*/
884+
if (creatorid == NULL) {
885+
len = erst_read(record_id, record, buflen);
886+
if (len == -ENOENT)
887+
erst_clear_cache(record_id);
888+
889+
return len;
890+
}
891+
892+
len = erst_read(record_id, record, buflen);
893+
/*
894+
* if erst_read return value is -ENOENT skip to next record_id,
895+
* and clear the record_id cache.
896+
*/
897+
if (len == -ENOENT) {
898+
erst_clear_cache(record_id);
899+
goto out;
900+
}
901+
902+
if (len < 0)
903+
goto out;
904+
905+
/*
906+
* if erst_read return value is less than record head length,
907+
* consider it as -EIO, and clear the record_id cache.
908+
*/
909+
if (len < recordlen) {
910+
len = -EIO;
911+
erst_clear_cache(record_id);
912+
goto out;
913+
}
914+
915+
/*
916+
* if creatorid is not wanted, consider it as not found,
917+
* for skipping to next record_id.
918+
*/
919+
if (!guid_equal(&record->creator_id, creatorid))
920+
len = -ENOENT;
921+
922+
out:
923+
return len;
924+
}
925+
EXPORT_SYMBOL_GPL(erst_read_record);
926+
859927
int erst_clear(u64 record_id)
860928
{
861929
int rc, i;
@@ -996,16 +1064,13 @@ static ssize_t erst_reader(struct pstore_record *record)
9961064
goto out;
9971065
}
9981066

999-
len = erst_read(record_id, &rcd->hdr, rcd_len);
1067+
len = erst_read_record(record_id, &rcd->hdr, rcd_len, sizeof(*rcd),
1068+
&CPER_CREATOR_PSTORE);
10001069
/* The record may be cleared by others, try read next record */
10011070
if (len == -ENOENT)
10021071
goto skip;
1003-
else if (len < 0 || len < sizeof(*rcd)) {
1004-
rc = -EIO;
1072+
else if (len < 0)
10051073
goto out;
1006-
}
1007-
if (!guid_equal(&rcd->hdr.creator_id, &CPER_CREATOR_PSTORE))
1008-
goto skip;
10091074

10101075
record->buf = kmalloc(len, GFP_KERNEL);
10111076
if (record->buf == NULL) {

include/acpi/apei.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ int erst_get_record_id_next(int *pos, u64 *record_id);
4646
void erst_get_record_id_end(void);
4747
ssize_t erst_read(u64 record_id, struct cper_record_header *record,
4848
size_t buflen);
49+
ssize_t erst_read_record(u64 record_id, struct cper_record_header *record,
50+
size_t buflen, size_t recordlen, const guid_t *creatorid);
4951
int erst_clear(u64 record_id);
5052

5153
int arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr, void *data);

0 commit comments

Comments
 (0)