[patch] dax: fix PMD faults on zero-length files
by Jeff Moyer
PMD faults on a zero length file on a file system mounted with -o dax
will not generate SIGBUS as expected.
fd = open(...O_TRUNC);
addr = mmap(NULL, 2*1024*1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
*addr = 'a';
<expect SIGBUS>
The problem is this code in dax_iomap_pmd_fault:
max_pgoff = (i_size_read(inode) - 1) >> PAGE_SHIFT;
If the inode size is zero, we end up with a max_pgoff that is way larger
than 0. :) Fix it by using DIV_ROUND_UP, as is done elsewhere in the
kernel.
I tested this with some simple test code that ensured that SIGBUS was
received where expected.
Signed-off-by: Jeff Moyer <jmoyer(a)redhat.com>
diff --git a/fs/dax.c b/fs/dax.c
index f001d8c7..191306c 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1327,7 +1327,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf,
* this is a reliable test.
*/
pgoff = linear_page_index(vma, pmd_addr);
- max_pgoff = (i_size_read(inode) - 1) >> PAGE_SHIFT;
+ max_pgoff = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
trace_dax_pmd_fault(inode, vmf, max_pgoff, 0);
@@ -1351,13 +1351,13 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf,
if ((pmd_addr + PMD_SIZE) > vma->vm_end)
goto fallback;
- if (pgoff > max_pgoff) {
+ if (pgoff >= max_pgoff) {
result = VM_FAULT_SIGBUS;
goto out;
}
/* If the PMD would extend beyond the file size */
- if ((pgoff | PG_PMD_COLOUR) > max_pgoff)
+ if ((pgoff | PG_PMD_COLOUR) >= max_pgoff)
goto fallback;
/*
4 years, 7 months
[PATCH v6 0/8] libnvdimm: add DMA supported blk-mq pmem driver
by Dave Jiang
v6:
- Put all common code for pmem drivers in pmem_core per Dan's suggestion.
- Added support code to get number of available DMA chans
- Fixed up Kconfig so that when pmem is built into the kernel, pmem_dma won't
show up.
v5:
- Added support to report descriptor transfer capability limit from dmaengine.
- Fixed up scatterlist support for dma_unmap_data per Dan's comments.
- Made the driver a separate pmem blk driver per Christoph's suggestion
and also fixed up all the issues pointed out by Christoph.
- Added pmem badblock checking/handling per Robert and also made DMA op to
be used by all buffer sizes.
v4:
- Addressed kbuild test bot issues. Passed kbuild test bot, 179 configs.
v3:
- Added patch to rename DMA_SG to DMA_SG_SG to make it explicit
- Added DMA_MEMCPY_SG transaction type to dmaengine
- Misc patch to add verification of DMA_MEMSET_SG that was missing
- Addressed all nd_pmem driver comments from Ross.
v2:
- Make dma_prep_memcpy_* into one function per Dan.
- Addressed various comments from Ross with code formatting and etc.
- Replaced open code with offset_in_page() macro per Johannes.
The following series implements a blk-mq pmem driver and
also adds infrastructure code to ioatdma and dmaengine in order to
support copying to and from scatterlist in order to process block
requests provided by blk-mq. The usage of DMA engines available on certain
platforms allow us to drastically reduce CPU utilization and at the same time
maintain performance that is good enough. Experimentations have been done on
DRAM backed pmem block device that showed the utilization of DMA engine is
beneficial. By default nd_pmem.ko will be loaded. This can be overridden
through module blacklisting in order to load nd_pmem_dma.ko.
---
Dave Jiang (8):
dmaengine: ioatdma: revert 7618d035 to allow sharing of DMA channels
dmaengine: Add DMA_MEMCPY_SG transaction op
dmaengine: add verification of DMA_MEMSET_SG in dmaengine
dmaengine: ioatdma: dma_prep_memcpy_sg support
dmaengine: add function to provide per descriptor xfercap for dma engine
dmaengine: add SG support to dmaengine_unmap
dmaengine: provide number of available channels
libnvdimm: Add blk-mq pmem driver
Documentation/dmaengine/provider.txt | 3
drivers/dma/dmaengine.c | 76 ++++
drivers/dma/ioat/dma.h | 4
drivers/dma/ioat/init.c | 6
drivers/dma/ioat/prep.c | 57 +++
drivers/nvdimm/Kconfig | 21 +
drivers/nvdimm/Makefile | 6
drivers/nvdimm/pmem.c | 264 ---------------
drivers/nvdimm/pmem.h | 48 +++
drivers/nvdimm/pmem_core.c | 298 +++++++++++++++++
drivers/nvdimm/pmem_dma.c | 606 ++++++++++++++++++++++++++++++++++
include/linux/dmaengine.h | 49 +++
12 files changed, 1170 insertions(+), 268 deletions(-)
create mode 100644 drivers/nvdimm/pmem_core.c
create mode 100644 drivers/nvdimm/pmem_dma.c
--
Signature
4 years, 7 months
[PATCH] fs, dax: unify IOMAP_F_DIRTY read vs write handling policy in the dax core
by Dan Williams
While reviewing whether MAP_SYNC should strengthen its current guarantee
of syncing writes from the initiating process to also include
third-party readers observing dirty metadata, Dave pointed out that the
check of IOMAP_WRITE is misplaced.
The policy of what to with IOMAP_F_DIRTY should be separated from the
generic filesystem mechanism of reporting dirty metadata. Move this
policy to the fs-dax core to simplify the per-filesystem iomap handlers,
and further centralize code that implements the MAP_SYNC policy. This
otherwise should not change behavior, it just makes it easier to change
behavior in the future.
Cc: Jan Kara <jack(a)suse.cz>
Cc: Christoph Hellwig <hch(a)lst.de>
Cc: Darrick J. Wong <darrick.wong(a)oracle.com>
Cc: Ross Zwisler <ross.zwisler(a)linux.intel.com>
Reported-by: Dave Chinner <david(a)fromorbit.com>
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
This is an additional cleanup I want to include in the 4.15 merge
request for the MAP_SYNC feature. Please review, I'm looking to send the
pull request towards the end of the week.
fs/dax.c | 15 +++++++++++++--
fs/ext4/inode.c | 2 +-
fs/xfs/xfs_iomap.c | 6 +++---
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/fs/dax.c b/fs/dax.c
index 78233c716757..27ba300660ff 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1079,6 +1079,17 @@ static int dax_fault_return(int error)
return VM_FAULT_SIGBUS;
}
+/*
+ * MAP_SYNC on a dax mapping guarantees dirty metadata is
+ * flushed on write-faults (non-cow), but not read-faults.
+ */
+static bool dax_fault_is_synchronous(unsigned long flags,
+ struct vm_area_struct *vma, struct iomap *iomap)
+{
+ return (flags & IOMAP_WRITE) && (vma->vm_flags & VM_SYNC)
+ && (iomap->flags & IOMAP_F_DIRTY);
+}
+
static int dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp,
const struct iomap_ops *ops)
{
@@ -1170,7 +1181,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp,
goto finish_iomap;
}
- sync = (vma->vm_flags & VM_SYNC) && (iomap.flags & IOMAP_F_DIRTY);
+ sync = dax_fault_is_synchronous(flags, vma, &iomap);
switch (iomap.type) {
case IOMAP_MAPPED:
@@ -1390,7 +1401,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp,
if (iomap.offset + iomap.length < pos + PMD_SIZE)
goto finish_iomap;
- sync = (vma->vm_flags & VM_SYNC) && (iomap.flags & IOMAP_F_DIRTY);
+ sync = dax_fault_is_synchronous(iomap_flags, vma, &iomap);
switch (iomap.type) {
case IOMAP_MAPPED:
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 13a198924a0f..ee4d907a4251 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3479,7 +3479,7 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
}
iomap->flags = 0;
- if ((flags & IOMAP_WRITE) && ext4_inode_datasync_dirty(inode))
+ if (ext4_inode_datasync_dirty(inode))
iomap->flags |= IOMAP_F_DIRTY;
iomap->bdev = inode->i_sb->s_bdev;
iomap->dax_dev = sbi->s_daxdev;
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index b43be199fbdf..888b60189983 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -1087,9 +1087,9 @@ xfs_file_iomap_begin(
trace_xfs_iomap_found(ip, offset, length, 0, &imap);
}
- if ((flags & IOMAP_WRITE) && xfs_ipincount(ip) &&
- (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP))
- iomap->flags |= IOMAP_F_DIRTY;
+ if (xfs_ipincount(ip))
+ if (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP)
+ iomap->flags |= IOMAP_F_DIRTY;
xfs_bmbt_to_iomap(ip, iomap, &imap);
4 years, 7 months
[RFC patch v2 0/7] ndctl: nvdimmd: notify/monitor the feathers of over threshold event
by Qi, Fuli
Hi, here is my second version of nvdimm daemon, It would be appreciated
if you
could check it.
Change log since v1:
- Adding a config file(/etc/nvdimmd/nvdimmd.conf)
- Using struct log_ctx instead of syslog()
- Using log_syslog() to save the notify messages to syslog
- Using log_file() to save the notify messages to special file
- Adding LOG_NOTICE level into log_priority
- Using automake instead of Makefile
- Adding a new util file(nvdimmd/util.c) including helper functions needed
for nvdimm daemon.
- Adding nvdimmd_test program
---
This is a patch set of nvdimmd, a tiny daemon to monitor the features of
over
threshold events. When an over thershold event fires, nvdimmd will
output the
notification including dimm health status to syslog or a special file to
users' configuration. Users can choose the output format to be
structured json or text.
Here are out put samples.
- json format:
2017/11/10 11:15:03 [28065] log_notify: nvdimm dimm over threshold notify
{
"dev":"nmem1",
"id":"cdab-0a-07e0-feffffff",
"handle":1,
"phys_id":1,
"health":{
"health_state":"non-critical",
"temperature_celsius":23,
"spares_percentage":75,
"alarm_temperature":true,
"alarm_spares":true,
"temperature_threshold":40,
"spares_threshold":5,
"life_used_percentage":5,
"shutdown_state":"clean"
}
}
- text format:
2017/11/10 16:21:53 [12479] log_notify: nvdimm dimm over threshold notify
dev: nmem1
health_state: non-critical
spares_percentage: 75
TODO list:
- The dimms to monitor should be filtered by namespace and region
- Add more information into the notify message
- Make nvdimmd_test an ndctl command or an option of ndctl inject-error
Makefile.am | 2 +-
configure.ac | 1 +
nvdimmd/Makefile.am | 47 ++++++++
nvdimmd/libnvdimmd.c | 315
++++++++++++++++++++++++++++++++++++++++++++++++
nvdimmd/libnvdimmd.h | 53 ++++++++
nvdimmd/nvdimmd | 228 +++++++++++++++++++++++++++++++++++
nvdimmd/nvdimmd.c | 112 +++++++++++++++++
nvdimmd/nvdimmd.conf | 25 ++++
nvdimmd/nvdimmd.service | 7 ++
nvdimmd/nvdimmd_test.c | 142 ++++++++++++++++++++++
nvdimmd/util.c | 80 ++++++++++++
nvdimmd/util.h | 33 +++++
util/log.c | 2 +
util/log.h | 3 +
14 files changed, 1049 insertions(+), 1 deletion(-)
4 years, 7 months
[PATCH v3 1/2] ndctl: daxctl: fix mmap size
by Dave Jiang
The size for mmap needs to be aligned to the region alignment. Fix the
mapping size so that it satisfy the alignment requirement.
Signed-off-by: Dave Jiang <dave.jiang(a)intel.com>
---
daxctl/io.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/daxctl/io.c b/daxctl/io.c
index 2f8cb4a..6e07b52 100644
--- a/daxctl/io.c
+++ b/daxctl/io.c
@@ -55,6 +55,7 @@ struct io_dev {
struct ndctl_region *region;
struct ndctl_dax *dax;
uint64_t size;
+ uint64_t mmap_size;
};
static struct {
@@ -83,6 +84,7 @@ static bool is_stdinout(struct io_dev *io_dev)
static int setup_device(struct io_dev *io_dev, size_t size)
{
int flags, rc;
+ uint64_t align;
if (is_stdinout(io_dev))
return 0;
@@ -104,8 +106,14 @@ static int setup_device(struct io_dev *io_dev, size_t size)
if (!io_dev->is_dax)
return 0;
+ align = ndctl_dax_get_align(io_dev->dax);
+ if (align == ULONG_MAX)
+ return -ERANGE;
+
+ io_dev->mmap_size = ALIGN(size, align);
flags = (io_dev->direction == IO_READ) ? PROT_READ : PROT_WRITE;
- io_dev->mmap = mmap(NULL, size, flags, MAP_SHARED, io_dev->fd, 0);
+ io_dev->mmap = mmap(NULL, io_dev->mmap_size, flags,
+ MAP_SHARED, io_dev->fd, 0);
if (io_dev->mmap == MAP_FAILED) {
rc = -errno;
perror("mmap");
@@ -501,6 +509,8 @@ static void cleanup(void)
for (i = 0; i < 2; i++) {
if (is_stdinout(&io.dev[i]))
continue;
+ if (io.dev[i].mmap_size)
+ munmap(io.dev[i].mmap, io.dev[i].mmap_size);
close(io.dev[i].fd);
}
}
4 years, 7 months
[PATCH v2 1/2] ndctl: daxctl: fix mmap size
by Dave Jiang
The size for mmap needs to be aligned to the region alignment. Fix the
mapping size so that it satisfy the alignment requirement.
Signed-off-by: Dave Jiang <dave.jiang(a)intel.com>
---
daxctl/io.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/daxctl/io.c b/daxctl/io.c
index 2f8cb4a..e739d0e 100644
--- a/daxctl/io.c
+++ b/daxctl/io.c
@@ -55,6 +55,7 @@ struct io_dev {
struct ndctl_region *region;
struct ndctl_dax *dax;
uint64_t size;
+ uint64_t mmap_size;
};
static struct {
@@ -83,6 +84,7 @@ static bool is_stdinout(struct io_dev *io_dev)
static int setup_device(struct io_dev *io_dev, size_t size)
{
int flags, rc;
+ unsigned long align;
if (is_stdinout(io_dev))
return 0;
@@ -104,8 +106,14 @@ static int setup_device(struct io_dev *io_dev, size_t size)
if (!io_dev->is_dax)
return 0;
+ align = ndctl_dax_get_align(io_dev->dax);
+ if (align == ULLONG_MAX)
+ return -ERANGE;
+
+ io_dev->mmap_size = ALIGN(size, align);
flags = (io_dev->direction == IO_READ) ? PROT_READ : PROT_WRITE;
- io_dev->mmap = mmap(NULL, size, flags, MAP_SHARED, io_dev->fd, 0);
+ io_dev->mmap = mmap(NULL, io_dev->mmap_size, flags,
+ MAP_SHARED, io_dev->fd, 0);
if (io_dev->mmap == MAP_FAILED) {
rc = -errno;
perror("mmap");
@@ -501,6 +509,8 @@ static void cleanup(void)
for (i = 0; i < 2; i++) {
if (is_stdinout(&io.dev[i]))
continue;
+ if (io.dev[i].mmap_size)
+ munmap(io.dev[i].mmap, io.dev[i].mmap_size);
close(io.dev[i].fd);
}
}
4 years, 7 months
[ndctl PATCH] libdaxctl: use the same uuid definition as libdaxctl
by Dan Williams
libdaxtl inadvertently included the uuid-devel version of the uuid.h
header rather than the libuuid header. Fix this up to avoid type
conflicts for applications that include both libdaxctl.h and libndctl.h.
Reported-by: Lukasz Plewa <lukasz.plewa(a)intel.com>
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
daxctl/libdaxctl.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
index 77f6a25d2e30..21bc376ce629 100644
--- a/daxctl/libdaxctl.h
+++ b/daxctl/libdaxctl.h
@@ -15,7 +15,12 @@
#include <stdarg.h>
#include <unistd.h>
-#include <uuid.h>
+
+#ifdef HAVE_LIBUUID
+#include <uuid/uuid.h>
+#else
+typedef unsigned char uuid_t[16];
+#endif
#ifdef __cplusplus
extern "C" {
4 years, 7 months
[PATCH 1/2] acpi, nfit: validate commands against the device type
by Dan Williams
Fix occasions in acpi_nfit_ctl where we check the command type without
validating whether we are parsing dimm vs bus level commands. Where the
command numbers alias between dimms and bus we can make the wrong
assumption just checking the raw command number. For example, with a
simple nfit_test mock up of the clear-error command we trigger the
following:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000094
IP: acpi_nfit_ctl+0x29b/0x930 [nfit]
[..]
Call Trace:
nfit_test_probe+0xb85/0xc09 [nfit_test]
platform_drv_probe+0x3b/0xa0
? platform_drv_probe+0x3b/0xa0
driver_probe_device+0x29c/0x450
? test_alloc+0x180/0x180 [nfit_test]
__driver_attach+0xe3/0xf0
? driver_probe_device+0x450/0x450
bus_for_each_dev+0x73/0xc0
driver_attach+0x1e/0x20
bus_add_driver+0x173/0x270
driver_register+0x60/0xe0
__platform_driver_register+0x36/0x40
nfit_test_init+0x2a1/0x1000 [nfit_test]
Fixes: 4b27db7e26cd ("acpi, nfit: add support for the _LSI, _LSR, and...")
Reported-by: Vishal Verma <vishal.l.verma(a)intel.com>
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
drivers/acpi/nfit/core.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 8043bfde7c63..ff2580e7611d 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -483,13 +483,14 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
min_t(u32, 256, in_buf.buffer.length), true);
/* call the BIOS, prefer the named methods over _DSM if available */
- if (cmd == ND_CMD_GET_CONFIG_SIZE && nfit_mem->has_lsi)
+ if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE && nfit_mem->has_lsi)
out_obj = acpi_label_info(handle);
- else if (cmd == ND_CMD_GET_CONFIG_DATA && nfit_mem->has_lsr) {
+ else if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && nfit_mem->has_lsr) {
struct nd_cmd_get_config_data_hdr *p = buf;
out_obj = acpi_label_read(handle, p->in_offset, p->in_length);
- } else if (cmd == ND_CMD_SET_CONFIG_DATA && nfit_mem->has_lsw) {
+ } else if (nvdimm && cmd == ND_CMD_SET_CONFIG_DATA
+ && nfit_mem->has_lsw) {
struct nd_cmd_set_config_hdr *p = buf;
out_obj = acpi_label_write(handle, p->in_offset, p->in_length,
@@ -497,7 +498,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
} else {
u8 revid;
- if (nfit_mem)
+ if (nvdimm)
revid = nfit_dsm_revid(nfit_mem->family, func);
else
revid = 1;
@@ -565,8 +566,10 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
* Set fw_status for all the commands with a known format to be
* later interpreted by xlat_status().
*/
- if (i >= 1 && ((cmd >= ND_CMD_ARS_CAP && cmd <= ND_CMD_CLEAR_ERROR)
- || (cmd >= ND_CMD_SMART && cmd <= ND_CMD_VENDOR)))
+ if (i >= 1 && ((!nvdimm && cmd >= ND_CMD_ARS_CAP
+ && cmd <= ND_CMD_CLEAR_ERROR)
+ || (nvdimm && cmd >= ND_CMD_SMART
+ && cmd <= ND_CMD_VENDOR)))
fw_status = *(u32 *) out_obj->buffer.pointer;
if (offset + in_buf.buffer.length < buf_len) {
4 years, 7 months
[PATCH] ndctl: daxctl: fix mmap size
by Dave Jiang
The size for mmap needs to be aligned to the region alignment. Add helper
funciton to determine the actual size to be mmap'd.
Signed-off-by: Dave Jiang <dave.jiang(a)intel.com>
---
daxctl/io.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/daxctl/io.c b/daxctl/io.c
index 2f8cb4a..97a4169 100644
--- a/daxctl/io.c
+++ b/daxctl/io.c
@@ -80,9 +80,26 @@ static bool is_stdinout(struct io_dev *io_dev)
io_dev->fd == STDOUT_FILENO) ? true : false;
}
+static int get_mmap_size(struct io_dev *io_dev, size_t size, size_t *map_size)
+{
+ unsigned long align;
+
+ align = ndctl_dax_get_align(io_dev->dax);
+ if (align == ULLONG_MAX)
+ return -ERANGE;
+
+ if (size <= align)
+ *map_size = align;
+ else
+ *map_size = (size / align) * align;
+
+ return 0;
+}
+
static int setup_device(struct io_dev *io_dev, size_t size)
{
int flags, rc;
+ size_t map_size;
if (is_stdinout(io_dev))
return 0;
@@ -104,8 +121,12 @@ static int setup_device(struct io_dev *io_dev, size_t size)
if (!io_dev->is_dax)
return 0;
+ rc = get_mmap_size(io_dev, size, &map_size);
+ if (rc < 0)
+ return rc;
+
flags = (io_dev->direction == IO_READ) ? PROT_READ : PROT_WRITE;
- io_dev->mmap = mmap(NULL, size, flags, MAP_SHARED, io_dev->fd, 0);
+ io_dev->mmap = mmap(NULL, map_size, flags, MAP_SHARED, io_dev->fd, 0);
if (io_dev->mmap == MAP_FAILED) {
rc = -errno;
perror("mmap");
4 years, 7 months
[ndctl PATCH] ndctl, disable-region: check for mounted namespaces
by Dan Williams
Perform a ndctl_namespace_disable_safe loop to disable a region to make
sure we are not ripping out a namespace from underneath an actively
mounted filesystem.
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
ndctl/action.h | 15 +++++++++++++++
ndctl/namespace.c | 15 ++++-----------
ndctl/region.c | 36 ++++++++++++++++++++++++++++++------
3 files changed, 49 insertions(+), 17 deletions(-)
create mode 100644 ndctl/action.h
diff --git a/ndctl/action.h b/ndctl/action.h
new file mode 100644
index 000000000000..43ea62adbcd2
--- /dev/null
+++ b/ndctl/action.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+#ifndef __NDCTL_ACTION_H__
+#define __NDCTL_ACTION_H__
+enum device_action {
+ ACTION_ENABLE,
+ ACTION_DISABLE,
+ ACTION_CREATE,
+ ACTION_DESTROY,
+ ACTION_CHECK,
+};
+#endif /* __NDCTL_ACTION_H__ */
diff --git a/ndctl/namespace.c b/ndctl/namespace.c
index b780924ecf4c..58f23ad0877a 100644
--- a/ndctl/namespace.c
+++ b/ndctl/namespace.c
@@ -17,6 +17,7 @@
#include <unistd.h>
#include <limits.h>
#include <syslog.h>
+#include "action.h"
#include <sys/stat.h>
#include <uuid/uuid.h>
#include <sys/types.h>
@@ -146,15 +147,7 @@ static const struct option check_options[] = {
OPT_END(),
};
-enum namespace_action {
- ACTION_ENABLE,
- ACTION_DISABLE,
- ACTION_CREATE,
- ACTION_DESTROY,
- ACTION_CHECK,
-};
-
-static int set_defaults(enum namespace_action mode)
+static int set_defaults(enum device_action mode)
{
int rc = 0;
@@ -264,7 +257,7 @@ static int set_defaults(enum namespace_action mode)
* looking at actual namespace devices and available resources.
*/
static const char *parse_namespace_options(int argc, const char **argv,
- enum namespace_action mode, const struct option *options,
+ enum device_action mode, const struct option *options,
char *xable_usage)
{
const char * const u[] = {
@@ -989,7 +982,7 @@ int namespace_check(struct ndctl_namespace *ndns, bool verbose, bool force,
bool repair);
static int do_xaction_namespace(const char *namespace,
- enum namespace_action action, struct ndctl_ctx *ctx)
+ enum device_action action, struct ndctl_ctx *ctx)
{
struct ndctl_namespace *ndns, *_n;
int rc = -ENXIO, success = 0;
diff --git a/ndctl/region.c b/ndctl/region.c
index cc3c133c3190..1402a7548be8 100644
--- a/ndctl/region.c
+++ b/ndctl/region.c
@@ -14,6 +14,7 @@
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
+#include "action.h"
#include <util/filter.h>
#include <util/parse-options.h>
#include <ndctl/libndctl.h>
@@ -67,8 +68,32 @@ static const char *parse_region_options(int argc, const char **argv,
return argv[0];
}
-static int do_xable_region(const char *region_arg,
- int (*xable_fn)(struct ndctl_region *), struct ndctl_ctx *ctx)
+static int region_action(struct ndctl_region *region, enum device_action mode)
+{
+ struct ndctl_namespace *ndns;
+ int rc = 0;
+
+ switch (mode) {
+ case ACTION_ENABLE:
+ rc = ndctl_region_enable(region);
+ break;
+ case ACTION_DISABLE:
+ ndctl_namespace_foreach(region, ndns) {
+ rc = ndctl_namespace_disable_safe(ndns);
+ if (rc)
+ return rc;
+ }
+ rc = ndctl_region_disable_invalidate(region);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int do_xable_region(const char *region_arg, enum device_action mode,
+ struct ndctl_ctx *ctx)
{
int rc = -ENXIO, success = 0;
struct ndctl_region *region;
@@ -88,7 +113,7 @@ static int do_xable_region(const char *region_arg,
continue;
if (!util_region_filter(region, region_arg))
continue;
- if (xable_fn(region) == 0)
+ if (region_action(region, mode) == 0)
success++;
}
}
@@ -103,8 +128,7 @@ int cmd_disable_region(int argc, const char **argv, void *ctx)
{
char *xable_usage = "ndctl disable-region <region> [<options>]";
const char *region = parse_region_options(argc, argv, xable_usage);
- int disabled = do_xable_region(region, ndctl_region_disable_invalidate,
- ctx);
+ int disabled = do_xable_region(region, ACTION_DISABLE, ctx);
if (disabled < 0) {
fprintf(stderr, "error disabling regions: %s\n",
@@ -124,7 +148,7 @@ int cmd_enable_region(int argc, const char **argv, void *ctx)
{
char *xable_usage = "ndctl enable-region <region> [<options>]";
const char *region = parse_region_options(argc, argv, xable_usage);
- int enabled = do_xable_region(region, ndctl_region_enable, ctx);
+ int enabled = do_xable_region(region, ACTION_ENABLE, ctx);
if (enabled < 0) {
fprintf(stderr, "error enabling regions: %s\n",
4 years, 7 months