From: Ira Weiny <[email protected]>

Dynamic Capacity (DC) DAX regions back their dax devices with per-extent
resource children of the region, rather than carving from a single
contiguous dax_region->res.  Allocating space for a DC dax device — on
initial uuid claim of its backing extents and on shrink-to-0 during
destroy — needs the same allocator the static case uses, but pointed at
a different parent resource.

Factor the body of dev_dax_resize() into __dev_dax_resize(parent, ...)
and add a dev_dax_resize_static() wrapper that passes dax_region->res
for static (non-DC) regions.  alloc_dev_dax_range() gains the same
parent parameter so it can operate under either kind of parent.

No functional change.

Reviewed-by: Jonathan Cameron <[email protected]>
Reviewed-by: Dave Jiang <[email protected]>
Signed-off-by: Ira Weiny <[email protected]>

---
Changes:
[anisa: reword to drop the options-considered discussion and "sparse"
 terminology; preserved in a later commit that realizes per-extent
 resource children]
---
 drivers/dax/bus.c | 131 ++++++++++++++++++++++++++++------------------
 1 file changed, 81 insertions(+), 50 deletions(-)

diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
index 6368bdfdf93a..5c1b93890d30 100644
--- a/drivers/dax/bus.c
+++ b/drivers/dax/bus.c
@@ -1012,11 +1012,10 @@ static int devm_register_dax_mapping(struct dev_dax 
*dev_dax, int range_id)
        return 0;
 }
 
-static int alloc_dev_dax_range(struct dev_dax *dev_dax, u64 start,
-               resource_size_t size, struct dax_resource *dax_resource)
+static int alloc_dev_dax_range(struct resource *parent, struct dev_dax 
*dev_dax,
+                              u64 start, resource_size_t size,
+                              struct dax_resource *dax_resource)
 {
-       struct dax_region *dax_region = dev_dax->region;
-       struct resource *res = &dax_region->res;
        struct device *dev = &dev_dax->dev;
        struct dev_dax_range *ranges;
        unsigned long pgoff = 0;
@@ -1034,14 +1033,14 @@ static int alloc_dev_dax_range(struct dev_dax *dev_dax, 
u64 start,
                return 0;
        }
 
-       alloc = __request_region(res, start, size, dev_name(dev), 0);
+       alloc = __request_region(parent, start, size, dev_name(dev), 0);
        if (!alloc)
                return -ENOMEM;
 
        ranges = krealloc(dev_dax->ranges, sizeof(*ranges)
                        * (dev_dax->nr_range + 1), GFP_KERNEL);
        if (!ranges) {
-               __release_region(res, alloc->start, resource_size(alloc));
+               __release_region(parent, alloc->start, resource_size(alloc));
                return -ENOMEM;
        }
 
@@ -1195,50 +1194,45 @@ static bool adjust_ok(struct dev_dax *dev_dax, struct 
resource *res)
        return true;
 }
 
-static ssize_t dev_dax_resize(struct dax_region *dax_region,
-               struct dev_dax *dev_dax, resource_size_t size)
+/**
+ * dev_dax_resize_static - Expand the device into the unused portion of the
+ * region. This may involve adjusting the end of an existing resource, or
+ * allocating a new resource.
+ *
+ * @parent: parent resource to allocate this range in
+ * @dev_dax: DAX device to be expanded
+ * @to_alloc: amount of space to alloc; must be <= space available in @parent
+ *
+ * Return the amount of space allocated or -ERRNO on failure
+ */
+static ssize_t dev_dax_resize_static(struct resource *parent,
+                                    struct dev_dax *dev_dax,
+                                    resource_size_t to_alloc)
 {
-       resource_size_t avail = dax_region_avail_size(dax_region), to_alloc;
-       resource_size_t dev_size = dev_dax_size(dev_dax);
-       struct resource *region_res = &dax_region->res;
-       struct device *dev = &dev_dax->dev;
        struct resource *res, *first;
-       resource_size_t alloc = 0;
        int rc;
 
-       if (dev->driver)
-               return -EBUSY;
-       if (size == dev_size)
-               return 0;
-       if (size > dev_size && size - dev_size > avail)
-               return -ENOSPC;
-       if (size < dev_size)
-               return dev_dax_shrink(dev_dax, size);
-
-       to_alloc = size - dev_size;
-       if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc),
-                       "resize of %pa misaligned\n", &to_alloc))
-               return -ENXIO;
-
-       /*
-        * Expand the device into the unused portion of the region. This
-        * may involve adjusting the end of an existing resource, or
-        * allocating a new resource.
-        */
-retry:
-       first = region_res->child;
-       if (!first)
-               return alloc_dev_dax_range(dev_dax, dax_region->res.start, 
to_alloc, NULL);
+       first = parent->child;
+       if (!first) {
+               rc = alloc_dev_dax_range(parent, dev_dax,
+                                          parent->start, to_alloc, NULL);
+               if (rc)
+                       return rc;
+               return to_alloc;
+       }
 
-       rc = -ENOSPC;
        for (res = first; res; res = res->sibling) {
                struct resource *next = res->sibling;
+               resource_size_t alloc;
 
                /* space at the beginning of the region */
-               if (res == first && res->start > dax_region->res.start) {
-                       alloc = min(res->start - dax_region->res.start, 
to_alloc);
-                       rc = alloc_dev_dax_range(dev_dax, 
dax_region->res.start, alloc, NULL);
-                       break;
+               if (res == first && res->start > parent->start) {
+                       alloc = min(res->start - parent->start, to_alloc);
+                       rc = alloc_dev_dax_range(parent, dev_dax,
+                                                parent->start, alloc, NULL);
+                       if (rc)
+                               return rc;
+                       return alloc;
                }
 
                alloc = 0;
@@ -1247,21 +1241,56 @@ static ssize_t dev_dax_resize(struct dax_region 
*dax_region,
                        alloc = min(next->start - (res->end + 1), to_alloc);
 
                /* space at the end of the region */
-               if (!alloc && !next && res->end < region_res->end)
-                       alloc = min(region_res->end - res->end, to_alloc);
+               if (!alloc && !next && res->end < parent->end)
+                       alloc = min(parent->end - res->end, to_alloc);
 
                if (!alloc)
                        continue;
 
                if (adjust_ok(dev_dax, res)) {
                        rc = adjust_dev_dax_range(dev_dax, res, 
resource_size(res) + alloc);
-                       break;
+                       if (rc)
+                               return rc;
+                       return alloc;
                }
-               rc = alloc_dev_dax_range(dev_dax, res->end + 1, alloc, NULL);
-               break;
+               rc = alloc_dev_dax_range(parent, dev_dax, res->end + 1, alloc, 
NULL);
+               if (rc)
+                       return rc;
+               return alloc;
        }
-       if (rc)
-               return rc;
+
+       /* available was already calculated and should never be an issue */
+       dev_WARN_ONCE(&dev_dax->dev, 1, "space not found?");
+       return 0;
+}
+
+static ssize_t dev_dax_resize(struct dax_region *dax_region,
+               struct dev_dax *dev_dax, resource_size_t size)
+{
+       resource_size_t avail = dax_region_avail_size(dax_region);
+       resource_size_t dev_size = dev_dax_size(dev_dax);
+       struct device *dev = &dev_dax->dev;
+       resource_size_t to_alloc;
+       resource_size_t alloc;
+
+       if (dev->driver)
+               return -EBUSY;
+       if (size == dev_size)
+               return 0;
+       if (size > dev_size && size - dev_size > avail)
+               return -ENOSPC;
+       if (size < dev_size)
+               return dev_dax_shrink(dev_dax, size);
+
+       to_alloc = size - dev_size;
+       if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc),
+                       "resize of %pa misaligned\n", &to_alloc))
+               return -ENXIO;
+
+retry:
+       alloc = dev_dax_resize_static(&dax_region->res, dev_dax, to_alloc);
+       if (alloc <= 0)
+               return alloc;
        to_alloc -= alloc;
        if (to_alloc)
                goto retry;
@@ -1367,7 +1396,8 @@ static ssize_t mapping_store(struct device *dev, struct 
device_attribute *attr,
 
        to_alloc = range_len(&r);
        if (alloc_is_aligned(dev_dax, to_alloc))
-               rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc, NULL);
+               rc = alloc_dev_dax_range(&dax_region->res, dev_dax, r.start,
+                                        to_alloc, NULL);
        up_write(&dax_dev_rwsem);
        up_write(&dax_region_rwsem);
 
@@ -1659,7 +1689,8 @@ static struct dev_dax *__devm_create_dev_dax(struct 
dev_dax_data *data)
        device_initialize(dev);
        dev_set_name(dev, "dax%d.%d", dax_region->id, dev_dax->id);
 
-       rc = alloc_dev_dax_range(dev_dax, dax_region->res.start, data->size, 
NULL);
+       rc = alloc_dev_dax_range(&dax_region->res, dev_dax, 
dax_region->res.start,
+                                data->size, NULL);
        if (rc)
                goto err_range;
 
-- 
2.43.0


Reply via email to