@@ -831,12 +831,14 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e,
831831 return ret ;
832832}
833833
834- static int ppl_recover (struct ppl_log * log , struct ppl_header * pplhdr )
834+ static int ppl_recover (struct ppl_log * log , struct ppl_header * pplhdr ,
835+ sector_t offset )
835836{
836837 struct ppl_conf * ppl_conf = log -> ppl_conf ;
837838 struct md_rdev * rdev = log -> rdev ;
838839 struct mddev * mddev = rdev -> mddev ;
839- sector_t ppl_sector = rdev -> ppl .sector + (PPL_HEADER_SIZE >> 9 );
840+ sector_t ppl_sector = rdev -> ppl .sector + offset +
841+ (PPL_HEADER_SIZE >> 9 );
840842 struct page * page ;
841843 int i ;
842844 int ret = 0 ;
@@ -920,6 +922,9 @@ static int ppl_write_empty_header(struct ppl_log *log)
920922 return - ENOMEM ;
921923
922924 pplhdr = page_address (page );
925+ /* zero out PPL space to avoid collision with old PPLs */
926+ blkdev_issue_zeroout (rdev -> bdev , rdev -> ppl .sector ,
927+ log -> rdev -> ppl .size , GFP_NOIO , 0 );
923928 memset (pplhdr -> reserved , 0xff , PPL_HDR_RESERVED );
924929 pplhdr -> signature = cpu_to_le32 (log -> ppl_conf -> signature );
925930 pplhdr -> checksum = cpu_to_le32 (~crc32c_le (~0 , pplhdr , PAGE_SIZE ));
@@ -940,63 +945,110 @@ static int ppl_load_distributed(struct ppl_log *log)
940945 struct ppl_conf * ppl_conf = log -> ppl_conf ;
941946 struct md_rdev * rdev = log -> rdev ;
942947 struct mddev * mddev = rdev -> mddev ;
943- struct page * page ;
944- struct ppl_header * pplhdr ;
948+ struct page * page , * page2 , * tmp ;
949+ struct ppl_header * pplhdr = NULL , * prev_pplhdr = NULL ;
945950 u32 crc , crc_stored ;
946951 u32 signature ;
947- int ret = 0 ;
952+ int ret = 0 , i ;
953+ sector_t pplhdr_offset = 0 , prev_pplhdr_offset = 0 ;
948954
949955 pr_debug ("%s: disk: %d\n" , __func__ , rdev -> raid_disk );
950-
951- /* read PPL header */
956+ /* read PPL headers, find the recent one */
952957 page = alloc_page (GFP_KERNEL );
953958 if (!page )
954959 return - ENOMEM ;
955960
956- if (!sync_page_io (rdev , rdev -> ppl .sector - rdev -> data_offset ,
957- PAGE_SIZE , page , REQ_OP_READ , 0 , false)) {
958- md_error (mddev , rdev );
959- ret = - EIO ;
960- goto out ;
961+ page2 = alloc_page (GFP_KERNEL );
962+ if (!page2 ) {
963+ __free_page (page );
964+ return - ENOMEM ;
961965 }
962- pplhdr = page_address (page );
963966
964- /* check header validity */
965- crc_stored = le32_to_cpu (pplhdr -> checksum );
966- pplhdr -> checksum = 0 ;
967- crc = ~crc32c_le (~0 , pplhdr , PAGE_SIZE );
967+ /* searching ppl area for latest ppl */
968+ while (pplhdr_offset < rdev -> ppl .size - (PPL_HEADER_SIZE >> 9 )) {
969+ if (!sync_page_io (rdev ,
970+ rdev -> ppl .sector - rdev -> data_offset +
971+ pplhdr_offset , PAGE_SIZE , page , REQ_OP_READ ,
972+ 0 , false)) {
973+ md_error (mddev , rdev );
974+ ret = - EIO ;
975+ /* if not able to read - don't recover any PPL */
976+ pplhdr = NULL ;
977+ break ;
978+ }
979+ pplhdr = page_address (page );
980+
981+ /* check header validity */
982+ crc_stored = le32_to_cpu (pplhdr -> checksum );
983+ pplhdr -> checksum = 0 ;
984+ crc = ~crc32c_le (~0 , pplhdr , PAGE_SIZE );
985+
986+ if (crc_stored != crc ) {
987+ pr_debug ("%s: ppl header crc does not match: stored: 0x%x calculated: 0x%x (offset: %llu)\n" ,
988+ __func__ , crc_stored , crc ,
989+ (unsigned long long )pplhdr_offset );
990+ pplhdr = prev_pplhdr ;
991+ pplhdr_offset = prev_pplhdr_offset ;
992+ break ;
993+ }
968994
969- if (crc_stored != crc ) {
970- pr_debug ("%s: ppl header crc does not match: stored: 0x%x calculated: 0x%x\n" ,
971- __func__ , crc_stored , crc );
972- ppl_conf -> mismatch_count ++ ;
973- goto out ;
974- }
995+ signature = le32_to_cpu (pplhdr -> signature );
975996
976- signature = le32_to_cpu (pplhdr -> signature );
997+ if (mddev -> external ) {
998+ /*
999+ * For external metadata the header signature is set and
1000+ * validated in userspace.
1001+ */
1002+ ppl_conf -> signature = signature ;
1003+ } else if (ppl_conf -> signature != signature ) {
1004+ pr_debug ("%s: ppl header signature does not match: stored: 0x%x configured: 0x%x (offset: %llu)\n" ,
1005+ __func__ , signature , ppl_conf -> signature ,
1006+ (unsigned long long )pplhdr_offset );
1007+ pplhdr = prev_pplhdr ;
1008+ pplhdr_offset = prev_pplhdr_offset ;
1009+ break ;
1010+ }
9771011
978- if (mddev -> external ) {
979- /*
980- * For external metadata the header signature is set and
981- * validated in userspace.
982- */
983- ppl_conf -> signature = signature ;
984- } else if (ppl_conf -> signature != signature ) {
985- pr_debug ("%s: ppl header signature does not match: stored: 0x%x configured: 0x%x\n" ,
986- __func__ , signature , ppl_conf -> signature );
987- ppl_conf -> mismatch_count ++ ;
988- goto out ;
1012+ if (prev_pplhdr && le64_to_cpu (prev_pplhdr -> generation ) >
1013+ le64_to_cpu (pplhdr -> generation )) {
1014+ /* previous was newest */
1015+ pplhdr = prev_pplhdr ;
1016+ pplhdr_offset = prev_pplhdr_offset ;
1017+ break ;
1018+ }
1019+
1020+ prev_pplhdr_offset = pplhdr_offset ;
1021+ prev_pplhdr = pplhdr ;
1022+
1023+ tmp = page ;
1024+ page = page2 ;
1025+ page2 = tmp ;
1026+
1027+ /* calculate next potential ppl offset */
1028+ for (i = 0 ; i < le32_to_cpu (pplhdr -> entries_count ); i ++ )
1029+ pplhdr_offset +=
1030+ le32_to_cpu (pplhdr -> entries [i ].pp_size ) >> 9 ;
1031+ pplhdr_offset += PPL_HEADER_SIZE >> 9 ;
9891032 }
9901033
1034+ /* no valid ppl found */
1035+ if (!pplhdr )
1036+ ppl_conf -> mismatch_count ++ ;
1037+ else
1038+ pr_debug ("%s: latest PPL found at offset: %llu, with generation: %llu\n" ,
1039+ __func__ , (unsigned long long )pplhdr_offset ,
1040+ le64_to_cpu (pplhdr -> generation ));
1041+
9911042 /* attempt to recover from log if we are starting a dirty array */
992- if (!mddev -> pers && mddev -> recovery_cp != MaxSector )
993- ret = ppl_recover (log , pplhdr );
994- out :
1043+ if (pplhdr && !mddev -> pers && mddev -> recovery_cp != MaxSector )
1044+ ret = ppl_recover (log , pplhdr , pplhdr_offset );
1045+
9951046 /* write empty header if we are starting the array */
9961047 if (!ret && !mddev -> pers )
9971048 ret = ppl_write_empty_header (log );
9981049
9991050 __free_page (page );
1051+ __free_page (page2 );
10001052
10011053 pr_debug ("%s: return: %d mismatch_count: %d recovered_entries: %d\n" ,
10021054 __func__ , ret , ppl_conf -> mismatch_count ,
0 commit comments