@@ -150,6 +150,8 @@ static unsigned int max_nr_fru;
150150/* Total length of record including headers and list of descriptor entries. */
151151static size_t max_rec_len ;
152152
153+ #define FMPM_MAX_REC_LEN (sizeof(struct fru_rec) + (sizeof(struct cper_fru_poison_desc) * 255))
154+
153155/* Total number of SPA entries across all FRUs. */
154156static unsigned int spa_nr_entries ;
155157
@@ -475,6 +477,16 @@ static void set_rec_fields(struct fru_rec *rec)
475477 struct cper_section_descriptor * sec_desc = & rec -> sec_desc ;
476478 struct cper_record_header * hdr = & rec -> hdr ;
477479
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+
478490 memcpy (hdr -> signature , CPER_SIG_RECORD , CPER_SIG_SIZE );
479491 hdr -> revision = CPER_RECORD_REV ;
480492 hdr -> signature_end = CPER_SIG_END ;
@@ -489,19 +501,21 @@ static void set_rec_fields(struct fru_rec *rec)
489501 hdr -> error_severity = CPER_SEV_RECOVERABLE ;
490502
491503 hdr -> validation_bits = 0 ;
492- hdr -> record_length = max_rec_len ;
493504 hdr -> creator_id = CPER_CREATOR_FMP ;
494505 hdr -> notification_type = CPER_NOTIFY_MCE ;
495506 hdr -> record_id = cper_next_record_id ();
496507 hdr -> flags = CPER_HW_ERROR_FLAGS_PREVERR ;
497508
498509 sec_desc -> section_offset = sizeof (struct cper_record_header );
499- sec_desc -> section_length = max_rec_len - sizeof (struct cper_record_header );
500510 sec_desc -> revision = CPER_SEC_REV ;
501511 sec_desc -> validation_bits = 0 ;
502512 sec_desc -> flags = CPER_SEC_PRIMARY ;
503513 sec_desc -> section_type = CPER_SECTION_TYPE_FMP ;
504514 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 );
505519}
506520
507521static int save_new_records (void )
@@ -512,16 +526,18 @@ static int save_new_records(void)
512526 int ret = 0 ;
513527
514528 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 )
516531 continue ;
517532
533+ if (!rec -> hdr .record_length )
534+ set_bit (i , new_records );
535+
518536 set_rec_fields (rec );
519537
520538 ret = update_record_on_storage (rec );
521539 if (ret )
522540 goto out_clear ;
523-
524- set_bit (i , new_records );
525541 }
526542
527543 return ret ;
@@ -641,12 +657,7 @@ static int get_saved_records(void)
641657 int ret , pos ;
642658 ssize_t len ;
643659
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 );
650661 if (!old ) {
651662 ret = - ENOMEM ;
652663 goto out ;
@@ -663,21 +674,31 @@ static int get_saved_records(void)
663674 * Make sure to clear temporary buffer between reads to avoid
664675 * leftover data from records of various sizes.
665676 */
666- memset (old , 0 , max_rec_len );
677+ memset (old , 0 , FMPM_MAX_REC_LEN );
667678
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 ,
669680 sizeof (struct fru_rec ), & CPER_CREATOR_FMP );
670681 if (len < 0 )
671682 continue ;
672683
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 );
675687 continue ;
676688 }
677689
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+ }
681702
682703 /* Restore the record */
683704 memcpy (new , old , len );
0 commit comments