diff mbox series

[v5,7/8] device-dax: ensure dev_dax->pgmap is valid for dynamic devices

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

Commit Message

Joao Martins Nov. 12, 2021, 3:08 p.m. UTC
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(-)

Comments

Christoph Hellwig Nov. 17, 2021, 9:37 a.m. UTC | #1
> +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.
Joao Martins Nov. 17, 2021, 10:15 a.m. UTC | #2
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 mbox series

Patch

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;