Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Andrew 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.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dan Williams and committed by
Linus Torvalds
6d82120f 33cf94d7

+101 -10
+83 -10
drivers/dax/bus.c
··· 230 230 static struct device_attribute dev_attr_region_size = __ATTR(size, 0444, 231 231 region_size_show, NULL); 232 232 233 - static ssize_t align_show(struct device *dev, 233 + static ssize_t region_align_show(struct device *dev, 234 234 struct device_attribute *attr, char *buf) 235 235 { 236 236 struct dax_region *dax_region = dev_get_drvdata(dev); 237 237 238 238 return sprintf(buf, "%u\n", dax_region->align); 239 239 } 240 - static DEVICE_ATTR_RO(align); 240 + static struct device_attribute dev_attr_region_align = 241 + __ATTR(align, 0400, region_align_show, NULL); 241 242 242 243 #define for_each_dax_region_resource(dax_region, res) \ 243 244 for (res = (dax_region)->res.child; res; res = res->sibling) ··· 489 488 static struct attribute *dax_region_attributes[] = { 490 489 &dev_attr_available_size.attr, 491 490 &dev_attr_region_size.attr, 492 - &dev_attr_align.attr, 491 + &dev_attr_region_align.attr, 493 492 &dev_attr_create.attr, 494 493 &dev_attr_seed.attr, 495 494 &dev_attr_delete.attr, ··· 859 858 return sprintf(buf, "%llu\n", size); 860 859 } 861 860 862 - static bool alloc_is_aligned(struct dax_region *dax_region, 863 - resource_size_t size) 861 + static bool alloc_is_aligned(struct dev_dax *dev_dax, resource_size_t size) 864 862 { 865 863 /* 866 864 * The minimum mapping granularity for a device instance is a 867 865 * single subsection, unless the arch says otherwise. 868 866 */ 869 - return IS_ALIGNED(size, max_t(unsigned long, dax_region->align, 870 - memremap_compat_align())); 867 + return IS_ALIGNED(size, max_t(unsigned long, dev_dax->align, memremap_compat_align())); 871 868 } 872 869 873 870 static int dev_dax_shrink(struct dev_dax *dev_dax, resource_size_t size) ··· 960 961 return dev_dax_shrink(dev_dax, size); 961 962 962 963 to_alloc = size - dev_size; 963 - if (dev_WARN_ONCE(dev, !alloc_is_aligned(dax_region, to_alloc), 964 + if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc), 964 965 "resize of %pa misaligned\n", &to_alloc)) 965 966 return -ENXIO; 966 967 ··· 1024 1025 if (rc) 1025 1026 return rc; 1026 1027 1027 - if (!alloc_is_aligned(dax_region, val)) { 1028 + if (!alloc_is_aligned(dev_dax, val)) { 1028 1029 dev_dbg(dev, "%s: size: %lld misaligned\n", __func__, val); 1029 1030 return -EINVAL; 1030 1031 } ··· 1042 1043 return rc == 0 ? len : rc; 1043 1044 } 1044 1045 static DEVICE_ATTR_RW(size); 1046 + 1047 + static ssize_t align_show(struct device *dev, 1048 + struct device_attribute *attr, char *buf) 1049 + { 1050 + struct dev_dax *dev_dax = to_dev_dax(dev); 1051 + 1052 + return sprintf(buf, "%d\n", dev_dax->align); 1053 + } 1054 + 1055 + static ssize_t dev_dax_validate_align(struct dev_dax *dev_dax) 1056 + { 1057 + resource_size_t dev_size = dev_dax_size(dev_dax); 1058 + struct device *dev = &dev_dax->dev; 1059 + int i; 1060 + 1061 + if (dev_size > 0 && !alloc_is_aligned(dev_dax, dev_size)) { 1062 + dev_dbg(dev, "%s: align %u invalid for size %pa\n", 1063 + __func__, dev_dax->align, &dev_size); 1064 + return -EINVAL; 1065 + } 1066 + 1067 + for (i = 0; i < dev_dax->nr_range; i++) { 1068 + size_t len = range_len(&dev_dax->ranges[i].range); 1069 + 1070 + if (!alloc_is_aligned(dev_dax, len)) { 1071 + dev_dbg(dev, "%s: align %u invalid for range %d\n", 1072 + __func__, dev_dax->align, i); 1073 + return -EINVAL; 1074 + } 1075 + } 1076 + 1077 + return 0; 1078 + } 1079 + 1080 + static ssize_t align_store(struct device *dev, struct device_attribute *attr, 1081 + const char *buf, size_t len) 1082 + { 1083 + struct dev_dax *dev_dax = to_dev_dax(dev); 1084 + struct dax_region *dax_region = dev_dax->region; 1085 + unsigned long val, align_save; 1086 + ssize_t rc; 1087 + 1088 + rc = kstrtoul(buf, 0, &val); 1089 + if (rc) 1090 + return -ENXIO; 1091 + 1092 + if (!dax_align_valid(val)) 1093 + return -EINVAL; 1094 + 1095 + device_lock(dax_region->dev); 1096 + if (!dax_region->dev->driver) { 1097 + device_unlock(dax_region->dev); 1098 + return -ENXIO; 1099 + } 1100 + 1101 + device_lock(dev); 1102 + if (dev->driver) { 1103 + rc = -EBUSY; 1104 + goto out_unlock; 1105 + } 1106 + 1107 + align_save = dev_dax->align; 1108 + dev_dax->align = val; 1109 + rc = dev_dax_validate_align(dev_dax); 1110 + if (rc) 1111 + dev_dax->align = align_save; 1112 + out_unlock: 1113 + device_unlock(dev); 1114 + device_unlock(dax_region->dev); 1115 + return rc == 0 ? len : rc; 1116 + } 1117 + static DEVICE_ATTR_RW(align); 1045 1118 1046 1119 static int dev_dax_target_node(struct dev_dax *dev_dax) 1047 1120 { ··· 1175 1104 return 0; 1176 1105 if (a == &dev_attr_numa_node.attr && !IS_ENABLED(CONFIG_NUMA)) 1177 1106 return 0; 1178 - if (a == &dev_attr_size.attr && is_static(dax_region)) 1107 + if ((a == &dev_attr_align.attr || 1108 + a == &dev_attr_size.attr) && is_static(dax_region)) 1179 1109 return 0444; 1180 1110 return a->mode; 1181 1111 } ··· 1185 1113 &dev_attr_modalias.attr, 1186 1114 &dev_attr_size.attr, 1187 1115 &dev_attr_target_node.attr, 1116 + &dev_attr_align.attr, 1188 1117 &dev_attr_resource.attr, 1189 1118 &dev_attr_numa_node.attr, 1190 1119 NULL,
+18
drivers/dax/dax-private.h
··· 87 87 } 88 88 89 89 phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff, unsigned long size); 90 + 91 + #ifdef CONFIG_TRANSPARENT_HUGEPAGE 92 + static inline bool dax_align_valid(unsigned long align) 93 + { 94 + if (align == PUD_SIZE && IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)) 95 + return true; 96 + if (align == PMD_SIZE && has_transparent_hugepage()) 97 + return true; 98 + if (align == PAGE_SIZE) 99 + return true; 100 + return false; 101 + } 102 + #else 103 + static inline bool dax_align_valid(unsigned long align) 104 + { 105 + return align == PAGE_SIZE; 106 + } 107 + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 90 108 #endif