pmem: refactor pmem_clear_poison()
Refactor the pmem_clear_poison() function such that the common shared code between the typical write path and the recovery write path is factored out. Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Jane Chu <jane.chu@oracle.com> Link: https://lore.kernel.org/r/20220422224508.440670-7-jane.chu@oracle.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
Родитель
047218ec90
Коммит
9409c9b670
|
@ -45,9 +45,25 @@ static struct nd_region *to_region(struct pmem_device *pmem)
|
|||
return to_nd_region(to_dev(pmem)->parent);
|
||||
}
|
||||
|
||||
static void hwpoison_clear(struct pmem_device *pmem,
|
||||
phys_addr_t phys, unsigned int len)
|
||||
static phys_addr_t to_phys(struct pmem_device *pmem, phys_addr_t offset)
|
||||
{
|
||||
return pmem->phys_addr + offset;
|
||||
}
|
||||
|
||||
static sector_t to_sect(struct pmem_device *pmem, phys_addr_t offset)
|
||||
{
|
||||
return (offset - pmem->data_offset) >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
static phys_addr_t to_offset(struct pmem_device *pmem, sector_t sector)
|
||||
{
|
||||
return (sector << SECTOR_SHIFT) + pmem->data_offset;
|
||||
}
|
||||
|
||||
static void pmem_mkpage_present(struct pmem_device *pmem, phys_addr_t offset,
|
||||
unsigned int len)
|
||||
{
|
||||
phys_addr_t phys = to_phys(pmem, offset);
|
||||
unsigned long pfn_start, pfn_end, pfn;
|
||||
|
||||
/* only pmem in the linear map supports HWPoison */
|
||||
|
@ -69,33 +85,40 @@ static void hwpoison_clear(struct pmem_device *pmem,
|
|||
}
|
||||
}
|
||||
|
||||
static void pmem_clear_bb(struct pmem_device *pmem, sector_t sector, long blks)
|
||||
{
|
||||
if (blks == 0)
|
||||
return;
|
||||
badblocks_clear(&pmem->bb, sector, blks);
|
||||
if (pmem->bb_state)
|
||||
sysfs_notify_dirent(pmem->bb_state);
|
||||
}
|
||||
|
||||
static long __pmem_clear_poison(struct pmem_device *pmem,
|
||||
phys_addr_t offset, unsigned int len)
|
||||
{
|
||||
phys_addr_t phys = to_phys(pmem, offset);
|
||||
long cleared = nvdimm_clear_poison(to_dev(pmem), phys, len);
|
||||
|
||||
if (cleared > 0) {
|
||||
pmem_mkpage_present(pmem, offset, cleared);
|
||||
arch_invalidate_pmem(pmem->virt_addr + offset, len);
|
||||
}
|
||||
return cleared;
|
||||
}
|
||||
|
||||
static blk_status_t pmem_clear_poison(struct pmem_device *pmem,
|
||||
phys_addr_t offset, unsigned int len)
|
||||
{
|
||||
struct device *dev = to_dev(pmem);
|
||||
sector_t sector;
|
||||
long cleared;
|
||||
blk_status_t rc = BLK_STS_OK;
|
||||
long cleared = __pmem_clear_poison(pmem, offset, len);
|
||||
|
||||
sector = (offset - pmem->data_offset) / 512;
|
||||
if (cleared < 0)
|
||||
return BLK_STS_IOERR;
|
||||
|
||||
cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
|
||||
pmem_clear_bb(pmem, to_sect(pmem, offset), cleared >> SECTOR_SHIFT);
|
||||
if (cleared < len)
|
||||
rc = BLK_STS_IOERR;
|
||||
if (cleared > 0 && cleared / 512) {
|
||||
hwpoison_clear(pmem, pmem->phys_addr + offset, cleared);
|
||||
cleared /= 512;
|
||||
dev_dbg(dev, "%#llx clear %ld sector%s\n",
|
||||
(unsigned long long) sector, cleared,
|
||||
cleared > 1 ? "s" : "");
|
||||
badblocks_clear(&pmem->bb, sector, cleared);
|
||||
if (pmem->bb_state)
|
||||
sysfs_notify_dirent(pmem->bb_state);
|
||||
}
|
||||
|
||||
arch_invalidate_pmem(pmem->virt_addr + offset, len);
|
||||
|
||||
return rc;
|
||||
return BLK_STS_IOERR;
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
static void write_pmem(void *pmem_addr, struct page *page,
|
||||
|
@ -143,7 +166,7 @@ static blk_status_t pmem_do_read(struct pmem_device *pmem,
|
|||
sector_t sector, unsigned int len)
|
||||
{
|
||||
blk_status_t rc;
|
||||
phys_addr_t pmem_off = sector * 512 + pmem->data_offset;
|
||||
phys_addr_t pmem_off = to_offset(pmem, sector);
|
||||
void *pmem_addr = pmem->virt_addr + pmem_off;
|
||||
|
||||
if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
|
||||
|
@ -158,7 +181,7 @@ static blk_status_t pmem_do_write(struct pmem_device *pmem,
|
|||
struct page *page, unsigned int page_off,
|
||||
sector_t sector, unsigned int len)
|
||||
{
|
||||
phys_addr_t pmem_off = sector * 512 + pmem->data_offset;
|
||||
phys_addr_t pmem_off = to_offset(pmem, sector);
|
||||
void *pmem_addr = pmem->virt_addr + pmem_off;
|
||||
|
||||
if (unlikely(is_bad_pmem(&pmem->bb, sector, len))) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче