[PATCH v2] mm/memory_hotplug: refrain from adding memory into an impossible node
by Vishal Verma
A misbehaving qemu created a situation where the ACPI SRAT table
advertised one fewer proximity domains than intended. The NFIT table did
describe all the expected proximity domains. This caused the device dax
driver to assign an impossible target_node to the device, and when
hotplugged as system memory, this would fail with the following
signature:
[ +0.001627] BUG: kernel NULL pointer dereference, address: 0000000000000088
[ +0.001331] #PF: supervisor read access in kernel mode
[ +0.000975] #PF: error_code(0x0000) - not-present page
[ +0.000976] PGD 80000001767d4067 P4D 80000001767d4067 PUD 10e0c4067 PMD 0
[ +0.001338] Oops: 0000 [#1] SMP PTI
[ +0.000676] CPU: 4 PID: 22737 Comm: kswapd3 Tainted: G O 5.6.0-rc5 #9
[ +0.001457] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014
[ +0.001990] RIP: 0010:prepare_kswapd_sleep+0x7c/0xc0
[ +0.000780] Code: 89 df e8 87 fd ff ff 89 c2 31 c0 84 d2 74 e6 0f 1f 44
00 00 48 8b 05 fb af 7a 01 48 63 93 88 1d 01 00 48 8b
84 d0 20 0f 00 00 <48> 3b 98 88 00 00 00 75 28 f0 80 a0
80 00 00 00 fe f0 80 a3 38 20
[ +0.002877] RSP: 0018:ffffc900017a3e78 EFLAGS: 00010202
[ +0.000805] RAX: 0000000000000000 RBX: ffff8881209e0000 RCX: 0000000000000000
[ +0.001115] RDX: 0000000000000003 RSI: 0000000000000000 RDI: ffff8881209e0e80
[ +0.001098] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000008000
[ +0.001092] R10: 0000000000000000 R11: 0000000000000003 R12: 0000000000000003
[ +0.001092] R13: 0000000000000003 R14: 0000000000000000 R15: ffffc900017a3ec8
[ +0.001091] FS: 0000000000000000(0000) GS:ffff888318c00000(0000) knlGS:0000000000000000
[ +0.001275] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ +0.000882] CR2: 0000000000000088 CR3: 0000000120b50002 CR4: 00000000001606e0
[ +0.001095] Call Trace:
[ +0.000388] kswapd+0x103/0x520
[ +0.000494] ? finish_wait+0x80/0x80
[ +0.000547] ? balance_pgdat+0x5a0/0x5a0
[ +0.000607] kthread+0x120/0x140
[ +0.000508] ? kthread_create_on_node+0x60/0x60
[ +0.000706] ret_from_fork+0x3a/0x50
Add a check in the add_memory path to ensure that the node to which we
are adding memory is in the node_possible_map
Cc: David Hildenbrand <david(a)redhat.com>
Cc: Dan Williams <dan.j.williams(a)intel.com>
Cc: Dave Hansen <dave.hansen(a)linux.intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma(a)intel.com>
---
mm/memory_hotplug.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
v2:
- Centralize the check in the add_memory path (David)
- Instead of failing, add the memory to a nearby node, while warning
(and tainting) to call out attention to the firmware bug (Dan)
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 0a54ffac8c68..022df38a5d8a 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -980,6 +980,28 @@ static int check_hotplug_memory_range(u64 start, u64 size)
return 0;
}
+/*
+ * Check that the node provided for adding memory was valid.
+ * If not, find the nearest valid node and add the memory there while
+ * tainting the kernel and displaying a warning to bring attention to the
+ * underlying firmware problem.
+ * Return nid if valid, or an adjusted node number that can be used instead
+ * if the original nid was not valid
+ */
+static int check_hotplug_node(int nid)
+{
+ int alt_nid;
+
+ if (node_possible(nid))
+ return nid;
+
+ alt_nid = numa_map_to_online_node(nid);
+ WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND,
+ "node %d expected, but was absent from the node_possible_map, using %d instead\n",
+ nid, alt_nid);
+ return alt_nid;
+}
+
static int online_memory_block(struct memory_block *mem, void *arg)
{
return device_online(&mem->dev);
@@ -1005,6 +1027,10 @@ int __ref add_memory_resource(int nid, struct resource *res)
if (ret)
return ret;
+ nid = check_hotplug_node(nid);
+ if (nid < 0)
+ return -ENXIO;
+
mem_hotplug_begin();
/*
--
2.21.1
2 years, 1 month
[PATCH] dax/kmem: refrain from adding memory into an impossible node
by Vishal Verma
A misbehaving qemu created a situation where the ACPI SRAT table
advertised one fewer proximity domains than intended. The NFIT table did
describe all the expected proximity domains. This caused the device dax
driver to assign an impossible target_node to the device, and when
hotplugged as system memory, this would fail with the following
signature:
[ +0.001627] BUG: kernel NULL pointer dereference, address: 0000000000000088
[ +0.001331] #PF: supervisor read access in kernel mode
[ +0.000975] #PF: error_code(0x0000) - not-present page
[ +0.000976] PGD 80000001767d4067 P4D 80000001767d4067 PUD 10e0c4067 PMD 0
[ +0.001338] Oops: 0000 [#1] SMP PTI
[ +0.000676] CPU: 4 PID: 22737 Comm: kswapd3 Tainted: G O 5.6.0-rc5 #9
[ +0.001457] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014
[ +0.001990] RIP: 0010:prepare_kswapd_sleep+0x7c/0xc0
[ +0.000780] Code: 89 df e8 87 fd ff ff 89 c2 31 c0 84 d2 74 e6 0f 1f 44
00 00 48 8b 05 fb af 7a 01 48 63 93 88 1d 01 00 48 8b
84 d0 20 0f 00 00 <48> 3b 98 88 00 00 00 75 28 f0 80 a0
80 00 00 00 fe f0 80 a3 38 20
[ +0.002877] RSP: 0018:ffffc900017a3e78 EFLAGS: 00010202
[ +0.000805] RAX: 0000000000000000 RBX: ffff8881209e0000 RCX: 0000000000000000
[ +0.001115] RDX: 0000000000000003 RSI: 0000000000000000 RDI: ffff8881209e0e80
[ +0.001098] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000008000
[ +0.001092] R10: 0000000000000000 R11: 0000000000000003 R12: 0000000000000003
[ +0.001092] R13: 0000000000000003 R14: 0000000000000000 R15: ffffc900017a3ec8
[ +0.001091] FS: 0000000000000000(0000) GS:ffff888318c00000(0000) knlGS:0000000000000000
[ +0.001275] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ +0.000882] CR2: 0000000000000088 CR3: 0000000120b50002 CR4: 00000000001606e0
[ +0.001095] Call Trace:
[ +0.000388] kswapd+0x103/0x520
[ +0.000494] ? finish_wait+0x80/0x80
[ +0.000547] ? balance_pgdat+0x5a0/0x5a0
[ +0.000607] kthread+0x120/0x140
[ +0.000508] ? kthread_create_on_node+0x60/0x60
[ +0.000706] ret_from_fork+0x3a/0x50
Add a check in the kmem driver to ensure that the target_node for the
device in question is in the nodes_possible mask.
Cc: Dan Williams <dan.j.williams(a)intel.com>
Acked-by: Dave Hansen <dave.hansen(a)linux.intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma(a)intel.com>
---
drivers/dax/kmem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index 3d0a7e702c94..760c5b4e88c8 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -32,7 +32,7 @@ int dev_dax_kmem_probe(struct device *dev)
* unavoidable performance issues.
*/
numa_node = dev_dax->target_node;
- if (numa_node < 0) {
+ if (numa_node < 0 || !node_possible(numa_node)) {
dev_warn(dev, "rejecting DAX region %pR with invalid node: %d\n",
res, numa_node);
return -EINVAL;
--
2.21.1
2 years, 1 month
[ndctl PATCH] Skip region filtering if numa_node attribute is not present
by Santosh Sivaraj
For kernel versions older than 5.4, the numa_node attribute is not
present for regions; due to which `ndctl list -U 1` fails to list
namespaces.
Signed-off-by: Santosh Sivaraj <santosh(a)fossix.org>
---
ndctl/lib/libndctl.c | 11 +++++++++++
ndctl/lib/libndctl.sym | 1 +
ndctl/libndctl.h | 1 +
util/filter.c | 12 +++++++++++-
4 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index ee737cb..fc82084 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -2471,6 +2471,17 @@ NDCTL_EXPORT struct ndctl_dimm *ndctl_region_get_next_dimm(struct ndctl_region *
return NULL;
}
+NDCTL_EXPORT int ndctl_region_has_numa_attr(struct ndctl_region *region)
+{
+ char *path = region->region_buf;
+
+ sprintf(path, "%s/numa_node", region->region_path);
+ if (access(path, F_OK) != -1)
+ return 1;
+
+ return 0;
+}
+
NDCTL_EXPORT int ndctl_region_get_numa_node(struct ndctl_region *region)
{
return region->numa_node;
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index ac575a2..b7c72a2 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -430,4 +430,5 @@ LIBNDCTL_23 {
ndctl_region_get_target_node;
ndctl_region_get_align;
ndctl_region_set_align;
+ ndctl_region_has_numa_attr;
} LIBNDCTL_22;
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index 2580f43..4e233d8 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -385,6 +385,7 @@ struct ndctl_dimm *ndctl_region_get_first_dimm(struct ndctl_region *region);
struct ndctl_dimm *ndctl_region_get_next_dimm(struct ndctl_region *region,
struct ndctl_dimm *dimm);
int ndctl_region_get_numa_node(struct ndctl_region *region);
+int ndctl_region_has_numa_attr(struct ndctl_region *region);
int ndctl_region_get_target_node(struct ndctl_region *region);
struct ndctl_region *ndctl_bus_get_region_by_physical_address(struct ndctl_bus *bus,
unsigned long long address);
diff --git a/util/filter.c b/util/filter.c
index af72793..8e60cfa 100644
--- a/util/filter.c
+++ b/util/filter.c
@@ -467,7 +467,13 @@ int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,
param->namespace))
continue;
- if (numa_node != NUMA_NO_NODE &&
+ /*
+ * if numa_node attribute is not available for regions
+ * (which is true for pre 5.4 kernels), don't skip the
+ * region, let namespace filter handle the filtering.
+ */
+ if (ndctl_region_has_numa_attr(region) &&
+ numa_node != NUMA_NO_NODE &&
ndctl_region_get_numa_node(region) != numa_node)
continue;
@@ -489,6 +495,10 @@ int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,
if (param->mode && util_nsmode(param->mode) != mode)
continue;
+ if (numa_node != NUMA_NO_NODE &&
+ ndctl_namespace_get_numa_node(ndns) != numa_node)
+ continue;
+
fctx->filter_namespace(ndns, fctx);
}
}
--
2.25.2
2 years, 1 month
[RFC PATCH] /dev/mem: Revoke mappings when a driver claims the
region
by Dan Williams
Commit 90a545e98126 ("restrict /dev/mem to idle io memory ranges")
introduced CONFIG_IO_STRICT_DEVMEM with the goal of protecting the
kernel against scenarios where a /dev/mem user tramples memory that a
kernel driver owns. However, this protection only prevents *new* read(),
write() and mmap() requests. Established mappings prior to the driver
calling request_mem_region() are left alone.
Especially with persistent memory, and the core kernel metadata that is
stored there, there are plentiful scenarios for a /dev/mem user to
violate the expectations of the driver and cause amplified damage.
Teach request_mem_region() to find and shoot down active /dev/mem
mappings that it believes it has successfully claimed for the exclusive
use of the driver.
Cc: Arnd Bergmann <arnd(a)arndb.de>
Cc: Ingo Molnar <mingo(a)redhat.com>
Cc: Kees Cook <keescook(a)chromium.org>
Cc: Russell King <linux(a)arm.linux.org.uk>
Cc: Andrew Morton <akpm(a)linux-foundation.org>
Cc: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Fixes: 90a545e98126 ("restrict /dev/mem to idle io memory ranges")
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
I marked this RFC because after writing it I realized we potentially
have the same problem with /dev/port, and many mmap drivers in general.
Is there a wider solution I'm missing?
drivers/char/mem.c | 104 +++++++++++++++++++++++++++++++++++++++++++-
include/linux/ioport.h | 6 +++
include/uapi/linux/magic.h | 1
kernel/resource.c | 5 ++
4 files changed, 114 insertions(+), 2 deletions(-)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 43dd0891ca1e..3a3b7b37c5d2 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -31,11 +31,15 @@
#include <linux/uio.h>
#include <linux/uaccess.h>
#include <linux/security.h>
+#include <linux/pseudo_fs.h>
+#include <uapi/linux/magic.h>
+#include <linux/mount.h>
#ifdef CONFIG_IA64
# include <linux/efi.h>
#endif
+#define DEVMEM_MINOR 1
#define DEVPORT_MINOR 4
static inline unsigned long size_inside_page(unsigned long start,
@@ -805,12 +809,66 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
return ret;
}
+static struct inode *devmem_inode;
+
+#ifdef CONFIG_IO_STRICT_DEVMEM
+void revoke_devmem(struct resource *res)
+{
+ struct inode *inode = READ_ONCE(devmem_inode);
+
+ /*
+ * Check that the initialization has completed. Losing the race
+ * is ok because it means drivers are claiming resources before
+ * the fs_initcall level of init and prevent /dev/mem from
+ * establishing mappings.
+ */
+ smp_rmb();
+ if (!inode)
+ return;
+
+ /*
+ * The expectation is that the driver has successfully marked
+ * the resource busy by this point, so devmem_is_allowed()
+ * should start returning false, however for performance this
+ * does not iterate the entire resource range.
+ */
+ if (devmem_is_allowed(PHYS_PFN(res->start)) &&
+ devmem_is_allowed(PHYS_PFN(res->end))) {
+ /*
+ * *cringe* iomem=relaxed says "go ahead, what's the
+ * worst that can happen?"
+ */
+ return;
+ }
+
+ unmap_mapping_range(inode->i_mapping, res->start, resource_size(res), 1);
+}
+#endif
+
static int open_port(struct inode *inode, struct file *filp)
{
+ int rc;
+
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- return security_locked_down(LOCKDOWN_DEV_MEM);
+ rc = security_locked_down(LOCKDOWN_DEV_MEM);
+ if (rc)
+ return rc;
+
+ if (iminor(inode) != DEVMEM_MINOR)
+ return 0;
+
+ /*
+ * Use a unified address space to have a single point to manage
+ * revocations when drivers want to take over a /dev/mem mapped
+ * range.
+ */
+ inode->i_mapping = devmem_inode->i_mapping;
+ inode->i_mapping->host = devmem_inode;
+ filp->f_mapping = inode->i_mapping;
+
+ return 0;
}
#define zero_lseek null_lseek
@@ -885,7 +943,7 @@ static const struct memdev {
fmode_t fmode;
} devlist[] = {
#ifdef CONFIG_DEVMEM
- [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
+ [DEVMEM_MINOR] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
#endif
#ifdef CONFIG_DEVKMEM
[2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET },
@@ -939,6 +997,46 @@ static char *mem_devnode(struct device *dev, umode_t *mode)
static struct class *mem_class;
+static int devmem_fs_init_fs_context(struct fs_context *fc)
+{
+ return init_pseudo(fc, DEVMEM_MAGIC) ? 0 : -ENOMEM;
+}
+
+static struct file_system_type devmem_fs_type = {
+ .name = "devmem",
+ .owner = THIS_MODULE,
+ .init_fs_context = devmem_fs_init_fs_context,
+ .kill_sb = kill_anon_super,
+};
+
+static int devmem_init_inode(void)
+{
+ static struct vfsmount *devmem_vfs_mount;
+ static int devmem_fs_cnt;
+ struct inode *inode;
+ int rc;
+
+ rc = simple_pin_fs(&devmem_fs_type, &devmem_vfs_mount, &devmem_fs_cnt);
+ if (rc < 0) {
+ pr_err("Cannot mount /dev/mem pseudo filesystem: %d\n", rc);
+ return rc;
+ }
+
+ inode = alloc_anon_inode(devmem_vfs_mount->mnt_sb);
+ if (IS_ERR(inode)) {
+ rc = PTR_ERR(inode);
+ pr_err("Cannot allocate inode for /dev/mem: %d\n", rc);
+ simple_release_fs(&devmem_vfs_mount, &devmem_fs_cnt);
+ return rc;
+ }
+
+ /* publish /dev/mem initialized */
+ WRITE_ONCE(devmem_inode, inode);
+ smp_wmb();
+
+ return 0;
+}
+
static int __init chr_dev_init(void)
{
int minor;
@@ -960,6 +1058,8 @@ static int __init chr_dev_init(void)
*/
if ((minor == DEVPORT_MINOR) && !arch_has_dev_port())
continue;
+ if ((minor == DEVMEM_MINOR) && devmem_init_inode() != 0)
+ continue;
device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
NULL, devlist[minor].name);
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index a9b9170b5dd2..6c3eca90cbc4 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -301,5 +301,11 @@ struct resource *devm_request_free_mem_region(struct device *dev,
struct resource *request_free_mem_region(struct resource *base,
unsigned long size, const char *name);
+#ifdef CONFIG_IO_STRICT_DEVMEM
+void revoke_devmem(struct resource *res);
+#else
+static inline void revoke_devmem(struct resource *res) { };
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* _LINUX_IOPORT_H */
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index d78064007b17..f3956fc11de6 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -94,6 +94,7 @@
#define BALLOON_KVM_MAGIC 0x13661366
#define ZSMALLOC_MAGIC 0x58295829
#define DMA_BUF_MAGIC 0x444d4142 /* "DMAB" */
+#define DEVMEM_MAGIC 0x454d444d /* "DMEM" */
#define Z3FOLD_MAGIC 0x33
#define PPC_CMM_MAGIC 0xc7571590
diff --git a/kernel/resource.c b/kernel/resource.c
index 76036a41143b..841737bbda9e 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1126,6 +1126,7 @@ struct resource * __request_region(struct resource *parent,
{
DECLARE_WAITQUEUE(wait, current);
struct resource *res = alloc_resource(GFP_KERNEL);
+ struct resource *orig_parent = parent;
if (!res)
return NULL;
@@ -1176,6 +1177,10 @@ struct resource * __request_region(struct resource *parent,
break;
}
write_unlock(&resource_lock);
+
+ if (res && orig_parent == &iomem_resource)
+ revoke_devmem(res);
+
return res;
}
EXPORT_SYMBOL(__request_region);
2 years, 1 month
[PATCH] nvdimm: cleanup resources when the initialization fails
by Wu Bo
From: Wu Bo <wubo40(a)huawei.com>
When the initialization fails, add the cleanup resources
in pmem_attach_disk() function
Signed-off-by: Wu Bo <wubo40(a)huawei.com>
---
drivers/nvdimm/pmem.c | 44 +++++++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 13 deletions(-)
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 2df6994..f235a59 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -383,7 +383,7 @@ static int pmem_attach_disk(struct device *dev,
struct device *gendev;
struct gendisk *disk;
void *addr;
- int rc;
+ int rc = -ENOMEM;
unsigned long flags = 0UL;
pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
@@ -392,14 +392,14 @@ static int pmem_attach_disk(struct device *dev,
rc = devm_namespace_enable(dev, ndns, nd_info_block_reserve());
if (rc)
- return rc;
+ goto out_free_pmem;
/* while nsio_rw_bytes is active, parse a pfn info block if
present */
if (is_nd_pfn(dev)) {
nd_pfn = to_nd_pfn(dev);
rc = nvdimm_setup_pfn(nd_pfn, &pmem->pgmap);
if (rc)
- return rc;
+ goto out_free_pmem;
}
/* we're attaching a block device, disable raw namespace access */
@@ -417,12 +417,13 @@ static int pmem_attach_disk(struct device *dev,
if (!devm_request_mem_region(dev, res->start, resource_size(res),
dev_name(&ndns->dev))) {
dev_warn(dev, "could not reserve region %pR\n", res);
- return -EBUSY;
+ rc = -EBUSY;
+ goto out_free_pmem;
}
q = blk_alloc_queue(pmem_make_request, dev_to_node(dev));
if (!q)
- return -ENOMEM;
+ goto out_realease_mem_region;
pmem->pfn_flags = PFN_DEV;
pmem->pgmap.ref = &q->q_usage_counter;
@@ -447,14 +448,16 @@ static int pmem_attach_disk(struct device *dev,
} else {
if (devm_add_action_or_reset(dev, pmem_release_queue,
&pmem->pgmap))
- return -ENOMEM;
+ goto out_cleanup_queue;
addr = devm_memremap(dev, pmem->phys_addr,
pmem->size, ARCH_MEMREMAP_PMEM);
memcpy(&bb_res, &nsio->res, sizeof(bb_res));
}
- if (IS_ERR(addr))
- return PTR_ERR(addr);
+ if (IS_ERR(addr)) {
+ rc = PTR_ERR(addr);
+ goto out_cleanup_queue;
+ }
pmem->virt_addr = addr;
blk_queue_write_cache(q, true, fua);
@@ -468,7 +471,7 @@ static int pmem_attach_disk(struct device *dev,
disk = alloc_disk_node(0, nid);
if (!disk)
- return -ENOMEM;
+ goto out_cleanup_queue;
pmem->disk = disk;
disk->fops = &pmem_fops;
@@ -479,7 +482,7 @@ static int pmem_attach_disk(struct device *dev,
set_capacity(disk, (pmem->size - pmem->pfn_pad - pmem->data_offset)
/ 512);
if (devm_init_badblocks(dev, &pmem->bb))
- return -ENOMEM;
+ goto out_put_disk;
nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res);
disk->bb = &pmem->bb;
@@ -487,8 +490,8 @@ static int pmem_attach_disk(struct device *dev,
flags = DAXDEV_F_SYNC;
dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops, flags);
if (IS_ERR(dax_dev)) {
- put_disk(disk);
- return PTR_ERR(dax_dev);
+ rc = PTR_ERR(dax_dev);
+ goto out_badblock_exit;
}
dax_write_cache(dax_dev, nvdimm_has_cache(nd_region));
pmem->dax_dev = dax_dev;
@@ -497,7 +500,7 @@ static int pmem_attach_disk(struct device *dev,
device_add_disk(dev, disk, NULL);
if (devm_add_action_or_reset(dev, pmem_release_disk, pmem))
- return -ENOMEM;
+ goto out_free_dax;
revalidate_disk(disk);
@@ -507,6 +510,21 @@ static int pmem_attach_disk(struct device *dev,
dev_warn(dev, "'badblocks' notification disabled\n");
return 0;
+
+out_free_dax:
+ del_gendisk(disk);
+ put_dax(dax_dev);
+out_badblock_exit:
+ badblocks_exit(&pmem->bb);
+out_put_disk:
+ put_disk(disk);
+out_cleanup_queue:
+ blk_cleanup_queue(q);
+out_realease_mem_region:
+ devm_release_mem_region(dev, res->start, resource_size(res));
+out_free_pmem:
+ devm_kfree(dev, pmem);
+ return rc;
}
static int nd_pmem_probe(struct device *dev)
--
1.8.3.1
2 years, 1 month
[PATCH] libnvdimm/security: make __nvdimm_security_overwrite_query() static
by Jason Yan
Fix the following sparse warning:
drivers/nvdimm/security.c:416:6: warning: symbol
'__nvdimm_security_overwrite_query' was not declared. Should it be
static?
Reported-by: Hulk Robot <hulkci(a)huawei.com>
Signed-off-by: Jason Yan <yanaijie(a)huawei.com>
---
drivers/nvdimm/security.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c
index 89b85970912d..11fb5ada70ad 100644
--- a/drivers/nvdimm/security.c
+++ b/drivers/nvdimm/security.c
@@ -413,7 +413,7 @@ static int security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
return rc;
}
-void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm)
+static void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm)
{
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev);
int rc;
--
2.17.2
2 years, 1 month
[GIT PULL] libnvdimm for v5.7
by Dan Williams
Hi Linus, please pull from:
git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
tags/libnvdimm-for-5.7
...to receive the libnvdimm and dax update for this cycle. There were
multiple touches outside of drivers/nvdimm/ this round to add cross
arch compatibility to the devm_memremap_pages() interface, enhance
numa information for persistent memory ranges, and add a
zero_page_range() dax operation. This cycle I switched from the
patchwork api to Konstantin's b4 script for collecting tags (from x86,
PowerPC, filesystem, and device-mapper folks), and everything looks to
have gone ok there. This has all appeared in -next with no reported
issues.
Given the current environment where one might need to step away on
short notice I thought it would be a good idea to highlight to you and
others a backup maintainer for libnvdimm. Vishal, has agreed to step
in if circumstances make me non-responsive for multiple days. Not
expecting anything, just being proactive.
---
The following changes since commit 11a48a5a18c63fd7621bb050228cebf13566e4d8:
Linux 5.6-rc2 (2020-02-16 13:16:59 -0800)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
tags/libnvdimm-for-5.7
for you to fetch changes up to f6d2b802f80d0ca89ee1f51c1781b3f79cdb25d5:
Merge branch 'for-5.7/libnvdimm' into libnvdimm-for-next (2020-04-02
19:55:17 -0700)
----------------------------------------------------------------
libnvdimm for 5.7
- Add support for region alignment configuration and enforcement to
fix compatibility across architectures and PowerPC page size
configurations.
- Introduce 'zero_page_range' as a dax operation. This facilitates
filesystem-dax operation without a block-device.
- Introduce phys_to_target_node() to facilitate drivers that want to
know resulting numa node if a given reserved address range was
onlined.
- Advertise a persistence-domain for of_pmem and papr_scm. The
persistence domain indicates where cpu-store cycles need to reach in
the platform-memory subsystem before the platform will consider them
power-fail protected.
- Promote numa_map_to_online_node() to a cross-kernel generic facility.
- Save x86 numa information to allow for node-id lookups for reserved
memory ranges, deploy that capability for the e820-pmem driver.
- Pick up some miscellaneous minor fixes, that missed v5.6-final,
including a some smatch reports in the ioctl path and some unit test
compilation fixups.
- Fixup some flexible-array declarations.
----------------------------------------------------------------
Aneesh Kumar K.V (1):
libnvdimm: Update persistence domain value for of_pmem and papr_scm device
Dan Carpenter (2):
acpi/nfit: improve bounds checking for 'func'
libnvdimm: Out of bounds read in __nd_ioctl()
Dan Williams (15):
ACPI: NUMA: Up-level "map to online node" functionality
mm/numa: Skip NUMA_NO_NODE and online nodes in numa_map_to_online_node()
powerpc/papr_scm: Switch to numa_map_to_online_node()
x86/mm: Introduce CONFIG_NUMA_KEEP_MEMINFO
x86/NUMA: Provide a range-to-target_node lookup facility
libnvdimm/e820: Retrieve and populate correct 'target_node' info
mm/memremap_pages: Kill unused __devm_memremap_pages()
mm/memremap_pages: Introduce memremap_compat_align()
libnvdimm/pfn: Prevent raw mode fallback if pfn-infoblock valid
libnvdimm/namespace: Enforce memremap_compat_align()
libnvdimm/region: Introduce NDD_LABELING
libnvdimm/region: Introduce an 'align' attribute
Merge branch 'for-5.6/libnvdimm-fixes' into libnvdimm-for-next
Merge branch 'for-5.7/numa' into libnvdimm-for-next
Merge branch 'for-5.7/libnvdimm' into libnvdimm-for-next
Gustavo A. R. Silva (3):
ACPI: NFIT: Replace zero-length array with flexible-array member
libnvdimm/label: Replace zero-length array with flexible-array member
libnvdimm/region: Replace zero-length array with flexible-array member
Jan Kara (1):
tools/testing/nvdimm: Fix compilation failure without
CONFIG_DEV_DAX_PMEM_COMPAT
Lukas Bulwahn (1):
MAINTAINERS: clarify maintenance of nvdimm testing tool
Santosh Sivaraj (1):
tools/test/nvdimm: Fix out of tree build
Vivek Goyal (7):
pmem: Add functions for reading/writing page to/from pmem
dax, pmem: Add a dax operation zero_page_range
s390,dcssblk,dax: Add dax zero_page_range operation to dcssblk driver
dm,dax: Add dax zero_page_range operation
dax: Use new dax zero page method for zeroing a page
dax,iomap: Add helper dax_iomap_zero() to zero a range
dax: Move mandatory ->zero_page_range() check in alloc_dax()
YueHaibing (1):
libnvdimm/region: Fix build error
MAINTAINERS | 1 +
arch/powerpc/Kconfig | 1 +
arch/powerpc/mm/ioremap.c | 21 +++++
arch/powerpc/platforms/pseries/papr_scm.c | 27 ++-----
arch/x86/Kconfig | 1 +
arch/x86/mm/numa.c | 67 +++++++++++----
drivers/acpi/nfit/core.c | 14 ++--
drivers/acpi/nfit/nfit.h | 13 +--
drivers/acpi/numa/srat.c | 41 ----------
drivers/dax/bus.c | 4 +-
drivers/dax/super.c | 28 ++++++-
drivers/md/dm-linear.c | 18 +++++
drivers/md/dm-log-writes.c | 17 ++++
drivers/md/dm-stripe.c | 23 ++++++
drivers/md/dm.c | 32 +++++++-
drivers/nvdimm/bus.c | 6 +-
drivers/nvdimm/dimm.c | 2 +-
drivers/nvdimm/dimm_devs.c | 95 +++++++++++++++++-----
drivers/nvdimm/e820.c | 18 +----
drivers/nvdimm/label.h | 2 +-
drivers/nvdimm/namespace_devs.c | 28 ++++++-
drivers/nvdimm/nd.h | 7 +-
drivers/nvdimm/of_pmem.c | 4 +-
drivers/nvdimm/pfn.h | 12 +++
drivers/nvdimm/pfn_devs.c | 40 +++++++--
drivers/nvdimm/pmem.c | 101 ++++++++++++++---------
drivers/nvdimm/region_devs.c | 130 ++++++++++++++++++++++++++----
drivers/s390/block/dcssblk.c | 20 ++++-
fs/dax.c | 59 ++++++--------
fs/iomap/buffered-io.c | 9 +--
include/linux/acpi.h | 23 +++++-
include/linux/dax.h | 21 ++---
include/linux/device-mapper.h | 3 +
include/linux/io.h | 2 -
include/linux/libnvdimm.h | 2 +
include/linux/memremap.h | 8 ++
include/linux/mmzone.h | 1 +
include/linux/numa.h | 30 ++++++-
lib/Kconfig | 3 +
mm/Kconfig | 5 ++
mm/mempolicy.c | 26 ++++++
mm/memremap.c | 23 ++++++
tools/testing/nvdimm/Kbuild | 4 +-
tools/testing/nvdimm/test/Kbuild | 4 +-
tools/testing/nvdimm/test/nfit.c | 2 +
45 files changed, 737 insertions(+), 261 deletions(-)
2 years, 1 month
[ndctl PATCH v2] monitor: Add epoll timeout for forcing a full dimm health check
by Vaibhav Jain
This patch adds a new command argument to the 'monitor' command namely
'--poll' that triggers a call to notify_dimm_event() at regular
intervals forcing a periodic check of status/events for the nvdimm
objects i.e. bus, dimms, regions or namespaces.
This behavior is useful for dimms that do not support event notifications
in case the health status of an nvdimm changes. This is especially
true in case of PAPR-SCM nvdimms as the PHYP hyper-visor doesn't provide
any notifications to the guest kernel on a change in nvdimm health
status. In such case periodic polling of the is the only way to track
the health of a nvdimm.
The patch updates monitor_event() adding a timeout value to
epoll_wait() call. Also to prevent the possibility of a single dimm
generating enough events thereby preventing check for status of other
nvdimms objects, a 'fullpoll_ts' time-stamp is added to keep track of
when full check of all nvdimms objects happened. If after epoll_wait()
returns 'fullpoll_ts' time-stamp indicates last a full status check
for nvdimm objects happened beyond 'poll-interval' seconds then a full
status check is enforced.
Cc: QI Fuli <qi.fuli(a)jp.fujitsu.com>
Cc: Dan Williams <dan.j.williams(a)intel.com>
Cc: Vishal Verma <vishal.l.verma(a)intel.com>
Signed-off-by: Vaibhav Jain <vaibhav(a)linux.ibm.com>
---
Changelog:
v1..v2
* Changed the '--check-interval' arg to '--poll' [Dan Williams]
* Update the documentation and patch description of the '--poll' arg
to accuratly reflect that it can report status/events for
all nvdimm objects. [Dan Williams]
---
Documentation/ndctl/ndctl-monitor.txt | 4 ++++
ndctl/monitor.c | 31 ++++++++++++++++++++++++---
2 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/Documentation/ndctl/ndctl-monitor.txt b/Documentation/ndctl/ndctl-monitor.txt
index 2239f047266d..0b6bb5c416c6 100644
--- a/Documentation/ndctl/ndctl-monitor.txt
+++ b/Documentation/ndctl/ndctl-monitor.txt
@@ -108,6 +108,10 @@ will not work if "--daemon" is specified.
The monitor will attempt to enable the alarm control bits for all
specified events.
+-p::
+--poll=::
+ Poll and report status/event every <n> seconds.
+
-u::
--human::
Output monitor notification as human friendly json format instead
diff --git a/ndctl/monitor.c b/ndctl/monitor.c
index 1755b87a5eeb..4e9b2236ff3c 100644
--- a/ndctl/monitor.c
+++ b/ndctl/monitor.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <json-c/json.h>
#include <libgen.h>
+#include <time.h>
#include <dirent.h>
#include <util/json.h>
#include <util/filter.h>
@@ -33,6 +34,7 @@ static struct monitor {
bool daemon;
bool human;
bool verbose;
+ unsigned int poll_timeout;
unsigned int event_flags;
struct log_ctx ctx;
} monitor;
@@ -322,9 +324,14 @@ static int monitor_event(struct ndctl_ctx *ctx,
struct monitor_filter_arg *mfa)
{
struct epoll_event ev, *events;
- int nfds, epollfd, i, rc = 0;
+ int nfds, epollfd, i, rc = 0, polltimeout = -1;
struct monitor_dimm *mdimm;
char buf;
+ /* last time a full poll happened */
+ struct timespec fullpoll_ts, ts;
+
+ if (monitor.poll_timeout)
+ polltimeout = monitor.poll_timeout * 1000;
events = calloc(mfa->num_dimm, sizeof(struct epoll_event));
if (!events) {
@@ -354,14 +361,30 @@ static int monitor_event(struct ndctl_ctx *ctx,
}
}
+ clock_gettime(CLOCK_BOOTTIME, &fullpoll_ts);
while (1) {
did_fail = 0;
- nfds = epoll_wait(epollfd, events, mfa->num_dimm, -1);
- if (nfds <= 0 && errno != EINTR) {
+ nfds = epoll_wait(epollfd, events, mfa->num_dimm, polltimeout);
+ if (nfds < 0 && errno != EINTR) {
err(&monitor, "epoll_wait error: (%s)\n", strerror(errno));
rc = -errno;
goto out;
}
+
+ /* If needed force a full poll of dimm health */
+ clock_gettime(CLOCK_BOOTTIME, &ts);
+ if ((fullpoll_ts.tv_sec - ts.tv_sec) > monitor.poll_timeout) {
+ nfds = 0;
+ dbg(&monitor, "forcing a full poll\n");
+ }
+
+ /* If we timed out then fill events array with all dimms */
+ if (nfds == 0) {
+ list_for_each(&mfa->dimms, mdimm, list)
+ events[nfds++].data.ptr = mdimm;
+ fullpoll_ts = ts;
+ }
+
for (i = 0; i < nfds; i++) {
mdimm = events[i].data.ptr;
if (util_dimm_event_filter(mdimm, monitor.event_flags)) {
@@ -570,6 +593,8 @@ int cmd_monitor(int argc, const char **argv, struct ndctl_ctx *ctx)
"use human friendly output formats"),
OPT_BOOLEAN('v', "verbose", &monitor.verbose,
"emit extra debug messages to log"),
+ OPT_UINTEGER('p', "poll", &monitor.poll_timeout,
+ "poll and report events/status every <n> seconds"),
OPT_END(),
};
const char * const u[] = {
--
2.25.2
2 years, 1 month
[PATCH] ndctl/namespace: skip zero namespaces when processing
by Michal Suchanek
Hello,
this is a fix for github issue #41. I tested on system with vpmem with
ndctl 64.1 that the issue is fixed. master builds with the fix applied.
8<-------------------------------------------------------------------->8
The kernel always creates zero length namespace with uuid 0 in each
region.
When processing all namespaces the user gets confusing errors from ndctl
trying to process this namespace. Skip it.
The user can still specify the namespace by name directly in case
processing it is desirable.
Fixes: #41
Signed-off-by: Michal Suchanek <msuchanek(a)suse.de>
---
ndctl/namespace.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/ndctl/namespace.c b/ndctl/namespace.c
index 0550580707e8..6f4a4b5b8883 100644
--- a/ndctl/namespace.c
+++ b/ndctl/namespace.c
@@ -2128,9 +2128,19 @@ static int do_xaction_namespace(const char *namespace,
ndctl_namespace_foreach_safe(region, ndns, _n) {
ndns_name = ndctl_namespace_get_devname(ndns);
- if (strcmp(namespace, "all") != 0
- && strcmp(namespace, ndns_name) != 0)
- continue;
+ if (strcmp(namespace, "all") == 0) {
+ static const uuid_t zero_uuid;
+ uuid_t uuid;
+
+ ndctl_namespace_get_uuid(ndns, uuid);
+ if (!ndctl_namespace_get_size(ndns) &&
+ !memcmp(uuid, zero_uuid, sizeof(uuid_t)))
+ continue;
+ } else {
+ if (strcmp(namespace, ndns_name) != 0)
+ continue;
+ }
+
switch (action) {
case ACTION_DISABLE:
rc = ndctl_namespace_disable_safe(ndns);
--
2.23.0
2 years, 1 month
[PATCH] libnvdimm: Validate command family indices
by Dan Williams
The ND_CMD_CALL format allows for a general passthrough of whitelisted
commands targeting a given command set. However there is no validation
of the family index relative to what the bus supports.
- Update the NFIT bus implementation (the only one that supports
ND_CMD_CALL passthrough) to also whitelist the valid set of command
family indices.
- Update the generic __nd_ioctl() path to validate that field on behalf
of all implementations.
Fixes: 31eca76ba2fc ("nfit, libnvdimm: limited/whitelisted dimm command marshaling mechanism")
Cc: <stable(a)vger.kernel.org>
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
drivers/acpi/nfit/core.c | 11 +++++++++--
drivers/acpi/nfit/nfit.h | 1 -
drivers/nvdimm/bus.c | 16 ++++++++++++++++
include/linux/libnvdimm.h | 2 ++
include/uapi/linux/ndctl.h | 4 ++++
5 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index d0090f71585c..bcf5af803941 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -1823,6 +1823,7 @@ static void populate_shutdown_status(struct nfit_mem *nfit_mem)
static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
struct nfit_mem *nfit_mem, u32 device_handle)
{
+ struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
struct acpi_device *adev, *adev_dimm;
struct device *dev = acpi_desc->dev;
unsigned long dsm_mask, label_mask;
@@ -1834,6 +1835,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
/* nfit test assumes 1:1 relationship between commands and dsms */
nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en;
nfit_mem->family = NVDIMM_FAMILY_INTEL;
+ set_bit(NVDIMM_FAMILY_INTEL, &nd_desc->dimm_family_mask);
if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID)
sprintf(nfit_mem->id, "%04x-%02x-%04x-%08x",
@@ -1886,10 +1888,13 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
* Note, that checking for function0 (bit0) tells us if any commands
* are reachable through this GUID.
*/
+ clear_bit(NVDIMM_FAMILY_INTEL, &nd_desc->dimm_family_mask);
for (i = 0; i <= NVDIMM_FAMILY_MAX; i++)
- if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))
+ if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1)) {
+ set_bit(i, &nd_desc->dimm_family_mask);
if (family < 0 || i == default_dsm_family)
family = i;
+ }
/* limit the supported commands to those that are publicly documented */
nfit_mem->family = family;
@@ -2151,6 +2156,9 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;
nd_desc->bus_dsm_mask = acpi_desc->bus_nfit_cmd_force_en;
+ set_bit(ND_CMD_CALL, &nd_desc->cmd_mask);
+ set_bit(NVDIMM_BUS_FAMILY_NFIT, &nd_desc->bus_family_mask);
+
adev = to_acpi_dev(acpi_desc);
if (!adev)
return;
@@ -2158,7 +2166,6 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)
if (acpi_check_dsm(adev->handle, guid, 1, 1ULL << i))
set_bit(i, &nd_desc->cmd_mask);
- set_bit(ND_CMD_CALL, &nd_desc->cmd_mask);
dsm_mask =
(1 << ND_CMD_ARS_CAP) |
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
index b317f4043705..5f5f8ce030e7 100644
--- a/drivers/acpi/nfit/nfit.h
+++ b/drivers/acpi/nfit/nfit.h
@@ -33,7 +33,6 @@
| ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
| ACPI_NFIT_MEM_NOT_ARMED | ACPI_NFIT_MEM_MAP_FAILED)
-#define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_HYPERV
#define NVDIMM_CMD_MAX 31
#define NVDIMM_STANDARD_CMDMASK \
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 09087c38fabd..955265656b96 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -1037,9 +1037,25 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
dimm_name = "bus";
}
+ /* Validate command family support against bus declared support */
if (cmd == ND_CMD_CALL) {
+ unsigned long *mask;
+
if (copy_from_user(&pkg, p, sizeof(pkg)))
return -EFAULT;
+
+ if (nvdimm) {
+ if (pkg.nd_family > NVDIMM_FAMILY_MAX)
+ return -EINVAL;
+ mask = &nd_desc->dimm_family_mask;
+ } else {
+ if (pkg.nd_family > NVDIMM_BUS_FAMILY_MAX)
+ return -EINVAL;
+ mask = &nd_desc->bus_family_mask;
+ }
+
+ if (!test_bit(pkg.nd_family, mask))
+ return -EINVAL;
}
if (!desc ||
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 9df091bd30ba..b41857f43883 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -76,6 +76,8 @@ struct nvdimm_bus_descriptor {
const struct attribute_group **attr_groups;
unsigned long bus_dsm_mask;
unsigned long cmd_mask;
+ unsigned long dimm_family_mask;
+ unsigned long bus_family_mask;
struct module *module;
char *provider_name;
struct device_node *of_node;
diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h
index de5d90212409..e28763c234e2 100644
--- a/include/uapi/linux/ndctl.h
+++ b/include/uapi/linux/ndctl.h
@@ -244,6 +244,10 @@ struct nd_cmd_pkg {
#define NVDIMM_FAMILY_HPE2 2
#define NVDIMM_FAMILY_MSFT 3
#define NVDIMM_FAMILY_HYPERV 4
+#define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_HYPERV
+
+#define NVDIMM_BUS_FAMILY_NFIT 0
+#define NVDIMM_BUS_FAMILY_MAX NVDIMM_BUS_FAMILY_NFIT
#define ND_IOCTL_CALL _IOWR(ND_IOCTL, ND_CMD_CALL,\
struct nd_cmd_pkg)
2 years, 1 month