Memory hotplug operations require ranges aligned to memory block
boundaries.  This is a generic operation for hotplug.

Add memory_block_aligned_range() as a common helper in <linux/memory.h>
that aligns the start address up and end address down to memory block
boundaries.  Guard against end underflow when the range falls below the
first memory block boundary, returning an empty range instead.

Update dax/kmem to use this helper.

Signed-off-by: Gregory Price <[email protected]>
Acked-by: David Hildenbrand (Arm) <[email protected]>
---
 drivers/dax/kmem.c     |  4 +---
 include/linux/memory.h | 27 +++++++++++++++++++++++++++
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index a18e2b968e4d..592171ec10f4 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -33,9 +33,7 @@ static int dax_kmem_range(struct dev_dax *dev_dax, int i, 
struct range *r)
        struct dev_dax_range *dax_range = &dev_dax->ranges[i];
        struct range *range = &dax_range->range;
 
-       /* memory-block align the hotplug range */
-       r->start = ALIGN(range->start, memory_block_size_bytes());
-       r->end = ALIGN_DOWN(range->end + 1, memory_block_size_bytes()) - 1;
+       *r = memory_block_aligned_range(range);
        if (r->start >= r->end) {
                r->start = range->start;
                r->end = range->end;
diff --git a/include/linux/memory.h b/include/linux/memory.h
index 463dc02f6cff..1783299073e4 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -20,6 +20,7 @@
 #include <linux/compiler.h>
 #include <linux/mutex.h>
 #include <linux/memory_hotplug.h>
+#include <linux/range.h>
 
 #define MIN_MEMORY_BLOCK_SIZE     (1UL << SECTION_SIZE_BITS)
 
@@ -100,6 +101,32 @@ int arch_get_memory_phys_device(unsigned long start_pfn);
 unsigned long memory_block_size_bytes(void);
 int set_memory_block_size_order(unsigned int order);
 
+/**
+ * memory_block_aligned_range - align a physical address range to memory blocks
+ * @range: the input range to align
+ *
+ * Aligns the start address up and the end address down to memory block
+ * boundaries. This is required for memory hotplug operations which must
+ * operate on memory-block aligned ranges.
+ *
+ * Returns the aligned range. Callers should check that the returned
+ * range is valid (aligned.start < aligned.end) before using it.
+ */
+static inline struct range memory_block_aligned_range(const struct range 
*range)
+{
+       struct range aligned;
+
+       aligned.start = ALIGN(range->start, memory_block_size_bytes());
+       aligned.end = ALIGN_DOWN(range->end + 1, memory_block_size_bytes());
+       /* No whole block fits (e.g. range below the first boundary): empty. */
+       if (aligned.end <= aligned.start)
+               aligned.start = aligned.end;
+       else
+               aligned.end -= 1;
+
+       return aligned;
+}
+
 struct memory_notify {
        unsigned long start_pfn;
        unsigned long nr_pages;
-- 
2.53.0-Meta


Reply via email to