Message ID | 20211112150824.11028-8-joao.m.martins@oracle.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | mm, dax: Introduce compound pages in devmap | expand |
> +bool static_dev_dax(struct dev_dax *dev_dax) > +{ > + return is_static(dev_dax->region); > +} > +EXPORT_SYMBOL_GPL(static_dev_dax); This function would massively benefit from documentic what a static DAX region is and why someone would want to care. Because even as someone occasionally dabbling with the DAX code I have no idea at all what that means.
On 11/17/21 10:37, Christoph Hellwig wrote: >> +bool static_dev_dax(struct dev_dax *dev_dax) >> +{ >> + return is_static(dev_dax->region); >> +} >> +EXPORT_SYMBOL_GPL(static_dev_dax); > > This function would massively benefit from documentic what a static > DAX region is and why someone would want to care. Because even as > someone occasionally dabbling with the DAX code I have no idea at all > what that means. > Good idea. Maybe something like this: diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 19dd83d3f3ea..8be6ec1ba193 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -129,6 +129,19 @@ ATTRIBUTE_GROUPS(dax_drv); static int dax_bus_match(struct device *dev, struct device_driver *drv); +/* + * Static dax regions (PMEM) are regions partitioned by an external entity like + * nvdimm where a single range is assigned and which boundaries are + * defined by NVDIMM Namespace boundaries (e.g. need to be contiguous). + * Dynamic dax regions (HMEM), the assigned region can be subdivided by dax + * core into multiple devices (i.e. "partitions") which are composed with 1 or + * more discontiguous ranges. + * When allocating a dax region, drivers must set whether it's static. + * On static dax devices, the @pgmap is pre-assigned to dax when calling + * devm_create_dev_dax(), whereas in dynamic dax devices it is allocated + * on device ->probe(). Care is needed to make sure that non static devices + * are killed with a cleared @pgmap field (see kill_dev_dax()). + */ static bool is_static(struct dax_region *dax_region) { return (dax_region->res.flags & IORESOURCE_DAX_STATIC) != 0;
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 6cc4da4c713d..19dd83d3f3ea 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -134,6 +134,12 @@ static bool is_static(struct dax_region *dax_region) return (dax_region->res.flags & IORESOURCE_DAX_STATIC) != 0; } +bool static_dev_dax(struct dev_dax *dev_dax) +{ + return is_static(dev_dax->region); +} +EXPORT_SYMBOL_GPL(static_dev_dax); + static u64 dev_dax_size(struct dev_dax *dev_dax) { u64 size = 0; @@ -363,6 +369,14 @@ void kill_dev_dax(struct dev_dax *dev_dax) kill_dax(dax_dev); unmap_mapping_range(inode->i_mapping, 0, 0, 1); + + /* + * Dynamic dax region have the pgmap allocated via dev_kzalloc() + * and thus freed by devm. Clear the pgmap to not have stale pgmap + * ranges on probe() from previous reconfigurations of region devices. + */ + if (!static_dev_dax(dev_dax)) + dev_dax->pgmap = NULL; } EXPORT_SYMBOL_GPL(kill_dev_dax); diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index 1e946ad7780a..4acdfee7dd59 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -48,6 +48,7 @@ int __dax_driver_register(struct dax_device_driver *dax_drv, __dax_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) void dax_driver_unregister(struct dax_device_driver *dax_drv); void kill_dev_dax(struct dev_dax *dev_dax); +bool static_dev_dax(struct dev_dax *dev_dax); #if IS_ENABLED(CONFIG_DEV_DAX_PMEM_COMPAT) int dev_dax_probe(struct dev_dax *dev_dax); diff --git a/drivers/dax/device.c b/drivers/dax/device.c index d6796a3115a6..a65c67ab5ee0 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -398,18 +398,33 @@ int dev_dax_probe(struct dev_dax *dev_dax) void *addr; int rc, i; - pgmap = dev_dax->pgmap; - if (dev_WARN_ONCE(dev, pgmap && dev_dax->nr_range > 1, - "static pgmap / multi-range device conflict\n")) + if (static_dev_dax(dev_dax) && dev_dax->nr_range > 1) { + dev_warn(dev, "static pgmap / multi-range device conflict\n"); return -EINVAL; + } + + if (static_dev_dax(dev_dax)) { + pgmap = dev_dax->pgmap; + } else { + if (dev_dax->pgmap) { + dev_warn(dev, + "dynamic-dax with pre-populated page map\n"); + return -EINVAL; + } - if (!pgmap) { pgmap = devm_kzalloc( dev, struct_size(pgmap, ranges, dev_dax->nr_range - 1), GFP_KERNEL); if (!pgmap) return -ENOMEM; + pgmap->nr_range = dev_dax->nr_range; + dev_dax->pgmap = pgmap; + + for (i = 0; i < dev_dax->nr_range; i++) { + struct range *range = &dev_dax->ranges[i].range; + pgmap->ranges[i] = *range; + } } for (i = 0; i < dev_dax->nr_range; i++) { @@ -421,9 +436,6 @@ int dev_dax_probe(struct dev_dax *dev_dax) i, range->start, range->end); return -EBUSY; } - /* don't update the range for static pgmap */ - if (!dev_dax->pgmap) - pgmap->ranges[i] = *range; } pgmap->type = MEMORY_DEVICE_GENERIC;
Right now, only static dax regions have a valid @pgmap pointer in its struct dev_dax. Dynamic dax case however, do not. In preparation for device-dax compound devmap support, make sure that dev_dax pgmap field is set after it has been allocated and initialized. dynamic dax device have the @pgmap is allocated at probe() and it's managed by devm (contrast to static dax region which a pgmap is provided and dax core kfrees it). So in addition to ensure a valid @pgmap, clear the pgmap when the dynamic dax device is released to avoid the same pgmap ranges to be re-requested across multiple region device reconfigs. Add a static_dev_dax() and use that helper in dev_dax_probe() to ensure the initialization differences between dynamic and static regions are more explicit. While at it, consolidate the ranges initialization when we allocate the @pgmap for the dynamic dax region case. Suggested-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Joao Martins <joao.m.martins@oracle.com> --- drivers/dax/bus.c | 14 ++++++++++++++ drivers/dax/bus.h | 1 + drivers/dax/device.c | 26 +++++++++++++++++++------- 3 files changed, 34 insertions(+), 7 deletions(-)