Skip to content

Commit 675dc2c

Browse files
pbaldysishligit
authored andcommitted
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 <[email protected]> Signed-off-by: Shaohua Li <[email protected]>
1 parent ddc0882 commit 675dc2c

File tree

1 file changed

+90
-38
lines changed

1 file changed

+90
-38
lines changed

drivers/md/raid5-ppl.c

Lines changed: 90 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)