@@ -150,6 +150,8 @@ static unsigned int max_nr_fru;
150
150
/* Total length of record including headers and list of descriptor entries. */
151
151
static size_t max_rec_len ;
152
152
153
+ #define FMPM_MAX_REC_LEN (sizeof(struct fru_rec) + (sizeof(struct cper_fru_poison_desc) * 255))
154
+
153
155
/* Total number of SPA entries across all FRUs. */
154
156
static unsigned int spa_nr_entries ;
155
157
@@ -475,6 +477,16 @@ static void set_rec_fields(struct fru_rec *rec)
475
477
struct cper_section_descriptor * sec_desc = & rec -> sec_desc ;
476
478
struct cper_record_header * hdr = & rec -> hdr ;
477
479
480
+ /*
481
+ * This is a saved record created with fewer max_nr_entries.
482
+ * Update the record lengths and keep everything else as-is.
483
+ */
484
+ if (hdr -> record_length && hdr -> record_length < max_rec_len ) {
485
+ pr_debug ("Growing record 0x%016llx from %u to %zu bytes\n" ,
486
+ hdr -> record_id , hdr -> record_length , max_rec_len );
487
+ goto update_lengths ;
488
+ }
489
+
478
490
memcpy (hdr -> signature , CPER_SIG_RECORD , CPER_SIG_SIZE );
479
491
hdr -> revision = CPER_RECORD_REV ;
480
492
hdr -> signature_end = CPER_SIG_END ;
@@ -489,19 +501,21 @@ static void set_rec_fields(struct fru_rec *rec)
489
501
hdr -> error_severity = CPER_SEV_RECOVERABLE ;
490
502
491
503
hdr -> validation_bits = 0 ;
492
- hdr -> record_length = max_rec_len ;
493
504
hdr -> creator_id = CPER_CREATOR_FMP ;
494
505
hdr -> notification_type = CPER_NOTIFY_MCE ;
495
506
hdr -> record_id = cper_next_record_id ();
496
507
hdr -> flags = CPER_HW_ERROR_FLAGS_PREVERR ;
497
508
498
509
sec_desc -> section_offset = sizeof (struct cper_record_header );
499
- sec_desc -> section_length = max_rec_len - sizeof (struct cper_record_header );
500
510
sec_desc -> revision = CPER_SEC_REV ;
501
511
sec_desc -> validation_bits = 0 ;
502
512
sec_desc -> flags = CPER_SEC_PRIMARY ;
503
513
sec_desc -> section_type = CPER_SECTION_TYPE_FMP ;
504
514
sec_desc -> section_severity = CPER_SEV_RECOVERABLE ;
515
+
516
+ update_lengths :
517
+ hdr -> record_length = max_rec_len ;
518
+ sec_desc -> section_length = max_rec_len - sizeof (struct cper_record_header );
505
519
}
506
520
507
521
static int save_new_records (void )
@@ -512,16 +526,18 @@ static int save_new_records(void)
512
526
int ret = 0 ;
513
527
514
528
for_each_fru (i , rec ) {
515
- if (rec -> hdr .record_length )
529
+ /* No need to update saved records that match the current record size. */
530
+ if (rec -> hdr .record_length == max_rec_len )
516
531
continue ;
517
532
533
+ if (!rec -> hdr .record_length )
534
+ set_bit (i , new_records );
535
+
518
536
set_rec_fields (rec );
519
537
520
538
ret = update_record_on_storage (rec );
521
539
if (ret )
522
540
goto out_clear ;
523
-
524
- set_bit (i , new_records );
525
541
}
526
542
527
543
return ret ;
@@ -641,12 +657,7 @@ static int get_saved_records(void)
641
657
int ret , pos ;
642
658
ssize_t len ;
643
659
644
- /*
645
- * Assume saved records match current max size.
646
- *
647
- * However, this may not be true depending on module parameters.
648
- */
649
- old = kmalloc (max_rec_len , GFP_KERNEL );
660
+ old = kmalloc (FMPM_MAX_REC_LEN , GFP_KERNEL );
650
661
if (!old ) {
651
662
ret = - ENOMEM ;
652
663
goto out ;
@@ -663,21 +674,31 @@ static int get_saved_records(void)
663
674
* Make sure to clear temporary buffer between reads to avoid
664
675
* leftover data from records of various sizes.
665
676
*/
666
- memset (old , 0 , max_rec_len );
677
+ memset (old , 0 , FMPM_MAX_REC_LEN );
667
678
668
- len = erst_read_record (record_id , & old -> hdr , max_rec_len ,
679
+ len = erst_read_record (record_id , & old -> hdr , FMPM_MAX_REC_LEN ,
669
680
sizeof (struct fru_rec ), & CPER_CREATOR_FMP );
670
681
if (len < 0 )
671
682
continue ;
672
683
673
- if (len > max_rec_len ) {
674
- pr_debug ("Found record larger than max_rec_len\n" );
684
+ new = get_valid_record (old );
685
+ if (!new ) {
686
+ erst_clear (record_id );
675
687
continue ;
676
688
}
677
689
678
- new = get_valid_record (old );
679
- if (!new )
680
- erst_clear (record_id );
690
+ if (len > max_rec_len ) {
691
+ unsigned int saved_nr_entries ;
692
+
693
+ saved_nr_entries = len - sizeof (struct fru_rec );
694
+ saved_nr_entries /= sizeof (struct cper_fru_poison_desc );
695
+
696
+ pr_warn ("Saved record found with %u entries.\n" , saved_nr_entries );
697
+ pr_warn ("Please increase max_nr_entries to %u.\n" , saved_nr_entries );
698
+
699
+ ret = - EINVAL ;
700
+ goto out_end ;
701
+ }
681
702
682
703
/* Restore the record */
683
704
memcpy (new , old , len );
0 commit comments