[PATCH 1/2] acpi/libnvdimm: rework ARS query and removing blocking on timeout at init
by Dave Jiang
On initialization we are going to set bit 1 of Start ARS DSM flag. This
allows us to retrieve the data from the previous scrub without starting a
scrub. This is to obtain any badblocks on all the DIMMs that does not have
scrubbing started by the BIOS. Previously we block surfacing the regions
until ARS is completed on all regions. That has been removed and we will
now do scrubbing in the background with a delayed workqueue. The delayed
workqueue will be scheduled starting at 1 second delay and doubled every
time it has to be rescheduled up to 30 minutes delay. The reschedule will
no longer be timing out.
Signed-off-by: Dave Jiang <dave.jiang(a)intel.com>
---
drivers/acpi/nfit/core.c | 263 ++++++++++++++++++++++------------------------
drivers/acpi/nfit/nfit.h | 14 ++
2 files changed, 135 insertions(+), 142 deletions(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 33c13324e265..32670b82fbfc 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -35,10 +35,6 @@ static bool force_enable_dimms;
module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
-static unsigned int scrub_timeout = NFIT_ARS_TIMEOUT;
-module_param(scrub_timeout, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(scrub_timeout, "Initial scrub timeout in seconds");
-
/* after three payloads of overflow, it's dead jim */
static unsigned int scrub_overflow_abort = 3;
module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR);
@@ -1250,7 +1246,8 @@ static ssize_t scrub_show(struct device *dev,
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
rc = sprintf(buf, "%d%s", acpi_desc->scrub_count,
- (work_busy(&acpi_desc->work)) ? "+\n" : "\n");
+ (work_busy(&acpi_desc->dwork.work)) ?
+ "+\n" : "\n");
}
device_unlock(dev);
return rc;
@@ -2799,86 +2796,6 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
return 0;
}
-static void acpi_nfit_async_scrub(struct acpi_nfit_desc *acpi_desc,
- struct nfit_spa *nfit_spa)
-{
- struct acpi_nfit_system_address *spa = nfit_spa->spa;
- unsigned int overflow_retry = scrub_overflow_abort;
- u64 init_ars_start = 0, init_ars_len = 0;
- struct device *dev = acpi_desc->dev;
- unsigned int tmo = scrub_timeout;
- int rc;
-
- if (!nfit_spa->ars_required || !nfit_spa->nd_region)
- return;
-
- rc = ars_start(acpi_desc, nfit_spa);
- /*
- * If we timed out the initial scan we'll still be busy here,
- * and will wait another timeout before giving up permanently.
- */
- if (rc < 0 && rc != -EBUSY)
- return;
-
- do {
- u64 ars_start, ars_len;
-
- if (acpi_desc->cancel)
- break;
- rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
- if (rc == -ENOTTY)
- break;
- if (rc == -EBUSY && !tmo) {
- dev_warn(dev, "range %d ars timeout, aborting\n",
- spa->range_index);
- break;
- }
-
- if (rc == -EBUSY) {
- /*
- * Note, entries may be appended to the list
- * while the lock is dropped, but the workqueue
- * being active prevents entries being deleted /
- * freed.
- */
- mutex_unlock(&acpi_desc->init_mutex);
- ssleep(1);
- tmo--;
- mutex_lock(&acpi_desc->init_mutex);
- continue;
- }
-
- /* we got some results, but there are more pending... */
- if (rc == -ENOSPC && overflow_retry--) {
- if (!init_ars_len) {
- init_ars_len = acpi_desc->ars_status->length;
- init_ars_start = acpi_desc->ars_status->address;
- }
- rc = ars_continue(acpi_desc);
- }
-
- if (rc < 0) {
- dev_warn(dev, "range %d ars continuation failed\n",
- spa->range_index);
- break;
- }
-
- if (init_ars_len) {
- ars_start = init_ars_start;
- ars_len = init_ars_len;
- } else {
- ars_start = acpi_desc->ars_status->address;
- ars_len = acpi_desc->ars_status->length;
- }
- dev_dbg(dev, "spa range: %d ars from %#llx + %#llx complete\n",
- spa->range_index, ars_start, ars_len);
- /* notify the region about new poison entries */
- nvdimm_region_notify(nfit_spa->nd_region,
- NVDIMM_REVALIDATE_POISON);
- break;
- } while (1);
-}
-
static void acpi_nfit_scrub(struct work_struct *work)
{
struct device *dev;
@@ -2887,37 +2804,57 @@ static void acpi_nfit_scrub(struct work_struct *work)
u64 init_scrub_address = 0;
bool init_ars_done = false;
struct acpi_nfit_desc *acpi_desc;
- unsigned int tmo = scrub_timeout;
unsigned int overflow_retry = scrub_overflow_abort;
+ int ars_needed = 0;
- acpi_desc = container_of(work, typeof(*acpi_desc), work);
+ acpi_desc = container_of(work, typeof(*acpi_desc), dwork.work);
dev = acpi_desc->dev;
- /*
- * We scrub in 2 phases. The first phase waits for any platform
- * firmware initiated scrubs to complete and then we go search for the
- * affected spa regions to mark them scanned. In the second phase we
- * initiate a directed scrub for every range that was not scrubbed in
- * phase 1. If we're called for a 'rescan', we harmlessly pass through
- * the first phase, but really only care about running phase 2, where
- * regions can be notified of new poison.
- */
-
- /* process platform firmware initiated scrubs */
retry:
mutex_lock(&acpi_desc->init_mutex);
list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
struct nd_cmd_ars_status *ars_status;
- struct acpi_nfit_system_address *spa;
- u64 ars_start, ars_len;
+ struct acpi_nfit_system_address *spa = nfit_spa->spa;
+ u64 ars_start_addr, ars_len;
int rc;
if (acpi_desc->cancel)
- break;
+ goto out;
- if (nfit_spa->nd_region)
+ if (nfit_spa->ars_state == NFIT_ARS_STATE_COMPLETE ||
+ nfit_spa->ars_state == NFIT_ARS_STATE_UNSUPPORTED ||
+ nfit_spa->ars_state == NFIT_ARS_STATE_FAILED)
continue;
+ if (nfit_spa->ars_state == NFIT_ARS_STATE_REQUESTED) {
+ dev_dbg(dev, "Range %d starting ARS\n",
+ spa->range_index);
+ rc = ars_start(acpi_desc, nfit_spa);
+ if (rc == -EBUSY) {
+ queue_delayed_work(nfit_wq, &acpi_desc->dwork,
+ acpi_desc->scrub_timeout * HZ);
+ /*
+ * Increase timeout for next time around.
+ * We'll max it at 30mins.
+ */
+ dev_dbg(dev, "Range %d ARS start busy. reschedule in %u seconds\n",
+ spa->range_index,
+ acpi_desc->scrub_timeout);
+ acpi_desc->scrub_timeout =
+ min_t(unsigned int,
+ acpi_desc->scrub_timeout * 2,
+ 1800);
+ goto out;
+ }
+ if (rc < 0) {
+ dev_dbg(dev, "Range %d ARS start failed.\n",
+ spa->range_index);
+ nfit_spa->ars_state = NFIT_ARS_STATE_FAILED;
+ continue;
+ }
+ nfit_spa->ars_state = NFIT_ARS_STATE_IN_PROGRESS;
+ }
+
if (init_ars_done) {
/*
* No need to re-query, we're now just
@@ -2930,23 +2867,30 @@ static void acpi_nfit_scrub(struct work_struct *work)
if (rc == -ENOTTY) {
/* no ars capability, just register spa and move on */
+ nfit_spa->ars_state = NFIT_ARS_STATE_UNSUPPORTED;
acpi_nfit_register_region(acpi_desc, nfit_spa);
continue;
}
- if (rc == -EBUSY && !tmo) {
- /* fallthrough to directed scrub in phase 2 */
- dev_warn(dev, "timeout awaiting ars results, continuing...\n");
- break;
- } else if (rc == -EBUSY) {
- mutex_unlock(&acpi_desc->init_mutex);
- ssleep(1);
- tmo--;
- goto retry;
+ if (rc == -EBUSY) {
+ nfit_spa->ars_state = NFIT_ARS_STATE_IN_PROGRESS;
+ queue_delayed_work(nfit_wq, &acpi_desc->dwork,
+ acpi_desc->scrub_timeout * HZ);
+ /*
+ * Increase timeout for next time around. We'll max
+ * it at 30mins
+ */
+ dev_dbg(dev, "Range %d ARS query busy. reschedule in %u seconds\n",
+ spa->range_index,
+ acpi_desc->scrub_timeout);
+ acpi_desc->scrub_timeout = min_t(unsigned int,
+ acpi_desc->scrub_timeout * 2, 1800);
+ goto out;
}
/* we got some results, but there are more pending... */
if (rc == -ENOSPC && overflow_retry--) {
+ nfit_spa->ars_state = NFIT_ARS_STATE_IN_PROGRESS;
ars_status = acpi_desc->ars_status;
/*
* Record the original scrub range, so that we
@@ -2965,57 +2909,86 @@ static void acpi_nfit_scrub(struct work_struct *work)
}
if (rc < 0) {
- /*
- * Initial scrub failed, we'll give it one more
- * try below...
- */
- break;
+ nfit_spa->ars_state = NFIT_ARS_STATE_FAILED;
+ dev_warn(dev, "Range %d ars continuation failed\n",
+ spa->range_index);
+ continue;
}
/* We got some final results, record completed ranges */
ars_status = acpi_desc->ars_status;
if (init_scrub_length) {
- ars_start = init_scrub_address;
- ars_len = ars_start + init_scrub_length;
+ ars_start_addr = init_scrub_address;
+ ars_len = ars_start_addr + init_scrub_length;
} else {
- ars_start = ars_status->address;
+ ars_start_addr = ars_status->address;
ars_len = ars_status->length;
}
- spa = nfit_spa->spa;
if (!init_ars_done) {
init_ars_done = true;
- dev_dbg(dev, "init scrub %#llx + %#llx complete\n",
- ars_start, ars_len);
+ dev_dbg(dev, "Scrub %#llx + %#llx complete\n",
+ ars_start_addr, ars_len);
}
- if (ars_start <= spa->address && ars_start + ars_len
- >= spa->address + spa->length)
+
+ if (ars_start_addr <= spa->address && ars_start_addr + ars_len
+ >= spa->address + spa->length &&
+ !nfit_spa->nd_region) {
acpi_nfit_register_region(acpi_desc, nfit_spa);
+ dev_dbg(dev, "Range %d register region\n",
+ nfit_spa->spa->range_index);
+ }
+
+ dev_dbg(dev, "Range %d ARS done\n", spa->range_index);
+ nfit_spa->ars_state = NFIT_ARS_STATE_COMPLETE;
+ acpi_desc->scrub_timeout = 1;
+ if (nfit_spa->nd_region)
+ nvdimm_region_notify(nfit_spa->nd_region,
+ NVDIMM_REVALIDATE_POISON);
}
/*
* For all the ranges not covered by an initial scrub we still
- * want to see if there are errors, but it's ok to discover them
- * asynchronously.
+ * want to see if there are errors
*/
list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+ if (nfit_spa->nd_region)
+ continue;
+
/*
- * Flag all the ranges that still need scrubbing, but
- * register them now to make data available.
+ * If we are going through here first time and region
+ * is not registered, we know BIOS has not scrubbed
+ * the range and we need to request scrubbing. Otherwise
+ * we'll just go ahead and register the region.
*/
- if (!nfit_spa->nd_region) {
- nfit_spa->ars_required = 1;
+ if (!acpi_desc->init_complete) {
+ dev_dbg(dev, "Range %d requested for ARS\n",
+ nfit_spa->spa->range_index);
+ nfit_spa->ars_state = NFIT_ARS_STATE_REQUESTED;
+ ars_needed++;
+ } else {
acpi_nfit_register_region(acpi_desc, nfit_spa);
+ dev_dbg(dev, "Range %d register region\n",
+ nfit_spa->spa->range_index);
}
}
- acpi_desc->init_complete = 1;
list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
- acpi_nfit_async_scrub(acpi_desc, nfit_spa);
+ dev_dbg(dev, "Range %d ars state: %d\n",
+ nfit_spa->spa->range_index,
+ nfit_spa->ars_state);
+ acpi_desc->init_complete = 1;
+ if (ars_needed) {
+ queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0);
+ goto out;
+ } else
+ acpi_desc->ars_start_flags = 0;
+
acpi_desc->scrub_count++;
- acpi_desc->ars_start_flags = 0;
if (acpi_desc->scrub_count_state)
sysfs_notify_dirent(acpi_desc->scrub_count_state);
+
+out:
mutex_unlock(&acpi_desc->init_mutex);
}
@@ -3032,9 +3005,13 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
return rc;
}
- acpi_desc->ars_start_flags = 0;
+ /*
+ * At initialization, we are going to grab all the known errors
+ * instead of starting ARS.
+ */
+ acpi_desc->ars_start_flags = ND_ARS_RETURN_PREV_DATA;
if (!acpi_desc->cancel)
- queue_work(nfit_wq, &acpi_desc->work);
+ queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0);
return 0;
}
@@ -3230,7 +3207,7 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
* just needs guarantees that any ars it initiates are not
* interrupted by any intervening start reqeusts from userspace.
*/
- if (work_busy(&acpi_desc->work))
+ if (work_busy(&acpi_desc->dwork.work))
return -EBUSY;
return 0;
@@ -3241,7 +3218,7 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags)
struct device *dev = acpi_desc->dev;
struct nfit_spa *nfit_spa;
- if (work_busy(&acpi_desc->work))
+ if (work_busy(&acpi_desc->dwork.work))
return -EBUSY;
mutex_lock(&acpi_desc->init_mutex);
@@ -3256,10 +3233,14 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags)
if (nfit_spa_type(spa) != NFIT_SPA_PM)
continue;
- nfit_spa->ars_required = 1;
+ if (nfit_spa->ars_state == NFIT_ARS_STATE_UNSUPPORTED ||
+ nfit_spa->ars_state == NFIT_ARS_STATE_FAILED)
+ continue;
+
+ nfit_spa->ars_state = NFIT_ARS_STATE_REQUESTED;
}
acpi_desc->ars_start_flags = flags;
- queue_work(nfit_wq, &acpi_desc->work);
+ queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0);
dev_dbg(dev, "ars_scan triggered\n");
mutex_unlock(&acpi_desc->init_mutex);
@@ -3290,7 +3271,8 @@ void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
INIT_LIST_HEAD(&acpi_desc->dimms);
INIT_LIST_HEAD(&acpi_desc->list);
mutex_init(&acpi_desc->init_mutex);
- INIT_WORK(&acpi_desc->work, acpi_nfit_scrub);
+ acpi_desc->scrub_timeout = 1;
+ INIT_DELAYED_WORK(&acpi_desc->dwork, acpi_nfit_scrub);
}
EXPORT_SYMBOL_GPL(acpi_nfit_desc_init);
@@ -3314,6 +3296,7 @@ void acpi_nfit_shutdown(void *data)
mutex_lock(&acpi_desc->init_mutex);
acpi_desc->cancel = 1;
+ cancel_delayed_work_sync(&acpi_desc->dwork);
mutex_unlock(&acpi_desc->init_mutex);
/*
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
index ac9c49463731..dde28f33a371 100644
--- a/drivers/acpi/nfit/nfit.h
+++ b/drivers/acpi/nfit/nfit.h
@@ -117,10 +117,19 @@ enum nfit_dimm_notifiers {
NFIT_NOTIFY_DIMM_HEALTH = 0x81,
};
+enum nfit_ars_state {
+ NFIT_ARS_STATE_IDLE = 0,
+ NFIT_ARS_STATE_REQUESTED,
+ NFIT_ARS_STATE_IN_PROGRESS,
+ NFIT_ARS_STATE_COMPLETE,
+ NFIT_ARS_STATE_UNSUPPORTED,
+ NFIT_ARS_STATE_FAILED,
+};
+
struct nfit_spa {
struct list_head list;
struct nd_region *nd_region;
- unsigned int ars_required:1;
+ enum nfit_ars_state ars_state;
u32 clear_err_unit;
u32 max_ars;
struct acpi_nfit_system_address spa[0];
@@ -191,7 +200,7 @@ struct acpi_nfit_desc {
u8 ars_start_flags;
struct nd_cmd_ars_status *ars_status;
size_t ars_status_size;
- struct work_struct work;
+ struct delayed_work dwork;
struct list_head list;
struct kernfs_node *scrub_count_state;
unsigned int scrub_count;
@@ -202,6 +211,7 @@ struct acpi_nfit_desc {
unsigned long bus_cmd_force_en;
unsigned long bus_nfit_cmd_force_en;
unsigned int platform_cap;
+ unsigned int scrub_timeout;
int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
void *iobuf, u64 len, int rw);
};
4 years, 2 months
[PATCH 0/4] Adding support to parse BERT for libnvdimm
by Dave Jiang
The following series implements support for parsing of the BERT records
and adding the error memory ranges to nvdimm badblocks in order for the
kernel to avoid prevent the kernel from accessing those areas. And with
the addition of this support, we can surface the nd regions instead of waiting
for ARS to complete. So the ARS handling is reworked to run in the
background and not block nd region registration.
---
Dave Jiang (4):
acpi: add find error record in BERT function
acpi/libnvdimm: search through BERT records and add to nvdimm badblocks
acpi/nfit: removing ARS timeout and change scrubbing to delayed work
acpi/nfit: allow knob to disable ARS being issued at kernel boot
drivers/acpi/apei/bert.c | 137 +++++++++++++++++++++---
drivers/acpi/nfit/core.c | 262 ++++++++++++++++++++-------------------------
drivers/acpi/nfit/nfit.h | 13 ++
drivers/nvdimm/core.c | 6 +
include/linux/acpi.h | 10 ++
include/linux/libnvdimm.h | 1
6 files changed, 271 insertions(+), 158 deletions(-)
--
4 years, 3 months
[PATCH v7 00/14] dax: fix dma vs truncate/hole-punch
by Dan Williams
Changes since v6 [1]:
* Collect some more reviewed-by's from Christoph, thanks Christoph!
* Rework XFS_MMAPLOCK_EXCL handling to *permit* rather than require
XFS_MMAPLOCK_EXCL to be held over calls to xfs_break_layouts()
(Christoph)
* Clean up kbuild robot reports against "ext2, dax: introduce ext2_dax_aops"
and "fs, dax: use page->mapping to warn if truncate collides with a
busy page".
* Squash the xfs_break_leased_layouts() 'did_unlock' rework into "xfs:
prepare xfs_break_layouts() for another layout type" (Christoph)
* Communicate the 'did_unlock' condition with an out parameter rather
than a positive error code (Christoph). A few other small / welcome
clean ups fell out as a result.
* Rename BREAK_TRUNCATE to BREAK_UNMAPI to make it clear the
implementation is concerned with any and all inode extent unmap
events, not just truncate(2). (Darrick)
* Rebase the branch on commit 6b2bb7265f0b "sched/wait: Introduce
wait_var_event()" from tip.git/sched/wait. Thanks Peter!
[1]: https://lists.01.org/pipermail/linux-nvdimm/2018-March/014806.html
---
Background:
get_user_pages() in the filesystem pins file backed memory pages for
access by devices performing dma. However, it only pins the memory pages
not the page-to-file offset association. If a file is truncated the
pages are mapped out of the file and dma may continue indefinitely into
a page that is owned by a device driver. This breaks coherency of the
file vs dma, but the assumption is that if userspace wants the
file-space truncated it does not matter what data is inbound from the
device, it is not relevant anymore. The only expectation is that dma can
safely continue while the filesystem reallocates the block(s).
Problem:
This expectation that dma can safely continue while the filesystem
changes the block map is broken by dax. With dax the target dma page
*is* the filesystem block. The model of leaving the page pinned for dma,
but truncating the file block out of the file, means that the filesytem
is free to reallocate a block under active dma to another file and now
the expected data-incoherency situation has turned into active
data-corruption.
Solution:
Defer all filesystem operations (fallocate(), truncate()) on a dax mode
file while any page/block in the file is under active dma. This solution
assumes that dma is transient. Cases where dma operations are known to
not be transient, like RDMA, have been explicitly disabled via
commits like 5f1d43de5416 "IB/core: disable memory registration of
filesystem-dax vmas".
The dax_layout_busy_page() routine is called by filesystems with a lock
held against mm faults (i_mmap_lock) to find pinned / busy dax pages.
The process of looking up a busy page invalidates all mappings
to trigger any subsequent get_user_pages() to block on i_mmap_lock.
The filesystem continues to call dax_layout_busy_page() until it finally
returns no more active pages. This approach assumes that the page
pinning is transient, if that assumption is violated the system would
have likely hung from the uncompleted I/O.
---
Dan Williams (14):
dax: store pfns in the radix
fs, dax: prepare for dax-specific address_space_operations
block, dax: remove dead code in blkdev_writepages()
xfs, dax: introduce xfs_dax_aops
ext4, dax: introduce ext4_dax_aops
ext2, dax: introduce ext2_dax_aops
fs, dax: use page->mapping to warn if truncate collides with a busy page
mm, dax: enable filesystems to trigger dev_pagemap ->page_free callbacks
mm, dev_pagemap: introduce CONFIG_DEV_PAGEMAP_OPS
memremap: mark devm_memremap_pages() EXPORT_SYMBOL_GPL
mm, fs, dax: handle layout changes to pinned dax mappings
xfs: prepare xfs_break_layouts() to be called with XFS_MMAPLOCK_EXCL
xfs: prepare xfs_break_layouts() for another layout type
xfs, dax: introduce xfs_break_dax_layouts()
drivers/dax/super.c | 96 +++++++++++++++++--
drivers/nvdimm/pmem.c | 3 -
fs/Kconfig | 1
fs/block_dev.c | 5 -
fs/dax.c | 231 ++++++++++++++++++++++++++++++++++++----------
fs/ext2/ext2.h | 1
fs/ext2/inode.c | 43 +++++----
fs/ext2/namei.c | 18 ----
fs/ext2/super.c | 6 +
fs/ext4/inode.c | 38 ++++++--
fs/ext4/super.c | 6 +
fs/libfs.c | 27 +++++
fs/xfs/xfs_aops.c | 21 +++-
fs/xfs/xfs_aops.h | 1
fs/xfs/xfs_file.c | 76 ++++++++++++++-
fs/xfs/xfs_inode.h | 16 +++
fs/xfs/xfs_ioctl.c | 8 --
fs/xfs/xfs_iops.c | 21 +++-
fs/xfs/xfs_pnfs.c | 16 ++-
fs/xfs/xfs_pnfs.h | 6 +
fs/xfs/xfs_super.c | 20 ++--
include/linux/dax.h | 46 ++++++++-
include/linux/fs.h | 3 +
include/linux/memremap.h | 28 ++----
include/linux/mm.h | 61 +++++++++---
kernel/memremap.c | 32 +++++-
mm/Kconfig | 5 +
mm/gup.c | 5 +
mm/hmm.c | 13 ---
mm/swap.c | 3 -
30 files changed, 638 insertions(+), 218 deletions(-)
4 years, 3 months
[ndctl PATCH 1/3] ndctl, check: fix a few error returns
by Vishal Verma
We were returning a raw '-1' in one case, and a couple of other 'errno'
returns without making them negative. Fix them to make the returns
consistent.
Cc: Dan Williams <dan.j.williams(a)intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma(a)intel.com>
---
ndctl/check.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ndctl/check.c b/ndctl/check.c
index 57bbf3f..d2d74a2 100644
--- a/ndctl/check.c
+++ b/ndctl/check.c
@@ -139,7 +139,7 @@ static int btt_write_info(struct btt_chk *bttc, struct btt_sb *btt_sb, u64 off)
err(bttc, "BTT info block at offset %#lx needs to be restored\n",
off);
repair_msg(bttc);
- return -1;
+ return -EIO;
}
info(bttc, "Restoring BTT info block at offset %#lx\n", off);
@@ -184,7 +184,7 @@ static int btt_copy_to_info2(struct arena_info *a)
ms_align = (void *)rounddown((u64)a->map.info2, a->bttc->sys_page_size);
ms_size = max(BTT_INFO_SIZE, a->bttc->sys_page_size);
if (msync(ms_align, ms_size, MS_SYNC) < 0)
- return errno;
+ return -errno;
return 0;
}
@@ -231,7 +231,7 @@ static int btt_map_write(struct arena_info *a, u32 lba, u32 mapping)
ms_align = (void *)rounddown((u64)&a->map.map[lba],
a->bttc->sys_page_size);
if (msync(ms_align, a->bttc->sys_page_size, MS_SYNC) < 0)
- return errno;
+ return -errno;
return 0;
}
--
2.14.3
4 years, 3 months
[PATCH 1/6] libnvdimm: Add of_node to region and bus descriptors
by Oliver O'Halloran
We want to be able to cross reference the region and bus devices
with the device tree node that they were spawned from. libNVDIMM
handles creating the actual devices for these internally, so we
need to pass in a pointer to the relevant node in the descriptor.
Signed-off-by: Oliver O'Halloran <oohall(a)gmail.com>
Acked-by: Dan Williams <dan.j.williams(a)intel.com>
---
drivers/nvdimm/bus.c | 1 +
drivers/nvdimm/region_devs.c | 1 +
include/linux/libnvdimm.h | 3 +++
3 files changed, 5 insertions(+)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 78eabc3a1ab1..c6106914f396 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -358,6 +358,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
nvdimm_bus->dev.release = nvdimm_bus_release;
nvdimm_bus->dev.groups = nd_desc->attr_groups;
nvdimm_bus->dev.bus = &nvdimm_bus_type;
+ nvdimm_bus->dev.of_node = nd_desc->of_node;
dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
rc = device_register(&nvdimm_bus->dev);
if (rc) {
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index e6d01911e092..2f1d5771100e 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -1005,6 +1005,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
dev->parent = &nvdimm_bus->dev;
dev->type = dev_type;
dev->groups = ndr_desc->attr_groups;
+ dev->of_node = ndr_desc->of_node;
nd_region->ndr_size = resource_size(ndr_desc->res);
nd_region->ndr_start = ndr_desc->res->start;
nd_device_register(dev);
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index ff855ed965fb..f61cb5050297 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -76,12 +76,14 @@ typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
unsigned int buf_len, int *cmd_rc);
+struct device_node;
struct nvdimm_bus_descriptor {
const struct attribute_group **attr_groups;
unsigned long bus_dsm_mask;
unsigned long cmd_mask;
struct module *module;
char *provider_name;
+ struct device_node *of_node;
ndctl_fn ndctl;
int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc);
int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc,
@@ -123,6 +125,7 @@ struct nd_region_desc {
int num_lanes;
int numa_node;
unsigned long flags;
+ struct device_node *of_node;
};
struct device;
--
2.9.5
4 years, 3 months
[PATCH] acpi, nfit: rework NVDIMM leaf method detection
by Dan Williams
Some BIOSen do not handle 0-byte transfer lengths for the _LSR and _LSW
(label storage read/write) methods. This causes Linux to fallback to the
deprecated _DSM path, or otherwise disable label support.
Introduce acpi_nvdimm_has_method() to detect whether a method is
available rather than calling the method, require _LSI and _LSR to be
paired, and require read support before enabling write support.
Cc: <stable(a)vger.kernel.org>
Fixes: 4b27db7e26cd ("acpi, nfit: add support for the _LS...")
Suggested-by: Erik Schmauss <erik.schmauss(a)intel.com>
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
drivers/acpi/nfit/core.c | 41 +++++++++++++++++++++--------------------
drivers/acpi/nfit/nfit.h | 5 ++---
2 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 4530d89044db..12fb414fa678 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -196,7 +196,7 @@ static int xlat_nvdimm_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd
* In the _LSI, _LSR, _LSW case the locked status is
* communicated via the read/write commands
*/
- if (nfit_mem->has_lsi)
+ if (nfit_mem->has_lsr)
break;
if (status >> 16 & ND_CONFIG_LOCKED)
@@ -483,7 +483,7 @@ 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 (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE && nfit_mem->has_lsi)
+ if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE && nfit_mem->has_lsr)
out_obj = acpi_label_info(handle);
else if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && nfit_mem->has_lsr) {
struct nd_cmd_get_config_data_hdr *p = buf;
@@ -1653,12 +1653,23 @@ static void acpi_nvdimm_notify(acpi_handle handle, u32 event, void *data)
device_unlock(dev->parent);
}
+static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method)
+{
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(adev->handle, method, &handle);
+
+ if (ACPI_SUCCESS(status))
+ return true;
+ return false;
+}
+
static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
struct nfit_mem *nfit_mem, u32 device_handle)
{
struct acpi_device *adev, *adev_dimm;
struct device *dev = acpi_desc->dev;
- union acpi_object *obj;
unsigned long dsm_mask;
const guid_t *guid;
int i;
@@ -1731,25 +1742,15 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
1ULL << i))
set_bit(i, &nfit_mem->dsm_mask);
- obj = acpi_label_info(adev_dimm->handle);
- if (obj) {
- ACPI_FREE(obj);
- nfit_mem->has_lsi = 1;
- dev_dbg(dev, "%s: has _LSI\n", dev_name(&adev_dimm->dev));
- }
-
- obj = acpi_label_read(adev_dimm->handle, 0, 0);
- if (obj) {
- ACPI_FREE(obj);
- nfit_mem->has_lsr = 1;
+ if (acpi_nvdimm_has_method(adev_dimm, "_LSI")
+ && acpi_nvdimm_has_method(adev_dimm, "_LSR")) {
dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev));
+ nfit_mem->has_lsr = true;
}
- obj = acpi_label_write(adev_dimm->handle, 0, 0, NULL);
- if (obj) {
- ACPI_FREE(obj);
- nfit_mem->has_lsw = 1;
+ if (nfit_mem->has_lsr && acpi_nvdimm_has_method(adev_dimm, "_LSW")) {
dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev));
+ nfit_mem->has_lsw = true;
}
return 0;
@@ -1838,10 +1839,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK;
}
- if (nfit_mem->has_lsi)
+ if (nfit_mem->has_lsr) {
set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
- if (nfit_mem->has_lsr)
set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
+ }
if (nfit_mem->has_lsw)
set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask);
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
index 50d36e166d70..ac9c49463731 100644
--- a/drivers/acpi/nfit/nfit.h
+++ b/drivers/acpi/nfit/nfit.h
@@ -171,9 +171,8 @@ struct nfit_mem {
struct resource *flush_wpq;
unsigned long dsm_mask;
int family;
- u32 has_lsi:1;
- u32 has_lsr:1;
- u32 has_lsw:1;
+ bool has_lsr;
+ bool has_lsw;
};
struct acpi_nfit_desc {
4 years, 3 months
[PATCH] ndctl, label: change nvdimm_num_label_slots per UEFI 2.7
by Toshi Kani
sizeof_namespace_index() fails when NVDIMM devices have the minimum
1024 bytes label storage area. nvdimm_num_label_slots() returns 3
slots while the area is only big enough for 2 slots.
Change nvdimm_num_label_slots() to calculate a number of label slots
according to UEFI 2.7 spec.
Signed-off-by: Toshi Kani <toshi.kani(a)hpe.com>
Cc: Dan Williams <dan.j.williams(a)intel.com>
---
ndctl/lib/dimm.c | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c
index b3e032e..6b78a4b 100644
--- a/ndctl/lib/dimm.c
+++ b/ndctl/lib/dimm.c
@@ -66,9 +66,27 @@ static unsigned int sizeof_namespace_label(struct nvdimm_data *ndd)
return ndctl_dimm_sizeof_namespace_label(to_dimm(ndd));
}
+static size_t __sizeof_namespace_index(u32 nslot)
+{
+ return ALIGN(sizeof(struct namespace_index) + DIV_ROUND_UP(nslot, 8),
+ NSINDEX_ALIGN);
+}
+
+static int __nvdimm_num_label_slots(struct nvdimm_data *ndd,
+ size_t index_size)
+{
+ return (ndd->config_size - index_size * 2) /
+ sizeof_namespace_label(ndd);
+}
+
static int nvdimm_num_label_slots(struct nvdimm_data *ndd)
{
- return ndd->config_size / (sizeof_namespace_label(ndd) + 1);
+ u32 tmp_nslot, n;
+
+ tmp_nslot = ndd->config_size / sizeof_namespace_label(ndd);
+ n = __sizeof_namespace_index(tmp_nslot) / NSINDEX_ALIGN;
+
+ return __nvdimm_num_label_slots(ndd, NSINDEX_ALIGN * n);
}
static unsigned int sizeof_namespace_index(struct nvdimm_data *ndd)
@@ -78,18 +96,14 @@ static unsigned int sizeof_namespace_index(struct nvdimm_data *ndd)
struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm);
/*
- * The minimum index space is 512 bytes, with that amount of
- * index we can describe ~1400 labels which is less than a byte
- * of overhead per label. Round up to a byte of overhead per
- * label and determine the size of the index region. Yes, this
- * starts to waste space at larger config_sizes, but it's
- * unlikely we'll ever see anything but 128K.
+ * Per UEFI 2.7, the minimum size of the Label Storage Area is large
+ * enough to hold 2 index blocks and 2 labels. The minimum index
+ * block size is 256 bytes, and the minimum label size is 256 bytes.
*/
nslot = nvdimm_num_label_slots(ndd);
space = ndd->config_size - nslot * sizeof_namespace_label(ndd);
- size = ALIGN(sizeof(struct namespace_index) + DIV_ROUND_UP(nslot, 8),
- NSINDEX_ALIGN) * 2;
- if (size <= space)
+ size = __sizeof_namespace_index(nslot) * 2;
+ if (size <= space && nslot >= 2)
return size / 2;
err(ctx, "%s: label area (%ld) too small to host (%d byte) labels\n",
4 years, 3 months
Attn: HR Dept. (Manpower Agency Introduction - Pakistan)
by Farrukh Shaikh
Dear Sir/Madam,
Are you looking to recruit manpower from Pakistan, India, Philippines, Bangladesh, Sri Lanka, Indonesia, Nepal, Myanmar or Vietnam? If not currently, please save this email for your future reference.
We (S.A.Z UNIVERSAL LINKS LTD) are a professional HR, recruiting and manpower placement company that provides all types of manpower recruitment services and having a strong history of top line manpower solutions i.e. professional, executive level, skilled, semi-skilled and unskilled workforce from Pakistan and from other countries (through our counterpart offices & associates) to large number of reputable employers for their projects in Middle East, Far East, Europe and America. Our steadfast commitment to serve our clients with utmost efficiency and responsibility has become our hallmark. Please visit "www.sazunilinks.com/profile.pdf" for our detailed company profile with some of our work history for your kind reference.
We are a registered manpower placement company under Pakistan Overseas Employment Promoters Association (POEPA) with a well-experienced team to select perfect candidates for our esteemed clients. Our mission is to provide excellent services and solutions according to exact requirement of our valuable clients as we believe that this is a key for a long term relationship with them.
Over the years, we were able to earn the trust of many reputable companies worldwide, particularly in the Gulf region: Some of our major clients in different regions are as follows:
.---Saudi Arabia---.:
.|. Almarai Company .|. ASSAD SAID for Contracting Co .|. Jeddah Cables Company .|. Nesma & Partners .|. Freyssinet Saudi Arabia .|. Al-Rushaid group .|. Al-Faraa Group .|. Omrania & Associates .|. Al-Muhaidib Contracting Co. .|. Al-Saad General Contracting Co. .|. Abahsain Company .|. Jomail Saudi Arabia .|. Petrozone Est. .|. Electric Water .|. Heater Factory .|. Bridgeway Specialized Contracting Co. Ltd .|. Top Screens Co. .|. National scientific company .|. Achevx Advertising .|. Industrial Contractors Co. Ltd.(INCO) .|. SAED Recruitment Co. .|. Jamjoom Medical Industries .|. SAG Contracting .|. Anan Iskan Housing Solutions .|. Almaarefah school .|. Arcoma Group .|. Dakheel Company .|. Global Ports Co. .|. IHG | Holiday Inn Riyadh .|. Sisco Saudi .|. Angari Co. .|. Dejam Co. .|. STS Co. .|. Gandour, Saudi Arabia .|. Maaf Dalkia, Saudi Arabia .|. Saudi Chevron Phillips Company .|. Alkhorayef Group .|. Universal Motors Agencies (GMC) .|. Arabian Auto Agency (AAA) .|. Al-Jomaih Holding Company .|. Saeed R Al-Zahrani Corporation (SRACO) .|. Arcelor Mittal Steel Company .|. Al-Watania Industries .|. Kanoo Commercial Group .|. Batterjee Holdings .|. AnNasban Group .|. Searas International .|. Astra Foods .|. Petron Saudi Contracting Co. .|. International Paints Ltd (AKZO NOBEL) .|. Al-Faraa Group .|. AECOM Arabia Ltd. Co. .|. PVC Arabia Co. .|. Al-Rasheed Group .|. United Meem Co. .|. JENAN Properties .|. Engineering Unit Gen. Cont. .|. Masakeen Co. .|. Eastern Industrial Company .|. M.J.E Steel Co. .|. Saudi International Petrochemical Co. (Sipchem) .|. Construction & Roads Services Co. .|. Al-Beer Medical Group .|. Ali H. Al-Ghamdi & Partners Co [AG&P] .|. Zuhair Fayez Partnership Consultants .|. Gulf Quality Control Co. Ltd .|. Al-Hamrani Fuchs Petroleum Co. .|. Star Weddings Co. .|. Petromin Corporation .|. Saudi Fal Co. .|. ZMS Group .|. University of Ha'il .|. Arrow Food Distribution Company .|. Al-Nasser Group .|. SASIB Arabia .|. First Technical Contracting .|. Rayan Gulf Company .|. Saudi Cranes & Steel Works .|. Emdad Contracting Company .|-- Also serving some prestigious clients like Saudi Aramco, MARAFIQ Utility Company, SABIC (Saudi Basic Industries Corporation), Hadeed Iron & Steel Company and many more through their designated contractors in Kingdom.
.--- United Arab Emirates ---.:
.|. Gulf Piping Company .|. Jerry Varghese .|. Em Tech LLC .|. Maaf Dalikia UAE .|. Cladtech International (Unipods - Al-Rajhi Holdings) .|. Europcar UAE .|. Sawaeed Employment LLC .|. Wave Tech L.L.C .|. Tamas Projects .|. Damas Groupe .|. IFFCO Group .|. MPS Management Consultancy .|. Majestic Jetties Company .|. Global Glass Company .|. Woodworks Factory .|. International Cap Company .|. Elenco Security Systems .|. AkzoNobel Middle East .|. Petron Emirates Contracting Co. .|. Al-Bassam RAK .|. Emirate Dredging Company .|. Global Management Consultants .|-- Also a registered Pakistani Manpower Agency with Abu Dhabi Chamber of Commerce & Industry.
.--- Qatar ---.:
.|. Belfa International .|. HBK Engineering Company .|. Capital Technology Company .|. Al-Khayyat Contracting .|.
.--- Oman ---.:
.|. Rataj Factory for Kitchen & Furniture .|. Nizwa Marble Company .|. A.N Printing Press .|. Arabworld Recruitment Company .|.
.--- Bahrain ---.:
.|. Synergy MiddleEast Group .|. Burgerline Chain of Restaurants .|. Ascentech Telecom .|. Sayed Kadhem Al-Durazi & Sons .|.
.--- Libya ---.:
.|. Galaxy Catering Company .|.
.--- Yemen ---.:
.|. Yemen Plast Co .|. Al Khaled For Gen. Comm. Agencies .|. AMTC Automotive & Machinery Trading Center (Toyota) .|.
.--- Sudan ---.:
.|. Jedian Group .|. Florence Services & Ventures Inc .|. African House for Printing the Glorious Qura'n .|.
The list of our valuable and highly satisfied clients continues to grow and so is our commitment to serve them. We have been extending the network around the world by establishing partnerships with experienced consultants and associates to provide solutions to our clientele more effectively.
If you need one window solution to all your HR/employment needs, please give us a chance to prove our mettle by providing competent, qualified and experienced candidates to you in a very professional & timely manner. We have our own interview & trade testing facilities in major cities such as Karachi, Lahore & Islamabad etc. We are looking forward to work with your esteemed organization.
Thanks / B. Regards
-----------------------------------------
Farrukh A. Shaikh | Director
0092300-8228363 (PAK)
0096653-5705632 (KSA)
farrukh(a)sazunilinks.com
Skype: "farrukh.a.shaikh"
www.linkedin.com/in/farrukhshaikh
WhatsApp for Android & iPhone 0092300-8228363
P.S: If you are not a concern person we should contact regarding Recruitment/HR, kindly let us have e-mail address of Recruitment/HR Manager of your company. We'd appreciate your kind co-operation in this regard. You can also add us on Skype "farrukh.a.shaikh" for any urgent discussions regarding your manpower needs between 11 AM to 7 PM PST.
S.A.Z Universal Links
Overseas Employment Promoters
(License # 2710/KHI)
3rd Floor, 11-E, 7th Commercial Lane,
Zamzama Boulevard, DHA-V,
Karachi-75500, Pakistan.
P: 009221-3-5375035-7 / 3-5375774-5 / 3-5875188
F: 009221-3-5838884
M: 0092300-8231431
M: 0092300-8228363
info(a)sazunilinks.com
W: www.sazunilinks.com
FB: www.facebook.com/sazunilinks
LI: www.linkedin.com/groups?gid=3121564
** The information contained in this message or any of its attachments may be privileged and confidential and intended for the exclusive use of the addressee. The views expressed may not be S.A.Z Universal Links's policy but the personal views of the originator. If you have received this message in error, please unsubscribe by advising the sender immediately by reply e-mail and delete this message and any attachments without retaining a copy.**
4 years, 3 months
[PATCH v9] ndctl: Add support for get bus and region persistence domain
by Dave Jiang
Adding helper functions to iterate through sysfs region persistence domain
attribute. The region will display the domain reported by sysfs for the
region. The bus will display the domain attribute with the least persistence
amongst all the regions. ndctl_bus_get_persistence_domain() and
ndctl_region_get_persistence_domain are exported. ndctl list will also display
the region persistence domain as well.
Signed-off-by: Dave Jiang <dave.jiang(a)intel.com>
---
v9:
- Clean up after "libnvdimm, nfit: fix persistence domain reporting" kernel
patch changes.
v8:
- Fix get ndctl_bus_get_persistence_domain logic
v7:
- set attrib to unknown when no attrib detected instead of none. will add
support of none attrib in kernel at a later time.
v6:
- emit "none" when there's nothing in sysfs attrib, and "unknown" when there
is no sysfs attrib at all.
- Use sysfs_read_attr() to retrieve domain values
- Change INT32_MAX to INT_MAX.
v5:
- space out ndctl_persistence_domain for future attributes
v4:
- change enum ndctl_persistence to enum ndctl_persistence_domain
v3:
- fixed up return types per Ross's comments
- removed persistence_domain for bus and calculate on the fly per Dan's comment
v2:
- Simplied scanning of persistence domain from Ross's comments.
ndctl/lib/libndctl.c | 42 ++++++++++++++++++++++++++++++++++++++++++
ndctl/lib/libndctl.sym | 2 ++
ndctl/libndctl.h | 14 ++++++++++++++
ndctl/list.c | 20 ++++++++++++++++++++
4 files changed, 78 insertions(+)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index a165e697..2a20dd16 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -180,6 +180,7 @@ struct ndctl_region {
} iset;
FILE *badblocks;
struct badblock bb;
+ enum ndctl_persistence_domain persistence_domain;
};
/**
@@ -916,6 +917,22 @@ NDCTL_EXPORT struct ndctl_bus *ndctl_bus_get_by_provider(struct ndctl_ctx *ctx,
return NULL;
}
+NDCTL_EXPORT enum ndctl_persistence_domain
+ndctl_bus_get_persistence_domain(struct ndctl_bus *bus)
+{
+ struct ndctl_region *region;
+ enum ndctl_persistence_domain pd = PERSISTENCE_UNINIT;
+
+ /* iterate through region to get the region persistence domain */
+ ndctl_region_foreach(bus, region) {
+ /* we are looking for the least persistence domain */
+ if (pd < region->persistence_domain)
+ pd = region->persistence_domain;
+ }
+
+ return pd;
+}
+
NDCTL_EXPORT struct ndctl_btt *ndctl_region_get_btt_seed(struct ndctl_region *region)
{
struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
@@ -1755,6 +1772,18 @@ static int region_set_type(struct ndctl_region *region, char *path)
return 0;
}
+static enum ndctl_persistence_domain region_get_pd_type(char *name)
+{
+ if (strncmp("cpu_cache", name, 9) == 0)
+ return PERSISTENCE_CPU_CACHE;
+ else if (strncmp("memory_controller", name, 17) == 0)
+ return PERSISTENCE_MEM_CTRL;
+ else if (strncmp("none", name, 4) == 0)
+ return PERSISTENCE_NONE;
+ else
+ return PERSISTENCE_UNKNOWN;
+}
+
static void *add_region(void *parent, int id, const char *region_base)
{
char buf[SYSFS_ATTR_SIZE];
@@ -1830,6 +1859,13 @@ static void *add_region(void *parent, int id, const char *region_base)
list_add(&bus->regions, ®ion->list);
+ /* get the persistence domain attrib */
+ sprintf(path, "%s/persistence_domain", region_base);
+ if (sysfs_read_attr(ctx, path, buf) < 0)
+ region->persistence_domain = PERSISTENCE_UNKNOWN;
+ else
+ region->persistence_domain = region_get_pd_type(buf);
+
free(path);
return region;
@@ -2093,6 +2129,12 @@ NDCTL_EXPORT struct badblock *ndctl_region_get_first_badblock(struct ndctl_regio
return ndctl_region_get_next_badblock(region);
}
+NDCTL_EXPORT enum ndctl_persistence_domain
+ndctl_region_get_persistence_domain(struct ndctl_region *region)
+{
+ return region->persistence_domain;
+}
+
static struct nd_cmd_vendor_tail *to_vendor_tail(struct ndctl_cmd *cmd)
{
struct nd_cmd_vendor_tail *tail = (struct nd_cmd_vendor_tail *)
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 21276614..3209aefe 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -350,4 +350,6 @@ global:
ndctl_dimm_cmd_new_ack_shutdown_count;
ndctl_region_get_numa_node;
ndctl_dimm_fw_update_supported;
+ ndctl_region_get_persistence_domain;
+ ndctl_bus_get_persistence_domain;
} LIBNDCTL_14;
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index f3a27411..f79e903b 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -18,6 +18,7 @@
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
+#include <limits.h>
#ifdef HAVE_LIBUUID
#include <uuid/uuid.h>
@@ -115,6 +116,8 @@ int ndctl_bus_is_cmd_supported(struct ndctl_bus *bus, int cmd);
unsigned int ndctl_bus_get_revision(struct ndctl_bus *bus);
unsigned int ndctl_bus_get_id(struct ndctl_bus *bus);
const char *ndctl_bus_get_provider(struct ndctl_bus *bus);
+enum ndctl_persistence_domain ndctl_bus_get_persistence_domain(
+ struct ndctl_bus *bus);
int ndctl_bus_wait_probe(struct ndctl_bus *bus);
int ndctl_bus_wait_for_scrub_completion(struct ndctl_bus *bus);
unsigned int ndctl_bus_get_scrub_count(struct ndctl_bus *bus);
@@ -305,6 +308,15 @@ struct badblock {
unsigned long long offset;
unsigned int len;
};
+
+enum ndctl_persistence_domain {
+ PERSISTENCE_UNINIT = -1,
+ PERSISTENCE_NONE = 0,
+ PERSISTENCE_MEM_CTRL = 10,
+ PERSISTENCE_CPU_CACHE = 20,
+ PERSISTENCE_UNKNOWN = INT_MAX,
+};
+
struct ndctl_region;
struct ndctl_region *ndctl_region_get_first(struct ndctl_bus *bus);
struct ndctl_region *ndctl_region_get_next(struct ndctl_region *region);
@@ -347,6 +359,8 @@ struct ndctl_region *ndctl_bus_get_region_by_physical_address(struct ndctl_bus *
for (dimm = ndctl_region_get_first_dimm(region); \
dimm != NULL; \
dimm = ndctl_region_get_next_dimm(region, dimm))
+enum ndctl_persistence_domain ndctl_region_get_persistence_domain(
+ struct ndctl_region *region);
int ndctl_region_is_enabled(struct ndctl_region *region);
int ndctl_region_enable(struct ndctl_region *region);
int ndctl_region_disable_invalidate(struct ndctl_region *region);
diff --git a/ndctl/list.c b/ndctl/list.c
index fe8036ea..6cf7c393 100644
--- a/ndctl/list.c
+++ b/ndctl/list.c
@@ -73,6 +73,7 @@ static struct json_object *region_to_json(struct ndctl_region *region,
struct ndctl_interleave_set *iset;
struct ndctl_mapping *mapping;
unsigned int bb_count = 0;
+ enum ndctl_persistence_domain pd;
int numa;
if (!jregion)
@@ -174,6 +175,25 @@ static struct json_object *region_to_json(struct ndctl_region *region,
if ((flags & UTIL_JSON_MEDIA_ERRORS) && jbbs)
json_object_object_add(jregion, "badblocks", jbbs);
+ pd = ndctl_region_get_persistence_domain(region);
+ switch (pd) {
+ case PERSISTENCE_CPU_CACHE:
+ jobj = json_object_new_string("cpu_cache");
+ break;
+ case PERSISTENCE_MEM_CTRL:
+ jobj = json_object_new_string("memory_controller");
+ break;
+ case PERSISTENCE_NONE:
+ jobj = json_object_new_string("none");
+ break;
+ default:
+ jobj = json_object_new_string("unknown");
+ break;
+ }
+
+ if (jobj)
+ json_object_object_add(jregion, "persistence_domain", jobj);
+
return jregion;
err:
fail("\n");
4 years, 3 months
回复:新常态下企业劳动关系发展趋势
by 秦主任
---- 原邮件信息 -----
发件人:秦主任<awkhsasm(a)lgq.com>
收件人:linux-nvdimm <linux-nvdimm(a)lists.01.org>;
4 years, 3 months