void nvdimm_drvdata_release(struct kref *kref) { struct nvdimm_drvdata *ndd = container_of(kref, typeof(*ndd), kref); struct device *dev = ndd->dev; struct resource *res, *_r; dev_dbg(dev, "%s\n", __func__); nvdimm_bus_lock(dev); for_each_dpa_resource_safe(ndd, res, _r) nvdimm_free_dpa(ndd, res); nvdimm_bus_unlock(dev); kvfree(ndd->data); kfree(ndd); put_device(dev); }
static int scan_free(struct nd_region *nd_region, struct nd_mapping *nd_mapping, struct nd_label_id *label_id, resource_size_t n) { bool is_blk = strncmp(label_id->id, "blk", 3) == 0; struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); int rc = 0; while (n) { struct resource *res, *last; resource_size_t new_start; last = NULL; for_each_dpa_resource(ndd, res) if (strcmp(res->name, label_id->id) == 0) last = res; res = last; if (!res) return 0; if (n >= resource_size(res)) { n -= resource_size(res); nd_dbg_dpa(nd_region, ndd, res, "delete %d\n", rc); nvdimm_free_dpa(ndd, res); /* retry with last resource deleted */ continue; } /* * Keep BLK allocations relegated to high DPA as much as * possible */ if (is_blk) new_start = res->start + n; else new_start = res->start; rc = adjust_resource(res, new_start, resource_size(res) - n); if (rc == 0) res->flags |= DPA_RESOURCE_ADJUSTED; nd_dbg_dpa(nd_region, ndd, res, "shrink %d\n", rc); break; } return rc; }