staticstruct device *to_dev(struct pmem_device *pmem)
{ /* * nvdimm bus services need a 'dev' parameter, and we record the device * at init in bb.dev.
*/ return pmem->bb.dev;
}
/* * Note, no need to hold a get_dev_pagemap() reference * here since we're in the driver I/O path and * outstanding I/O requests pin the dev_pagemap.
*/ if (test_and_clear_pmem_poison(page))
clear_mce_nospec(pfn);
}
}
staticvoid 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);
}
if (kaddr)
*kaddr = pmem->virt_addr + offset; if (pfn)
*pfn = PHYS_PFN(pmem->phys_addr + offset);
if (bb->count &&
badblocks_check(bb, sector, num, &first_bad, &num_bad)) { long actual_nr;
if (mode != DAX_RECOVERY_WRITE) return -EHWPOISON;
/* * Set the recovery stride is set to kernel page size because * the underlying driver and firmware clear poison functions * don't appear to handle large chunk(such as 2MiB) reliably.
*/
actual_nr = PHYS_PFN(
PAGE_ALIGN((first_bad - sector) << SECTOR_SHIFT));
dev_dbg(pmem->bb.dev, "start sector(%llu), nr_pages(%ld), first_bad(%llu), actual_nr(%ld)\n",
sector, nr_pages, first_bad, actual_nr); if (actual_nr) return actual_nr; return 1;
}
/* * If badblocks are present but not in the range, limit known good range * to the requested range.
*/ if (bb->count) return nr_pages; return PHYS_PFN(pmem->size - pmem->pfn_pad - offset);
}
/* * The recovery write thread started out as a normal pwrite thread and * when the filesystem was told about potential media error in the * range, filesystem turns the normal pwrite to a dax_recovery_write. * * The recovery write consists of clearing media poison, clearing page * HWPoison bit, re-enable page-wide read-write permission, flush the * caches and finally write. A competing pread thread will be held * off during the recovery process since data read back might not be * valid, and this is achieved by clearing the badblock records after * the recovery write is complete. Competing recovery write threads * are already serialized by writer lock held by dax_iomap_rw().
*/ static size_t pmem_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
{ struct pmem_device *pmem = dax_get_private(dax_dev);
size_t olen, len, off;
phys_addr_t pmem_off; struct device *dev = pmem->bb.dev; long cleared;
off = offset_in_page(addr);
len = PFN_PHYS(PFN_UP(off + bytes)); if (!is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) >> SECTOR_SHIFT, len)) return _copy_from_iter_flushcache(addr, bytes, i);
/* * Not page-aligned range cannot be recovered. This should not * happen unless something else went wrong.
*/ if (off || !PAGE_ALIGNED(bytes)) {
dev_dbg(dev, "Found poison, but addr(%p) or bytes(%#zx) not page aligned\n",
addr, bytes); return 0;
}
pmem_off = PFN_PHYS(pgoff) + pmem->data_offset;
cleared = __pmem_clear_poison(pmem, pmem_off, len); if (cleared > 0 && cleared < len) {
dev_dbg(dev, "poison cleared only %ld out of %zu bytes\n",
cleared, len); return 0;
} if (cleared < 0) {
dev_dbg(dev, "poison clear failed: %ld\n", cleared); return 0;
}
pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL); if (!pmem) return -ENOMEM;
rc = devm_namespace_enable(dev, ndns, nd_info_block_reserve()); if (rc) return rc;
/* while nsio_rw_bytes is active, parse a pfn info block if present */ if (is_nd_pfn(dev)) {
nd_pfn = to_nd_pfn(dev);
rc = nvdimm_setup_pfn(nd_pfn, &pmem->pgmap); if (rc) return rc;
}
/* we're attaching a block device, disable raw namespace access */
devm_namespace_disable(dev, ndns);
dev_set_drvdata(dev, pmem);
pmem->phys_addr = res->start;
pmem->size = resource_size(res);
fua = nvdimm_has_flush(nd_region); if (!IS_ENABLED(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) || fua < 0) {
dev_warn(dev, "unable to guarantee persistence of writes\n");
fua = 0;
} if (fua)
lim.features |= BLK_FEAT_FUA; if (is_nd_pfn(dev) || pmem_should_map_pages(dev))
lim.features |= BLK_FEAT_DAX;
if (!devm_request_mem_region(dev, res->start, resource_size(res),
dev_name(&ndns->dev))) {
dev_warn(dev, "could not reserve region %pR\n", res); return -EBUSY;
}
disk = blk_alloc_disk(&lim, nid); if (IS_ERR(disk)) return PTR_ERR(disk);
staticint nd_pmem_probe(struct device *dev)
{ int ret; struct nd_namespace_common *ndns;
ndns = nvdimm_namespace_common_probe(dev); if (IS_ERR(ndns)) return PTR_ERR(ndns);
if (is_nd_btt(dev)) return nvdimm_namespace_attach_btt(ndns);
if (is_nd_pfn(dev)) return pmem_attach_disk(dev, ndns);
ret = devm_namespace_enable(dev, ndns, nd_info_block_reserve()); if (ret) return ret;
ret = nd_btt_probe(dev, ndns); if (ret == 0) return -ENXIO;
/* * We have two failure conditions here, there is no * info reserver block or we found a valid info reserve block * but failed to initialize the pfn superblock. * * For the first case consider namespace as a raw pmem namespace * and attach a disk. * * For the latter, consider this a success and advance the namespace * seed.
*/
ret = nd_pfn_probe(dev, ndns); if (ret == 0) return -ENXIO; elseif (ret == -EOPNOTSUPP) return ret;
ret = nd_dax_probe(dev, ndns); if (ret == 0) return -ENXIO; elseif (ret == -EOPNOTSUPP) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.