resource_size_t nd_region_available_dpa(struct nd_region *nd_region) { resource_size_t blk_max_overlap = 0, available, overlap; int i; WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev)); retry: available = 0; overlap = blk_max_overlap; for (i = 0; i < nd_region->ndr_mappings; i++) { struct nd_mapping *nd_mapping = &nd_region->mapping[i]; struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); /* if a dimm is disabled the available capacity is zero */ if (!ndd) return 0; if (is_nd_pmem(&nd_region->dev)) { available += nd_pmem_available_dpa(nd_region, nd_mapping, &overlap); if (overlap > blk_max_overlap) { blk_max_overlap = overlap; goto retry; } } else if (is_nd_blk(&nd_region->dev)) { available += nd_blk_available_dpa(nd_mapping); } } return available; }
struct nvdimm_drvdata *to_ndd(struct nd_mapping *nd_mapping) { struct nvdimm *nvdimm = nd_mapping->nvdimm; WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm->dev)); return dev_get_drvdata(&nvdimm->dev); }
/** * nd_is_uuid_unique - verify that no other namespace has @uuid * @dev: any device on a nvdimm_bus * @uuid: uuid to check */ bool nd_is_uuid_unique(struct device *dev, u8 *uuid) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); if (!nvdimm_bus) return false; WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm_bus->dev)); if (device_for_each_child(&nvdimm_bus->dev, uuid, is_namespace_uuid_busy) != 0) return false; return true; }
struct resource *nvdimm_allocate_dpa(struct nvdimm_drvdata *ndd, struct nd_label_id *label_id, resource_size_t start, resource_size_t n) { char *name = kmemdup(label_id, sizeof(*label_id), GFP_KERNEL); struct resource *res; if (!name) return NULL; WARN_ON_ONCE(!is_nvdimm_bus_locked(ndd->dev)); res = __request_region(&ndd->dpa, start, n, name, 0); if (!res) kfree(name); return res; }
void nvdimm_free_dpa(struct nvdimm_drvdata *ndd, struct resource *res) { WARN_ON_ONCE(!is_nvdimm_bus_locked(ndd->dev)); kfree(res->name); __release_region(&ndd->dpa, res->start, resource_size(res)); }
ssize_t nd_namespace_store(struct device *dev, struct nd_namespace_common **_ndns, const char *buf, size_t len) { struct nd_namespace_common *ndns; struct device *found; char *name; if (dev->driver) { dev_dbg(dev, "%s: -EBUSY\n", __func__); return -EBUSY; } name = kstrndup(buf, len, GFP_KERNEL); if (!name) return -ENOMEM; strim(name); if (strncmp(name, "namespace", 9) == 0 || strcmp(name, "") == 0) /* pass */; else { len = -EINVAL; goto out; } ndns = *_ndns; if (strcmp(name, "") == 0) { nd_detach_and_reset(dev, _ndns); goto out; } else if (ndns) { dev_dbg(dev, "namespace already set to: %s\n", dev_name(&ndns->dev)); len = -EBUSY; goto out; } found = device_find_child(dev->parent, name, namespace_match); if (!found) { dev_dbg(dev, "'%s' not found under %s\n", name, dev_name(dev->parent)); len = -ENODEV; goto out; } ndns = to_ndns(found); if (__nvdimm_namespace_capacity(ndns) < SZ_16M) { dev_dbg(dev, "%s too small to host\n", name); len = -ENXIO; goto out_attach; } WARN_ON_ONCE(!is_nvdimm_bus_locked(dev)); if (!nd_attach_ndns(dev, ndns, _ndns)) { dev_dbg(dev, "%s already claimed\n", dev_name(&ndns->dev)); len = -EBUSY; } out_attach: put_device(&ndns->dev); /* from device_find_child */ out: kfree(name); return len; }
static ssize_t __namespace_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct nd_btt *nd_btt = to_nd_btt(dev); struct nd_namespace_common *ndns; struct device *found; char *name; if (dev->driver) { dev_dbg(dev, "%s: -EBUSY\n", __func__); return -EBUSY; } name = kstrndup(buf, len, GFP_KERNEL); if (!name) return -ENOMEM; strim(name); if (strncmp(name, "namespace", 9) == 0 || strcmp(name, "") == 0) /* pass */; else { len = -EINVAL; goto out; } ndns = nd_btt->ndns; if (strcmp(name, "") == 0) { /* detach the namespace and destroy / reset the btt device */ nd_btt_detach_ndns(nd_btt); if (is_nd_btt_idle(dev)) nd_device_unregister(dev, ND_ASYNC); else { nd_btt->lbasize = 0; kfree(nd_btt->uuid); nd_btt->uuid = NULL; } goto out; } else if (ndns) { dev_dbg(dev, "namespace already set to: %s\n", dev_name(&ndns->dev)); len = -EBUSY; goto out; } found = device_find_child(dev->parent, name, namespace_match); if (!found) { dev_dbg(dev, "'%s' not found under %s\n", name, dev_name(dev->parent)); len = -ENODEV; goto out; } ndns = to_ndns(found); if (__nvdimm_namespace_capacity(ndns) < SZ_16M) { dev_dbg(dev, "%s too small to host btt\n", name); len = -ENXIO; goto out_attach; } WARN_ON_ONCE(!is_nvdimm_bus_locked(&nd_btt->dev)); if (!nd_btt_attach_ndns(nd_btt, ndns)) { dev_dbg(dev, "%s already claimed\n", dev_name(&ndns->dev)); len = -EBUSY; } out_attach: put_device(&ndns->dev); /* from device_find_child */ out: kfree(name); return len; }