463
int erst_get_record_id_begin(int *pos)
470
rc = mutex_lock_interruptible(&erst_record_id_cache.lock);
473
erst_record_id_cache.refcount++;
474
mutex_unlock(&erst_record_id_cache.lock);
480
EXPORT_SYMBOL_GPL(erst_get_record_id_begin);
482
/* erst_record_id_cache.lock must be held by caller */
483
static int __erst_record_id_cache_add_one(void)
485
u64 id, prev_id, first_id;
490
id = prev_id = first_id = APEI_ERST_INVALID_RECORD_ID;
492
raw_spin_lock_irqsave(&erst_lock, flags);
493
rc = __erst_get_next_record_id(&id);
494
raw_spin_unlock_irqrestore(&erst_lock, flags);
499
if (id == APEI_ERST_INVALID_RECORD_ID)
501
/* can not skip current ID, or loop back to first ID */
502
if (id == prev_id || id == first_id)
504
if (first_id == APEI_ERST_INVALID_RECORD_ID)
508
entries = erst_record_id_cache.entries;
509
for (i = 0; i < erst_record_id_cache.len; i++) {
510
if (entries[i] == id)
513
/* record id already in cache, try next */
514
if (i < erst_record_id_cache.len)
516
if (erst_record_id_cache.len >= erst_record_id_cache.size) {
517
int new_size, alloc_size;
520
new_size = erst_record_id_cache.size * 2;
521
new_size = clamp_val(new_size, ERST_RECORD_ID_CACHE_SIZE_MIN,
522
ERST_RECORD_ID_CACHE_SIZE_MAX);
523
if (new_size <= erst_record_id_cache.size) {
524
if (printk_ratelimit())
525
pr_warning(FW_WARN ERST_PFX
526
"too many record ID!\n");
529
alloc_size = new_size * sizeof(entries[0]);
530
if (alloc_size < PAGE_SIZE)
531
new_entries = kmalloc(alloc_size, GFP_KERNEL);
533
new_entries = vmalloc(alloc_size);
536
memcpy(new_entries, entries,
537
erst_record_id_cache.len * sizeof(entries[0]));
538
if (erst_record_id_cache.size < PAGE_SIZE)
542
erst_record_id_cache.entries = entries = new_entries;
543
erst_record_id_cache.size = new_size;
546
erst_record_id_cache.len++;
447
552
* Get the record ID of an existing error record on the persistent
448
553
* storage. If there is no error record on the persistent storage, the
449
554
* returned record_id is APEI_ERST_INVALID_RECORD_ID.
451
int erst_get_next_record_id(u64 *record_id)
556
int erst_get_record_id_next(int *pos, u64 *record_id)
456
561
if (erst_disable)
459
raw_spin_lock_irqsave(&erst_lock, flags);
460
rc = __erst_get_next_record_id(record_id);
461
raw_spin_unlock_irqrestore(&erst_lock, flags);
564
/* must be enclosed by erst_get_record_id_begin/end */
565
BUG_ON(!erst_record_id_cache.refcount);
566
BUG_ON(*pos < 0 || *pos > erst_record_id_cache.len);
568
mutex_lock(&erst_record_id_cache.lock);
569
entries = erst_record_id_cache.entries;
570
for (; *pos < erst_record_id_cache.len; (*pos)++)
571
if (entries[*pos] != APEI_ERST_INVALID_RECORD_ID)
573
/* found next record id in cache */
574
if (*pos < erst_record_id_cache.len) {
575
*record_id = entries[*pos];
580
/* Try to add one more record ID to cache */
581
rc = __erst_record_id_cache_add_one();
584
/* successfully add one new ID */
586
*record_id = erst_record_id_cache.entries[*pos];
591
*record_id = APEI_ERST_INVALID_RECORD_ID;
594
mutex_unlock(&erst_record_id_cache.lock);
465
EXPORT_SYMBOL_GPL(erst_get_next_record_id);
598
EXPORT_SYMBOL_GPL(erst_get_record_id_next);
600
/* erst_record_id_cache.lock must be held by caller */
601
static void __erst_record_id_cache_compact(void)
606
if (erst_record_id_cache.refcount)
609
entries = erst_record_id_cache.entries;
610
for (i = 0; i < erst_record_id_cache.len; i++) {
611
if (entries[i] == APEI_ERST_INVALID_RECORD_ID)
614
memcpy(&entries[wpos], &entries[i], sizeof(entries[i]));
617
erst_record_id_cache.len = wpos;
620
void erst_get_record_id_end(void)
623
* erst_disable != 0 should be detected by invoker via the
624
* return value of erst_get_record_id_begin/next, so this
625
* function should not be called for erst_disable != 0.
627
BUG_ON(erst_disable);
629
mutex_lock(&erst_record_id_cache.lock);
630
erst_record_id_cache.refcount--;
631
BUG_ON(erst_record_id_cache.refcount < 0);
632
__erst_record_id_cache_compact();
633
mutex_unlock(&erst_record_id_cache.lock);
635
EXPORT_SYMBOL_GPL(erst_get_record_id_end);
467
637
static int __erst_write_to_storage(u64 offset)
704
874
EXPORT_SYMBOL_GPL(erst_read);
707
* If return value > buflen, the buffer size is not big enough,
708
* else if return value = 0, there is no more record to read,
709
* else if return value < 0, something goes wrong,
710
* else everything is OK, and return value is record length
712
ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
722
raw_spin_lock_irqsave(&erst_lock, flags);
723
rc = __erst_get_next_record_id(&record_id);
725
raw_spin_unlock_irqrestore(&erst_lock, flags);
729
if (record_id == APEI_ERST_INVALID_RECORD_ID) {
730
raw_spin_unlock_irqrestore(&erst_lock, flags);
734
len = __erst_read(record_id, record, buflen);
735
raw_spin_unlock_irqrestore(&erst_lock, flags);
739
EXPORT_SYMBOL_GPL(erst_read_next);
741
876
int erst_clear(u64 record_id)
744
879
unsigned long flags;
746
882
if (erst_disable)
885
rc = mutex_lock_interruptible(&erst_record_id_cache.lock);
749
888
raw_spin_lock_irqsave(&erst_lock, flags);
750
889
if (erst_erange.attr & ERST_RANGE_NVRAM)
751
890
rc = __erst_clear_from_nvram(record_id);
753
892
rc = __erst_clear_from_storage(record_id);
754
893
raw_spin_unlock_irqrestore(&erst_lock, flags);
896
entries = erst_record_id_cache.entries;
897
for (i = 0; i < erst_record_id_cache.len; i++) {
898
if (entries[i] == record_id)
899
entries[i] = APEI_ERST_INVALID_RECORD_ID;
901
__erst_record_id_cache_compact();
903
mutex_unlock(&erst_record_id_cache.lock);
758
906
EXPORT_SYMBOL_GPL(erst_clear);
932
static int erst_open_pstore(struct pstore_info *psi);
933
static int erst_close_pstore(struct pstore_info *psi);
934
static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
935
struct timespec *time);
936
static u64 erst_writer(enum pstore_type_id type, size_t size);
938
static struct pstore_info erst_info = {
939
.owner = THIS_MODULE,
941
.open = erst_open_pstore,
942
.close = erst_close_pstore,
944
.write = erst_writer,
948
#define CPER_CREATOR_PSTORE \
949
UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \
950
0x64, 0x90, 0xb8, 0x9d)
951
#define CPER_SECTION_TYPE_DMESG \
952
UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \
953
0x94, 0x19, 0xeb, 0x12)
954
#define CPER_SECTION_TYPE_MCE \
955
UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
956
0x04, 0x4a, 0x38, 0xfc)
958
struct cper_pstore_record {
959
struct cper_record_header hdr;
960
struct cper_section_descriptor sec_hdr;
964
static int reader_pos;
966
static int erst_open_pstore(struct pstore_info *psi)
973
rc = erst_get_record_id_begin(&reader_pos);
978
static int erst_close_pstore(struct pstore_info *psi)
980
erst_get_record_id_end();
985
static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
986
struct timespec *time)
991
struct cper_pstore_record *rcd = (struct cper_pstore_record *)
992
(erst_info.buf - sizeof(*rcd));
998
rc = erst_get_record_id_next(&reader_pos, &record_id);
1002
/* no more record */
1003
if (record_id == APEI_ERST_INVALID_RECORD_ID) {
1008
len = erst_read(record_id, &rcd->hdr, sizeof(*rcd) +
1010
/* The record may be cleared by others, try read next record */
1017
if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0)
1021
if (uuid_le_cmp(rcd->sec_hdr.section_type,
1022
CPER_SECTION_TYPE_DMESG) == 0)
1023
*type = PSTORE_TYPE_DMESG;
1024
else if (uuid_le_cmp(rcd->sec_hdr.section_type,
1025
CPER_SECTION_TYPE_MCE) == 0)
1026
*type = PSTORE_TYPE_MCE;
1028
*type = PSTORE_TYPE_UNKNOWN;
1030
if (rcd->hdr.validation_bits & CPER_VALID_TIMESTAMP)
1031
time->tv_sec = rcd->hdr.timestamp;
1037
return (rc < 0) ? rc : (len - sizeof(*rcd));
1040
static u64 erst_writer(enum pstore_type_id type, size_t size)
1042
struct cper_pstore_record *rcd = (struct cper_pstore_record *)
1043
(erst_info.buf - sizeof(*rcd));
1045
memset(rcd, 0, sizeof(*rcd));
1046
memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
1047
rcd->hdr.revision = CPER_RECORD_REV;
1048
rcd->hdr.signature_end = CPER_SIG_END;
1049
rcd->hdr.section_count = 1;
1050
rcd->hdr.error_severity = CPER_SEV_FATAL;
1051
/* timestamp valid. platform_id, partition_id are invalid */
1052
rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP;
1053
rcd->hdr.timestamp = get_seconds();
1054
rcd->hdr.record_length = sizeof(*rcd) + size;
1055
rcd->hdr.creator_id = CPER_CREATOR_PSTORE;
1056
rcd->hdr.notification_type = CPER_NOTIFY_MCE;
1057
rcd->hdr.record_id = cper_next_record_id();
1058
rcd->hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR;
1060
rcd->sec_hdr.section_offset = sizeof(*rcd);
1061
rcd->sec_hdr.section_length = size;
1062
rcd->sec_hdr.revision = CPER_SEC_REV;
1063
/* fru_id and fru_text is invalid */
1064
rcd->sec_hdr.validation_bits = 0;
1065
rcd->sec_hdr.flags = CPER_SEC_PRIMARY;
1067
case PSTORE_TYPE_DMESG:
1068
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
1070
case PSTORE_TYPE_MCE:
1071
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
1076
rcd->sec_hdr.section_severity = CPER_SEV_FATAL;
1078
erst_write(&rcd->hdr);
1080
return rcd->hdr.record_id;
784
1083
static int __init erst_init(void)