Commit 6d82120f authored by Dan Williams's avatar Dan Williams Committed by Linus Torvalds

device-dax: add an 'align' attribute

Introduce a device align attribute.  While doing so, rename the region
align attribute to be more explicitly named as so, but keep it named as
@align to retain the API for tools like daxctl.

Changes on align may not always be valid, when say certain mappings were
created with 2M and then we switch to 1G.  So, we validate all ranges
against the new value being attempted, post resizing.
Signed-off-by: default avatarJoao Martins <joao.m.martins@oracle.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Brice Goglin <Brice.Goglin@inria.fr>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Dave Jiang <dave.jiang@intel.com>
Cc: David Airlie <airlied@linux.ie>
Cc: David Hildenbrand <david@redhat.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Hulk Robot <hulkci@huawei.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Ira Weiny <ira.weiny@intel.com>
Cc: Jason Gunthorpe <jgg@mellanox.com>
Cc: Jason Yan <yanaijie@huawei.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: "Jérôme Glisse" <jglisse@redhat.com>
Cc: Jia He <justin.he@arm.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: kernel test robot <lkp@intel.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Paul Mackerras <paulus@ozlabs.org>
Cc: Pavel Tatashin <pasha.tatashin@soleen.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Vishal Verma <vishal.l.verma@intel.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Wei Yang <richard.weiyang@linux.alibaba.com>
Cc: Will Deacon <will@kernel.org>
Link: https://lkml.kernel.org/r/159643105944.4062302.3131761052969132784.stgit@dwillia2-desk3.amr.corp.intel.com
Link: https://lore.kernel.org/r/20200716172913.19658-3-joao.m.martins@oracle.com
Link: https://lkml.kernel.org/r/160106118486.30709.13012322227204800596.stgit@dwillia2-desk3.amr.corp.intel.comSigned-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 33cf94d7
...@@ -230,14 +230,15 @@ static ssize_t region_size_show(struct device *dev, ...@@ -230,14 +230,15 @@ static ssize_t region_size_show(struct device *dev,
static struct device_attribute dev_attr_region_size = __ATTR(size, 0444, static struct device_attribute dev_attr_region_size = __ATTR(size, 0444,
region_size_show, NULL); region_size_show, NULL);
static ssize_t align_show(struct device *dev, static ssize_t region_align_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct dax_region *dax_region = dev_get_drvdata(dev); struct dax_region *dax_region = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", dax_region->align); return sprintf(buf, "%u\n", dax_region->align);
} }
static DEVICE_ATTR_RO(align); static struct device_attribute dev_attr_region_align =
__ATTR(align, 0400, region_align_show, NULL);
#define for_each_dax_region_resource(dax_region, res) \ #define for_each_dax_region_resource(dax_region, res) \
for (res = (dax_region)->res.child; res; res = res->sibling) for (res = (dax_region)->res.child; res; res = res->sibling)
...@@ -488,7 +489,7 @@ static umode_t dax_region_visible(struct kobject *kobj, struct attribute *a, ...@@ -488,7 +489,7 @@ static umode_t dax_region_visible(struct kobject *kobj, struct attribute *a,
static struct attribute *dax_region_attributes[] = { static struct attribute *dax_region_attributes[] = {
&dev_attr_available_size.attr, &dev_attr_available_size.attr,
&dev_attr_region_size.attr, &dev_attr_region_size.attr,
&dev_attr_align.attr, &dev_attr_region_align.attr,
&dev_attr_create.attr, &dev_attr_create.attr,
&dev_attr_seed.attr, &dev_attr_seed.attr,
&dev_attr_delete.attr, &dev_attr_delete.attr,
...@@ -858,15 +859,13 @@ static ssize_t size_show(struct device *dev, ...@@ -858,15 +859,13 @@ static ssize_t size_show(struct device *dev,
return sprintf(buf, "%llu\n", size); return sprintf(buf, "%llu\n", size);
} }
static bool alloc_is_aligned(struct dax_region *dax_region, static bool alloc_is_aligned(struct dev_dax *dev_dax, resource_size_t size)
resource_size_t size)
{ {
/* /*
* The minimum mapping granularity for a device instance is a * The minimum mapping granularity for a device instance is a
* single subsection, unless the arch says otherwise. * single subsection, unless the arch says otherwise.
*/ */
return IS_ALIGNED(size, max_t(unsigned long, dax_region->align, return IS_ALIGNED(size, max_t(unsigned long, dev_dax->align, memremap_compat_align()));
memremap_compat_align()));
} }
static int dev_dax_shrink(struct dev_dax *dev_dax, resource_size_t size) static int dev_dax_shrink(struct dev_dax *dev_dax, resource_size_t size)
...@@ -961,7 +960,7 @@ static ssize_t dev_dax_resize(struct dax_region *dax_region, ...@@ -961,7 +960,7 @@ static ssize_t dev_dax_resize(struct dax_region *dax_region,
return dev_dax_shrink(dev_dax, size); return dev_dax_shrink(dev_dax, size);
to_alloc = size - dev_size; to_alloc = size - dev_size;
if (dev_WARN_ONCE(dev, !alloc_is_aligned(dax_region, to_alloc), if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc),
"resize of %pa misaligned\n", &to_alloc)) "resize of %pa misaligned\n", &to_alloc))
return -ENXIO; return -ENXIO;
...@@ -1025,7 +1024,7 @@ static ssize_t size_store(struct device *dev, struct device_attribute *attr, ...@@ -1025,7 +1024,7 @@ static ssize_t size_store(struct device *dev, struct device_attribute *attr,
if (rc) if (rc)
return rc; return rc;
if (!alloc_is_aligned(dax_region, val)) { if (!alloc_is_aligned(dev_dax, val)) {
dev_dbg(dev, "%s: size: %lld misaligned\n", __func__, val); dev_dbg(dev, "%s: size: %lld misaligned\n", __func__, val);
return -EINVAL; return -EINVAL;
} }
...@@ -1044,6 +1043,78 @@ static ssize_t size_store(struct device *dev, struct device_attribute *attr, ...@@ -1044,6 +1043,78 @@ static ssize_t size_store(struct device *dev, struct device_attribute *attr,
} }
static DEVICE_ATTR_RW(size); static DEVICE_ATTR_RW(size);
static ssize_t align_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dev_dax *dev_dax = to_dev_dax(dev);
return sprintf(buf, "%d\n", dev_dax->align);
}
static ssize_t dev_dax_validate_align(struct dev_dax *dev_dax)
{
resource_size_t dev_size = dev_dax_size(dev_dax);
struct device *dev = &dev_dax->dev;
int i;
if (dev_size > 0 && !alloc_is_aligned(dev_dax, dev_size)) {
dev_dbg(dev, "%s: align %u invalid for size %pa\n",
__func__, dev_dax->align, &dev_size);
return -EINVAL;
}
for (i = 0; i < dev_dax->nr_range; i++) {
size_t len = range_len(&dev_dax->ranges[i].range);
if (!alloc_is_aligned(dev_dax, len)) {
dev_dbg(dev, "%s: align %u invalid for range %d\n",
__func__, dev_dax->align, i);
return -EINVAL;
}
}
return 0;
}
static ssize_t align_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t len)
{
struct dev_dax *dev_dax = to_dev_dax(dev);
struct dax_region *dax_region = dev_dax->region;
unsigned long val, align_save;
ssize_t rc;
rc = kstrtoul(buf, 0, &val);
if (rc)
return -ENXIO;
if (!dax_align_valid(val))
return -EINVAL;
device_lock(dax_region->dev);
if (!dax_region->dev->driver) {
device_unlock(dax_region->dev);
return -ENXIO;
}
device_lock(dev);
if (dev->driver) {
rc = -EBUSY;
goto out_unlock;
}
align_save = dev_dax->align;
dev_dax->align = val;
rc = dev_dax_validate_align(dev_dax);
if (rc)
dev_dax->align = align_save;
out_unlock:
device_unlock(dev);
device_unlock(dax_region->dev);
return rc == 0 ? len : rc;
}
static DEVICE_ATTR_RW(align);
static int dev_dax_target_node(struct dev_dax *dev_dax) static int dev_dax_target_node(struct dev_dax *dev_dax)
{ {
struct dax_region *dax_region = dev_dax->region; struct dax_region *dax_region = dev_dax->region;
...@@ -1104,7 +1175,8 @@ static umode_t dev_dax_visible(struct kobject *kobj, struct attribute *a, int n) ...@@ -1104,7 +1175,8 @@ static umode_t dev_dax_visible(struct kobject *kobj, struct attribute *a, int n)
return 0; return 0;
if (a == &dev_attr_numa_node.attr && !IS_ENABLED(CONFIG_NUMA)) if (a == &dev_attr_numa_node.attr && !IS_ENABLED(CONFIG_NUMA))
return 0; return 0;
if (a == &dev_attr_size.attr && is_static(dax_region)) if ((a == &dev_attr_align.attr ||
a == &dev_attr_size.attr) && is_static(dax_region))
return 0444; return 0444;
return a->mode; return a->mode;
} }
...@@ -1113,6 +1185,7 @@ static struct attribute *dev_dax_attributes[] = { ...@@ -1113,6 +1185,7 @@ static struct attribute *dev_dax_attributes[] = {
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
&dev_attr_size.attr, &dev_attr_size.attr,
&dev_attr_target_node.attr, &dev_attr_target_node.attr,
&dev_attr_align.attr,
&dev_attr_resource.attr, &dev_attr_resource.attr,
&dev_attr_numa_node.attr, &dev_attr_numa_node.attr,
NULL, NULL,
......
...@@ -87,4 +87,22 @@ static inline struct dax_mapping *to_dax_mapping(struct device *dev) ...@@ -87,4 +87,22 @@ static inline struct dax_mapping *to_dax_mapping(struct device *dev)
} }
phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff, unsigned long size); phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff, unsigned long size);
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static inline bool dax_align_valid(unsigned long align)
{
if (align == PUD_SIZE && IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD))
return true;
if (align == PMD_SIZE && has_transparent_hugepage())
return true;
if (align == PAGE_SIZE)
return true;
return false;
}
#else
static inline bool dax_align_valid(unsigned long align)
{
return align == PAGE_SIZE;
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment