提交 675dc2cc 编写于 作者: P Pawel Baldysiak 提交者: Shaohua Li

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: NPawel Baldysiak <pawel.baldysiak@intel.com>
Signed-off-by: NShaohua Li <shli@fb.com>
上级 ddc08823
...@@ -831,12 +831,14 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e, ...@@ -831,12 +831,14 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e,
return ret; return ret;
} }
static int ppl_recover(struct ppl_log *log, struct ppl_header *pplhdr) static int ppl_recover(struct ppl_log *log, struct ppl_header *pplhdr,
sector_t offset)
{ {
struct ppl_conf *ppl_conf = log->ppl_conf; struct ppl_conf *ppl_conf = log->ppl_conf;
struct md_rdev *rdev = log->rdev; struct md_rdev *rdev = log->rdev;
struct mddev *mddev = rdev->mddev; struct mddev *mddev = rdev->mddev;
sector_t ppl_sector = rdev->ppl.sector + (PPL_HEADER_SIZE >> 9); sector_t ppl_sector = rdev->ppl.sector + offset +
(PPL_HEADER_SIZE >> 9);
struct page *page; struct page *page;
int i; int i;
int ret = 0; int ret = 0;
...@@ -920,6 +922,9 @@ static int ppl_write_empty_header(struct ppl_log *log) ...@@ -920,6 +922,9 @@ static int ppl_write_empty_header(struct ppl_log *log)
return -ENOMEM; return -ENOMEM;
pplhdr = page_address(page); pplhdr = page_address(page);
/* zero out PPL space to avoid collision with old PPLs */
blkdev_issue_zeroout(rdev->bdev, rdev->ppl.sector,
log->rdev->ppl.size, GFP_NOIO, 0);
memset(pplhdr->reserved, 0xff, PPL_HDR_RESERVED); memset(pplhdr->reserved, 0xff, PPL_HDR_RESERVED);
pplhdr->signature = cpu_to_le32(log->ppl_conf->signature); pplhdr->signature = cpu_to_le32(log->ppl_conf->signature);
pplhdr->checksum = cpu_to_le32(~crc32c_le(~0, pplhdr, PAGE_SIZE)); pplhdr->checksum = cpu_to_le32(~crc32c_le(~0, pplhdr, PAGE_SIZE));
...@@ -940,24 +945,36 @@ static int ppl_load_distributed(struct ppl_log *log) ...@@ -940,24 +945,36 @@ static int ppl_load_distributed(struct ppl_log *log)
struct ppl_conf *ppl_conf = log->ppl_conf; struct ppl_conf *ppl_conf = log->ppl_conf;
struct md_rdev *rdev = log->rdev; struct md_rdev *rdev = log->rdev;
struct mddev *mddev = rdev->mddev; struct mddev *mddev = rdev->mddev;
struct page *page; struct page *page, *page2, *tmp;
struct ppl_header *pplhdr; struct ppl_header *pplhdr = NULL, *prev_pplhdr = NULL;
u32 crc, crc_stored; u32 crc, crc_stored;
u32 signature; u32 signature;
int ret = 0; int ret = 0, i;
sector_t pplhdr_offset = 0, prev_pplhdr_offset = 0;
pr_debug("%s: disk: %d\n", __func__, rdev->raid_disk); pr_debug("%s: disk: %d\n", __func__, rdev->raid_disk);
/* read PPL headers, find the recent one */
/* read PPL header */
page = alloc_page(GFP_KERNEL); page = alloc_page(GFP_KERNEL);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
if (!sync_page_io(rdev, rdev->ppl.sector - rdev->data_offset, page2 = alloc_page(GFP_KERNEL);
PAGE_SIZE, page, REQ_OP_READ, 0, false)) { if (!page2) {
__free_page(page);
return -ENOMEM;
}
/* searching ppl area for latest ppl */
while (pplhdr_offset < rdev->ppl.size - (PPL_HEADER_SIZE >> 9)) {
if (!sync_page_io(rdev,
rdev->ppl.sector - rdev->data_offset +
pplhdr_offset, PAGE_SIZE, page, REQ_OP_READ,
0, false)) {
md_error(mddev, rdev); md_error(mddev, rdev);
ret = -EIO; ret = -EIO;
goto out; /* if not able to read - don't recover any PPL */
pplhdr = NULL;
break;
} }
pplhdr = page_address(page); pplhdr = page_address(page);
...@@ -967,10 +984,12 @@ static int ppl_load_distributed(struct ppl_log *log) ...@@ -967,10 +984,12 @@ static int ppl_load_distributed(struct ppl_log *log)
crc = ~crc32c_le(~0, pplhdr, PAGE_SIZE); crc = ~crc32c_le(~0, pplhdr, PAGE_SIZE);
if (crc_stored != crc) { if (crc_stored != crc) {
pr_debug("%s: ppl header crc does not match: stored: 0x%x calculated: 0x%x\n", pr_debug("%s: ppl header crc does not match: stored: 0x%x calculated: 0x%x (offset: %llu)\n",
__func__, crc_stored, crc); __func__, crc_stored, crc,
ppl_conf->mismatch_count++; (unsigned long long)pplhdr_offset);
goto out; pplhdr = prev_pplhdr;
pplhdr_offset = prev_pplhdr_offset;
break;
} }
signature = le32_to_cpu(pplhdr->signature); signature = le32_to_cpu(pplhdr->signature);
...@@ -982,21 +1001,54 @@ static int ppl_load_distributed(struct ppl_log *log) ...@@ -982,21 +1001,54 @@ static int ppl_load_distributed(struct ppl_log *log)
*/ */
ppl_conf->signature = signature; ppl_conf->signature = signature;
} else if (ppl_conf->signature != signature) { } else if (ppl_conf->signature != signature) {
pr_debug("%s: ppl header signature does not match: stored: 0x%x configured: 0x%x\n", pr_debug("%s: ppl header signature does not match: stored: 0x%x configured: 0x%x (offset: %llu)\n",
__func__, signature, ppl_conf->signature); __func__, signature, ppl_conf->signature,
ppl_conf->mismatch_count++; (unsigned long long)pplhdr_offset);
goto out; pplhdr = prev_pplhdr;
pplhdr_offset = prev_pplhdr_offset;
break;
}
if (prev_pplhdr && le64_to_cpu(prev_pplhdr->generation) >
le64_to_cpu(pplhdr->generation)) {
/* previous was newest */
pplhdr = prev_pplhdr;
pplhdr_offset = prev_pplhdr_offset;
break;
}
prev_pplhdr_offset = pplhdr_offset;
prev_pplhdr = pplhdr;
tmp = page;
page = page2;
page2 = tmp;
/* calculate next potential ppl offset */
for (i = 0; i < le32_to_cpu(pplhdr->entries_count); i++)
pplhdr_offset +=
le32_to_cpu(pplhdr->entries[i].pp_size) >> 9;
pplhdr_offset += PPL_HEADER_SIZE >> 9;
} }
/* no valid ppl found */
if (!pplhdr)
ppl_conf->mismatch_count++;
else
pr_debug("%s: latest PPL found at offset: %llu, with generation: %llu\n",
__func__, (unsigned long long)pplhdr_offset,
le64_to_cpu(pplhdr->generation));
/* attempt to recover from log if we are starting a dirty array */ /* attempt to recover from log if we are starting a dirty array */
if (!mddev->pers && mddev->recovery_cp != MaxSector) if (pplhdr && !mddev->pers && mddev->recovery_cp != MaxSector)
ret = ppl_recover(log, pplhdr); ret = ppl_recover(log, pplhdr, pplhdr_offset);
out:
/* write empty header if we are starting the array */ /* write empty header if we are starting the array */
if (!ret && !mddev->pers) if (!ret && !mddev->pers)
ret = ppl_write_empty_header(log); ret = ppl_write_empty_header(log);
__free_page(page); __free_page(page);
__free_page(page2);
pr_debug("%s: return: %d mismatch_count: %d recovered_entries: %d\n", pr_debug("%s: return: %d mismatch_count: %d recovered_entries: %d\n",
__func__, ret, ppl_conf->mismatch_count, __func__, ret, ppl_conf->mismatch_count,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册