aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPawel Baldysiak <pawel.baldysiak@intel.com>2017-08-16 11:13:46 -0400
committerShaohua Li <shli@fb.com>2017-08-28 10:45:49 -0400
commit675dc2ccc27c02449da45e1a03234104c2449f68 (patch)
tree3f19c52ed617cde589407cd27a10f2eb2396be26
parentddc088238cd6988bb4ac3776f403d7ff9d3c7a63 (diff)
raid5-ppl: Recovery support for multiple partial parity logs
Search PPL buffer in order to find out the latest PPL header (the one with largest generation number) and use it for recovery. The PPL entry format and recovery algorithm are the same as for single PPL approach. Signed-off-by: Pawel Baldysiak <pawel.baldysiak@intel.com> Signed-off-by: Shaohua Li <shli@fb.com>
-rw-r--r--drivers/md/raid5-ppl.c128
1 files changed, 90 insertions, 38 deletions
diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c
index b313f17a6260..a98ef172f8e8 100644
--- a/drivers/md/raid5-ppl.c
+++ b/drivers/md/raid5-ppl.c
@@ -831,12 +831,14 @@ out:
831 return ret; 831 return ret;
832} 832}
833 833
834static int ppl_recover(struct ppl_log *log, struct ppl_header *pplhdr) 834static int ppl_recover(struct ppl_log *log, struct ppl_header *pplhdr,
835 sector_t offset)
835{ 836{
836 struct ppl_conf *ppl_conf = log->ppl_conf; 837 struct ppl_conf *ppl_conf = log->ppl_conf;
837 struct md_rdev *rdev = log->rdev; 838 struct md_rdev *rdev = log->rdev;
838 struct mddev *mddev = rdev->mddev; 839 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);
840 struct page *page; 842 struct page *page;
841 int i; 843 int i;
842 int ret = 0; 844 int ret = 0;
@@ -920,6 +922,9 @@ static int ppl_write_empty_header(struct ppl_log *log)
920 return -ENOMEM; 922 return -ENOMEM;
921 923
922 pplhdr = page_address(page); 924 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);
923 memset(pplhdr->reserved, 0xff, PPL_HDR_RESERVED); 928 memset(pplhdr->reserved, 0xff, PPL_HDR_RESERVED);
924 pplhdr->signature = cpu_to_le32(log->ppl_conf->signature); 929 pplhdr->signature = cpu_to_le32(log->ppl_conf->signature);
925 pplhdr->checksum = cpu_to_le32(~crc32c_le(~0, pplhdr, PAGE_SIZE)); 930 pplhdr->checksum = cpu_to_le32(~crc32c_le(~0, pplhdr, PAGE_SIZE));
@@ -940,63 +945,110 @@ static int ppl_load_distributed(struct ppl_log *log)
940 struct ppl_conf *ppl_conf = log->ppl_conf; 945 struct ppl_conf *ppl_conf = log->ppl_conf;
941 struct md_rdev *rdev = log->rdev; 946 struct md_rdev *rdev = log->rdev;
942 struct mddev *mddev = rdev->mddev; 947 struct mddev *mddev = rdev->mddev;
943 struct page *page; 948 struct page *page, *page2, *tmp;
944 struct ppl_header *pplhdr; 949 struct ppl_header *pplhdr = NULL, *prev_pplhdr = NULL;
945 u32 crc, crc_stored; 950 u32 crc, crc_stored;
946 u32 signature; 951 u32 signature;
947 int ret = 0; 952 int ret = 0, i;
953 sector_t pplhdr_offset = 0, prev_pplhdr_offset = 0;
948 954
949 pr_debug("%s: disk: %d\n", __func__, rdev->raid_disk); 955 pr_debug("%s: disk: %d\n", __func__, rdev->raid_disk);
950 956 /* read PPL headers, find the recent one */
951 /* read PPL header */
952 page = alloc_page(GFP_KERNEL); 957 page = alloc_page(GFP_KERNEL);
953 if (!page) 958 if (!page)
954 return -ENOMEM; 959 return -ENOMEM;
955 960
956 if (!sync_page_io(rdev, rdev->ppl.sector - rdev->data_offset, 961 page2 = alloc_page(GFP_KERNEL);
957 PAGE_SIZE, page, REQ_OP_READ, 0, false)) { 962 if (!page2) {
958 md_error(mddev, rdev); 963 __free_page(page);
959 ret = -EIO; 964 return -ENOMEM;
960 goto out;
961 } 965 }
962 pplhdr = page_address(page);
963 966
964 /* check header validity */ 967 /* searching ppl area for latest ppl */
965 crc_stored = le32_to_cpu(pplhdr->checksum); 968 while (pplhdr_offset < rdev->ppl.size - (PPL_HEADER_SIZE >> 9)) {
966 pplhdr->checksum = 0; 969 if (!sync_page_io(rdev,
967 crc = ~crc32c_le(~0, pplhdr, PAGE_SIZE); 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 }
968 994
969 if (crc_stored != crc) { 995 signature = le32_to_cpu(pplhdr->signature);
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 }
975 996
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 }
977 1011
978 if (mddev->external) { 1012 if (prev_pplhdr && le64_to_cpu(prev_pplhdr->generation) >
979 /* 1013 le64_to_cpu(pplhdr->generation)) {
980 * For external metadata the header signature is set and 1014 /* previous was newest */
981 * validated in userspace. 1015 pplhdr = prev_pplhdr;
982 */ 1016 pplhdr_offset = prev_pplhdr_offset;
983 ppl_conf->signature = signature; 1017 break;
984 } else if (ppl_conf->signature != signature) { 1018 }
985 pr_debug("%s: ppl header signature does not match: stored: 0x%x configured: 0x%x\n", 1019
986 __func__, signature, ppl_conf->signature); 1020 prev_pplhdr_offset = pplhdr_offset;
987 ppl_conf->mismatch_count++; 1021 prev_pplhdr = pplhdr;
988 goto out; 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;
989 } 1032 }
990 1033
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
991 /* attempt to recover from log if we are starting a dirty array */ 1042 /* attempt to recover from log if we are starting a dirty array */
992 if (!mddev->pers && mddev->recovery_cp != MaxSector) 1043 if (pplhdr && !mddev->pers && mddev->recovery_cp != MaxSector)
993 ret = ppl_recover(log, pplhdr); 1044 ret = ppl_recover(log, pplhdr, pplhdr_offset);
994out: 1045
995 /* write empty header if we are starting the array */ 1046 /* write empty header if we are starting the array */
996 if (!ret && !mddev->pers) 1047 if (!ret && !mddev->pers)
997 ret = ppl_write_empty_header(log); 1048 ret = ppl_write_empty_header(log);
998 1049
999 __free_page(page); 1050 __free_page(page);
1051 __free_page(page2);
1000 1052
1001 pr_debug("%s: return: %d mismatch_count: %d recovered_entries: %d\n", 1053 pr_debug("%s: return: %d mismatch_count: %d recovered_entries: %d\n",
1002 __func__, ret, ppl_conf->mismatch_count, 1054 __func__, ret, ppl_conf->mismatch_count,