@@ -92,11 +92,14 @@ struct pstore_zone {
92
92
* @kpszs: kmsg dump storage zones
93
93
* @ppsz: pmsg storage zone
94
94
* @cpsz: console storage zone
95
+ * @fpszs: ftrace storage zones
95
96
* @kmsg_max_cnt: max count of @kpszs
96
97
* @kmsg_read_cnt: counter of total read kmsg dumps
97
98
* @kmsg_write_cnt: counter of total kmsg dump writes
98
99
* @pmsg_read_cnt: counter of total read pmsg zone
99
100
* @console_read_cnt: counter of total read console zone
101
+ * @ftrace_max_cnt: max count of @fpszs
102
+ * @ftrace_read_cnt: counter of max read ftrace zone
100
103
* @oops_counter: counter of oops dumps
101
104
* @panic_counter: counter of panic dumps
102
105
* @recovered: whether finished recovering data from storage
@@ -109,11 +112,14 @@ struct psz_context {
109
112
struct pstore_zone * * kpszs ;
110
113
struct pstore_zone * ppsz ;
111
114
struct pstore_zone * cpsz ;
115
+ struct pstore_zone * * fpszs ;
112
116
unsigned int kmsg_max_cnt ;
113
117
unsigned int kmsg_read_cnt ;
114
118
unsigned int kmsg_write_cnt ;
115
119
unsigned int pmsg_read_cnt ;
116
120
unsigned int console_read_cnt ;
121
+ unsigned int ftrace_max_cnt ;
122
+ unsigned int ftrace_read_cnt ;
117
123
/*
118
124
* These counters should be calculated during recovery.
119
125
* It records the oops/panic times after crashes rather than boots.
@@ -314,6 +320,8 @@ static void psz_flush_all_dirty_zones(struct work_struct *work)
314
320
ret |= psz_flush_dirty_zone (cxt -> cpsz );
315
321
if (cxt -> kpszs )
316
322
ret |= psz_flush_dirty_zones (cxt -> kpszs , cxt -> kmsg_max_cnt );
323
+ if (cxt -> fpszs )
324
+ ret |= psz_flush_dirty_zones (cxt -> fpszs , cxt -> ftrace_max_cnt );
317
325
if (ret && cxt -> pstore_zone_info )
318
326
schedule_delayed_work (& psz_cleaner , msecs_to_jiffies (1000 ));
319
327
}
@@ -550,6 +558,31 @@ static int psz_recover_zone(struct psz_context *cxt, struct pstore_zone *zone)
550
558
return ret ;
551
559
}
552
560
561
+ static int psz_recover_zones (struct psz_context * cxt ,
562
+ struct pstore_zone * * zones , unsigned int cnt )
563
+ {
564
+ int ret ;
565
+ unsigned int i ;
566
+ struct pstore_zone * zone ;
567
+
568
+ if (!zones )
569
+ return 0 ;
570
+
571
+ for (i = 0 ; i < cnt ; i ++ ) {
572
+ zone = zones [i ];
573
+ if (unlikely (!zone ))
574
+ continue ;
575
+ ret = psz_recover_zone (cxt , zone );
576
+ if (ret )
577
+ goto recover_fail ;
578
+ }
579
+
580
+ return 0 ;
581
+ recover_fail :
582
+ pr_debug ("recover %s[%u] failed\n" , zone -> name , i );
583
+ return ret ;
584
+ }
585
+
553
586
/**
554
587
* psz_recovery() - recover data from storage
555
588
* @cxt: the context of pstore/zone
@@ -574,6 +607,10 @@ static inline int psz_recovery(struct psz_context *cxt)
574
607
goto out ;
575
608
576
609
ret = psz_recover_zone (cxt , cxt -> cpsz );
610
+ if (ret )
611
+ goto out ;
612
+
613
+ ret = psz_recover_zones (cxt , cxt -> fpszs , cxt -> ftrace_max_cnt );
577
614
578
615
out :
579
616
if (unlikely (ret ))
@@ -592,6 +629,7 @@ static int psz_pstore_open(struct pstore_info *psi)
592
629
cxt -> kmsg_read_cnt = 0 ;
593
630
cxt -> pmsg_read_cnt = 0 ;
594
631
cxt -> console_read_cnt = 0 ;
632
+ cxt -> ftrace_read_cnt = 0 ;
595
633
return 0 ;
596
634
}
597
635
@@ -658,6 +696,10 @@ static int psz_pstore_erase(struct pstore_record *record)
658
696
return psz_record_erase (cxt , cxt -> ppsz );
659
697
case PSTORE_TYPE_CONSOLE :
660
698
return psz_record_erase (cxt , cxt -> cpsz );
699
+ case PSTORE_TYPE_FTRACE :
700
+ if (record -> id >= cxt -> ftrace_max_cnt )
701
+ return - EINVAL ;
702
+ return psz_record_erase (cxt , cxt -> fpszs [record -> id ]);
661
703
default : return - EINVAL ;
662
704
}
663
705
}
@@ -802,6 +844,13 @@ static int notrace psz_pstore_write(struct pstore_record *record)
802
844
return psz_record_write (cxt -> cpsz , record );
803
845
case PSTORE_TYPE_PMSG :
804
846
return psz_record_write (cxt -> ppsz , record );
847
+ case PSTORE_TYPE_FTRACE : {
848
+ int zonenum = smp_processor_id ();
849
+
850
+ if (!cxt -> fpszs )
851
+ return - ENOSPC ;
852
+ return psz_record_write (cxt -> fpszs [zonenum ], record );
853
+ }
805
854
default :
806
855
return - EINVAL ;
807
856
}
@@ -817,6 +866,14 @@ static struct pstore_zone *psz_read_next_zone(struct psz_context *cxt)
817
866
return zone ;
818
867
}
819
868
869
+ if (cxt -> ftrace_read_cnt < cxt -> ftrace_max_cnt )
870
+ /*
871
+ * No need psz_old_ok(). Let psz_ftrace_read() do so for
872
+ * combination. psz_ftrace_read() should traverse over
873
+ * all zones in case of some zone without data.
874
+ */
875
+ return cxt -> fpszs [cxt -> ftrace_read_cnt ++ ];
876
+
820
877
if (cxt -> pmsg_read_cnt == 0 ) {
821
878
cxt -> pmsg_read_cnt ++ ;
822
879
zone = cxt -> ppsz ;
@@ -891,6 +948,38 @@ static ssize_t psz_kmsg_read(struct pstore_zone *zone,
891
948
return size + hlen ;
892
949
}
893
950
951
+ /* try to combine all ftrace zones */
952
+ static ssize_t psz_ftrace_read (struct pstore_zone * zone ,
953
+ struct pstore_record * record )
954
+ {
955
+ struct psz_context * cxt ;
956
+ struct psz_buffer * buf ;
957
+ int ret ;
958
+
959
+ if (!zone || !record )
960
+ return - ENOSPC ;
961
+
962
+ if (!psz_old_ok (zone ))
963
+ goto out ;
964
+
965
+ buf = (struct psz_buffer * )zone -> oldbuf ;
966
+ if (!buf )
967
+ return - ENOMSG ;
968
+
969
+ ret = pstore_ftrace_combine_log (& record -> buf , & record -> size ,
970
+ (char * )buf -> data , atomic_read (& buf -> datalen ));
971
+ if (unlikely (ret ))
972
+ return ret ;
973
+
974
+ out :
975
+ cxt = record -> psi -> data ;
976
+ if (cxt -> ftrace_read_cnt < cxt -> ftrace_max_cnt )
977
+ /* then, read next ftrace zone */
978
+ return - ENOMSG ;
979
+ record -> id = 0 ;
980
+ return record -> size ? record -> size : - ENOMSG ;
981
+ }
982
+
894
983
static ssize_t psz_record_read (struct pstore_zone * zone ,
895
984
struct pstore_record * record )
896
985
{
@@ -941,6 +1030,9 @@ static ssize_t psz_pstore_read(struct pstore_record *record)
941
1030
readop = psz_kmsg_read ;
942
1031
record -> id = cxt -> kmsg_read_cnt - 1 ;
943
1032
break ;
1033
+ case PSTORE_TYPE_FTRACE :
1034
+ readop = psz_ftrace_read ;
1035
+ break ;
944
1036
case PSTORE_TYPE_CONSOLE :
945
1037
fallthrough ;
946
1038
case PSTORE_TYPE_PMSG :
@@ -1005,6 +1097,8 @@ static void psz_free_all_zones(struct psz_context *cxt)
1005
1097
psz_free_zone (& cxt -> ppsz );
1006
1098
if (cxt -> cpsz )
1007
1099
psz_free_zone (& cxt -> cpsz );
1100
+ if (cxt -> fpszs )
1101
+ psz_free_zones (& cxt -> fpszs , & cxt -> ftrace_max_cnt );
1008
1102
}
1009
1103
1010
1104
static struct pstore_zone * psz_init_zone (enum pstore_type_id type ,
@@ -1115,6 +1209,17 @@ static int psz_alloc_zones(struct psz_context *cxt)
1115
1209
goto free_out ;
1116
1210
}
1117
1211
1212
+ off_size += info -> ftrace_size ;
1213
+ cxt -> fpszs = psz_init_zones (PSTORE_TYPE_FTRACE , & off ,
1214
+ info -> ftrace_size ,
1215
+ info -> ftrace_size / nr_cpu_ids ,
1216
+ & cxt -> ftrace_max_cnt );
1217
+ if (IS_ERR (cxt -> fpszs )) {
1218
+ err = PTR_ERR (cxt -> fpszs );
1219
+ cxt -> fpszs = NULL ;
1220
+ goto free_out ;
1221
+ }
1222
+
1118
1223
cxt -> kpszs = psz_init_zones (PSTORE_TYPE_DMESG , & off ,
1119
1224
info -> total_size - off_size ,
1120
1225
info -> kmsg_size , & cxt -> kmsg_max_cnt );
@@ -1149,7 +1254,8 @@ int register_pstore_zone(struct pstore_zone_info *info)
1149
1254
return - EINVAL ;
1150
1255
}
1151
1256
1152
- if (!info -> kmsg_size && !info -> pmsg_size && !info -> console_size ) {
1257
+ if (!info -> kmsg_size && !info -> pmsg_size && !info -> console_size &&
1258
+ !info -> ftrace_size ) {
1153
1259
pr_warn ("at least one record size must be non-zero\n" );
1154
1260
return - EINVAL ;
1155
1261
}
@@ -1173,6 +1279,7 @@ int register_pstore_zone(struct pstore_zone_info *info)
1173
1279
check_size (kmsg_size , SECTOR_SIZE );
1174
1280
check_size (pmsg_size , SECTOR_SIZE );
1175
1281
check_size (console_size , SECTOR_SIZE );
1282
+ check_size (ftrace_size , SECTOR_SIZE );
1176
1283
1177
1284
#undef check_size
1178
1285
@@ -1200,6 +1307,7 @@ int register_pstore_zone(struct pstore_zone_info *info)
1200
1307
pr_debug ("\tkmsg size : %ld Bytes\n" , info -> kmsg_size );
1201
1308
pr_debug ("\tpmsg size : %ld Bytes\n" , info -> pmsg_size );
1202
1309
pr_debug ("\tconsole size : %ld Bytes\n" , info -> console_size );
1310
+ pr_debug ("\tftrace size : %ld Bytes\n" , info -> ftrace_size );
1203
1311
1204
1312
err = psz_alloc_zones (cxt );
1205
1313
if (err ) {
@@ -1237,6 +1345,10 @@ int register_pstore_zone(struct pstore_zone_info *info)
1237
1345
cxt -> pstore .flags |= PSTORE_FLAGS_CONSOLE ;
1238
1346
pr_cont (" console" );
1239
1347
}
1348
+ if (info -> ftrace_size ) {
1349
+ cxt -> pstore .flags |= PSTORE_FLAGS_FTRACE ;
1350
+ pr_cont (" ftrace" );
1351
+ }
1240
1352
pr_cont ("\n" );
1241
1353
1242
1354
err = pstore_register (& cxt -> pstore );
0 commit comments