static int is_uuid_busy(struct device *dev, void *data) { u8 *uuid1 = data, *uuid2 = NULL; if (is_namespace_pmem(dev)) { struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); uuid2 = nspm->uuid; } else if (is_namespace_blk(dev)) { struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev); uuid2 = nsblk->uuid; } else if (is_nd_btt(dev)) { struct nd_btt *nd_btt = to_nd_btt(dev); uuid2 = nd_btt->uuid; } else if (is_nd_pfn(dev)) { struct nd_pfn *nd_pfn = to_nd_pfn(dev); uuid2 = nd_pfn->uuid; } if (uuid2 && memcmp(uuid1, uuid2, NSLABEL_UUID_LEN) == 0) return -EBUSY; return 0; }
struct nd_pfn *to_nd_pfn(struct device *dev) { struct nd_pfn *nd_pfn = container_of(dev, struct nd_pfn, dev); WARN_ON(!is_nd_pfn(dev)); return nd_pfn; }
const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns, char *name) { struct nd_region *nd_region = to_nd_region(ndns->dev.parent); const char *suffix = NULL; if (ndns->claim) { if (is_nd_btt(ndns->claim)) suffix = "s"; else if (is_nd_pfn(ndns->claim)) suffix = "m"; else dev_WARN_ONCE(&ndns->dev, 1, "unknown claim type by %s\n", dev_name(ndns->claim)); } if (is_namespace_pmem(&ndns->dev) || is_namespace_io(&ndns->dev)) { if (!suffix && pmem_should_map_pages(&ndns->dev)) suffix = "m"; sprintf(name, "pmem%d%s", nd_region->id, suffix ? suffix : ""); } else if (is_namespace_blk(&ndns->dev)) { struct nd_namespace_blk *nsblk; nsblk = to_nd_namespace_blk(&ndns->dev); sprintf(name, "ndblk%d.%d%s", nd_region->id, nsblk->id, suffix ? suffix : ""); } else { return NULL; } return name; }
static int nd_pmem_remove(struct device *dev) { struct pmem_device *pmem = dev_get_drvdata(dev); if (is_nd_btt(dev)) nvdimm_namespace_detach_btt(pmem->ndns); else if (is_nd_pfn(dev)) nvdimm_namespace_detach_pfn(pmem->ndns); else pmem_detach_disk(pmem); return 0; }
static bool is_idle(struct device *dev, struct nd_namespace_common *ndns) { struct nd_region *nd_region = to_nd_region(dev->parent); struct device *seed = NULL; if (is_nd_btt(dev)) seed = nd_region->btt_seed; else if (is_nd_pfn(dev)) seed = nd_region->pfn_seed; else if (is_nd_dax(dev)) seed = nd_region->dax_seed; if (seed == dev || ndns || dev->driver) return false; return true; }
struct nd_pfn *to_nd_pfn_safe(struct device *dev) { /* * pfn device attributes are re-used by dax device instances, so we * need to be careful to correct device-to-nd_pfn conversion. */ if (is_nd_pfn(dev)) return to_nd_pfn(dev); if (is_nd_dax(dev)) { struct nd_dax *nd_dax = to_nd_dax(dev); return &nd_dax->nd_pfn; } WARN_ON(1); return NULL; }
bool pmem_should_map_pages(struct device *dev) { struct nd_region *nd_region = to_nd_region(dev->parent); if (!IS_ENABLED(CONFIG_ZONE_DEVICE)) return false; if (!test_bit(ND_REGION_PAGEMAP, &nd_region->flags)) return false; if (is_nd_pfn(dev) || is_nd_btt(dev)) return false; #ifdef ARCH_MEMREMAP_PMEM return ARCH_MEMREMAP_PMEM == MEMREMAP_WB; #else return false; #endif }
static void nd_detach_and_reset(struct device *dev, struct nd_namespace_common **_ndns) { /* detach the namespace and destroy / reset the device */ nd_detach_ndns(dev, _ndns); if (is_idle(dev, *_ndns)) { nd_device_unregister(dev, ND_ASYNC); } else if (is_nd_btt(dev)) { struct nd_btt *nd_btt = to_nd_btt(dev); nd_btt->lbasize = 0; kfree(nd_btt->uuid); nd_btt->uuid = NULL; } else if (is_nd_pfn(dev) || is_nd_dax(dev)) { struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); kfree(nd_pfn->uuid); nd_pfn->uuid = NULL; nd_pfn->mode = PFN_MODE_NONE; } }
static int nd_pmem_probe(struct device *dev) { struct nd_region *nd_region = to_nd_region(dev->parent); struct nd_namespace_common *ndns; struct nd_namespace_io *nsio; struct pmem_device *pmem; ndns = nvdimm_namespace_common_probe(dev); if (IS_ERR(ndns)) return PTR_ERR(ndns); nsio = to_nd_namespace_io(&ndns->dev); pmem = pmem_alloc(dev, &nsio->res, nd_region->id); if (IS_ERR(pmem)) return PTR_ERR(pmem); pmem->ndns = ndns; dev_set_drvdata(dev, pmem); ndns->rw_bytes = pmem_rw_bytes; if (is_nd_btt(dev)) return nvdimm_namespace_attach_btt(ndns); if (is_nd_pfn(dev)) return nvdimm_namespace_attach_pfn(ndns); if (nd_btt_probe(ndns, pmem) == 0) { /* we'll come back as btt-pmem */ return -ENXIO; } if (nd_pfn_probe(ndns, pmem) == 0) { /* we'll come back as pfn-pmem */ return -ENXIO; } return pmem_attach_disk(dev, ndns, pmem); }