[4.18-stable PATCH] acpi, nfit: Fix Address Range Scrub completion tracking
by Dan Williams
commit d3abaf43bab8d5b0a3c6b982100d9e2be96de4ad upstream.
The Address Range Scrub implementation tried to skip running scrubs
against ranges that were already scrubbed by the BIOS. Unfortunately
that support also resulted in early scrub completions as evidenced by
this debug output from nfit_test:
nd_region region9: ARS: range 1 short complete
nd_region region3: ARS: range 1 short complete
nd_region region4: ARS: range 2 ARS start (0)
nd_region region4: ARS: range 2 short complete
...i.e. completions without any indications that the scrub was started.
This state of affairs was hard to see in the code due to the
proliferation of state bits and mistakenly trying to track done state
per-range when the completion is a global property of the bus.
So, kill the four ARS state bits (ARS_REQ, ARS_REQ_REDO, ARS_DONE, and
ARS_SHORT), and replace them with just 2 request flags ARS_REQ_SHORT and
ARS_REQ_LONG. The implementation will still complete and reap the
results of BIOS initiated ARS, but it will not attempt to use that
information to affect the completion status of scrubbing the ranges from
a Linux perspective.
Instead, try to synchronously run a short ARS per range at init time and
schedule a long scrub in the background. If ARS is busy with an ARS
request, schedule both a short and a long scrub for when ARS returns to
idle. This logic also satisfies the intent of what ARS_REQ_REDO was
trying to achieve. The new rule is that the REQ flag stays set until the
next successful ars_start() for that range.
With the new policy that the REQ flags are not cleared until the next
start, the implementation no longer loses requests as can be seen from
the following log:
nd_region region3: ARS: range 1 ARS start short (0)
nd_region region9: ARS: range 1 ARS start short (0)
nd_region region3: ARS: range 1 complete
nd_region region4: ARS: range 2 ARS start short (0)
nd_region region9: ARS: range 1 complete
nd_region region9: ARS: range 1 ARS start long (0)
nd_region region4: ARS: range 2 complete
nd_region region3: ARS: range 1 ARS start long (0)
nd_region region9: ARS: range 1 complete
nd_region region3: ARS: range 1 complete
nd_region region4: ARS: range 2 ARS start long (0)
nd_region region4: ARS: range 2 complete
...note that the nfit_test emulated driver provides 2 buses, that is why
some of the range indices are duplicated. Notice that each range
now successfully completes a short and long scrub.
Cc: <stable(a)vger.kernel.org>
Fixes: 14c73f997a5e ("nfit, address-range-scrub: introduce nfit_spa->ars_state")
Fixes: cc3d3458d46f ("acpi/nfit: queue issuing of ars when an uc error...")
Reported-by: Jacek Zloch <jacek.zloch(a)intel.com>
Reported-by: Krzysztof Rusocki <krzysztof.rusocki(a)intel.com>
Reviewed-by: Dave Jiang <dave.jiang(a)intel.com>
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
drivers/acpi/nfit/core.c | 163 +++++++++++++++++++++++++++-------------------
drivers/acpi/nfit/nfit.h | 9 +--
2 files changed, 101 insertions(+), 71 deletions(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 7c479002e798..c0db96e8a81a 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -2456,7 +2456,8 @@ static int ars_get_cap(struct acpi_nfit_desc *acpi_desc,
return cmd_rc;
}
-static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa)
+static int ars_start(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_spa *nfit_spa, enum nfit_ars_state req_type)
{
int rc;
int cmd_rc;
@@ -2467,7 +2468,7 @@ static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa
memset(&ars_start, 0, sizeof(ars_start));
ars_start.address = spa->address;
ars_start.length = spa->length;
- if (test_bit(ARS_SHORT, &nfit_spa->ars_state))
+ if (req_type == ARS_REQ_SHORT)
ars_start.flags = ND_ARS_RETURN_PREV_DATA;
if (nfit_spa_type(spa) == NFIT_SPA_PM)
ars_start.type = ND_ARS_PERSISTENT;
@@ -2524,6 +2525,15 @@ static void ars_complete(struct acpi_nfit_desc *acpi_desc,
struct nd_region *nd_region = nfit_spa->nd_region;
struct device *dev;
+ lockdep_assert_held(&acpi_desc->init_mutex);
+ /*
+ * Only advance the ARS state for ARS runs initiated by the
+ * kernel, ignore ARS results from BIOS initiated runs for scrub
+ * completion tracking.
+ */
+ if (acpi_desc->scrub_spa != nfit_spa)
+ return;
+
if ((ars_status->address >= spa->address && ars_status->address
< spa->address + spa->length)
|| (ars_status->address < spa->address)) {
@@ -2543,23 +2553,13 @@ static void ars_complete(struct acpi_nfit_desc *acpi_desc,
} else
return;
- if (test_bit(ARS_DONE, &nfit_spa->ars_state))
- return;
-
- if (!test_and_clear_bit(ARS_REQ, &nfit_spa->ars_state))
- return;
-
+ acpi_desc->scrub_spa = NULL;
if (nd_region) {
dev = nd_region_dev(nd_region);
nvdimm_region_notify(nd_region, NVDIMM_REVALIDATE_POISON);
} else
dev = acpi_desc->dev;
-
- dev_dbg(dev, "ARS: range %d %s complete\n", spa->range_index,
- test_bit(ARS_SHORT, &nfit_spa->ars_state)
- ? "short" : "long");
- clear_bit(ARS_SHORT, &nfit_spa->ars_state);
- set_bit(ARS_DONE, &nfit_spa->ars_state);
+ dev_dbg(dev, "ARS: range %d complete\n", spa->range_index);
}
static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc)
@@ -2840,46 +2840,55 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc)
return 0;
}
-static int ars_register(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa,
- int *query_rc)
+static int ars_register(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_spa *nfit_spa)
{
- int rc = *query_rc;
+ int rc;
- if (no_init_ars)
+ if (no_init_ars || test_bit(ARS_FAILED, &nfit_spa->ars_state))
return acpi_nfit_register_region(acpi_desc, nfit_spa);
- set_bit(ARS_REQ, &nfit_spa->ars_state);
- set_bit(ARS_SHORT, &nfit_spa->ars_state);
+ set_bit(ARS_REQ_SHORT, &nfit_spa->ars_state);
+ set_bit(ARS_REQ_LONG, &nfit_spa->ars_state);
- switch (rc) {
+ switch (acpi_nfit_query_poison(acpi_desc)) {
case 0:
case -EAGAIN:
- rc = ars_start(acpi_desc, nfit_spa);
- if (rc == -EBUSY) {
- *query_rc = rc;
+ rc = ars_start(acpi_desc, nfit_spa, ARS_REQ_SHORT);
+ /* shouldn't happen, try again later */
+ if (rc == -EBUSY)
break;
- } else if (rc == 0) {
- rc = acpi_nfit_query_poison(acpi_desc);
- } else {
+ if (rc) {
set_bit(ARS_FAILED, &nfit_spa->ars_state);
break;
}
- if (rc == -EAGAIN)
- clear_bit(ARS_SHORT, &nfit_spa->ars_state);
- else if (rc == 0)
- ars_complete(acpi_desc, nfit_spa);
+ clear_bit(ARS_REQ_SHORT, &nfit_spa->ars_state);
+ rc = acpi_nfit_query_poison(acpi_desc);
+ if (rc)
+ break;
+ acpi_desc->scrub_spa = nfit_spa;
+ ars_complete(acpi_desc, nfit_spa);
+ /*
+ * If ars_complete() says we didn't complete the
+ * short scrub, we'll try again with a long
+ * request.
+ */
+ acpi_desc->scrub_spa = NULL;
break;
case -EBUSY:
+ case -ENOMEM:
case -ENOSPC:
+ /*
+ * BIOS was using ARS, wait for it to complete (or
+ * resources to become available) and then perform our
+ * own scrubs.
+ */
break;
default:
set_bit(ARS_FAILED, &nfit_spa->ars_state);
break;
}
- if (test_and_clear_bit(ARS_DONE, &nfit_spa->ars_state))
- set_bit(ARS_REQ, &nfit_spa->ars_state);
-
return acpi_nfit_register_region(acpi_desc, nfit_spa);
}
@@ -2901,6 +2910,8 @@ static unsigned int __acpi_nfit_scrub(struct acpi_nfit_desc *acpi_desc,
struct device *dev = acpi_desc->dev;
struct nfit_spa *nfit_spa;
+ lockdep_assert_held(&acpi_desc->init_mutex);
+
if (acpi_desc->cancel)
return 0;
@@ -2924,21 +2935,49 @@ static unsigned int __acpi_nfit_scrub(struct acpi_nfit_desc *acpi_desc,
ars_complete_all(acpi_desc);
list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+ enum nfit_ars_state req_type;
+ int rc;
+
if (test_bit(ARS_FAILED, &nfit_spa->ars_state))
continue;
- if (test_bit(ARS_REQ, &nfit_spa->ars_state)) {
- int rc = ars_start(acpi_desc, nfit_spa);
-
- clear_bit(ARS_DONE, &nfit_spa->ars_state);
- dev = nd_region_dev(nfit_spa->nd_region);
- dev_dbg(dev, "ARS: range %d ARS start (%d)\n",
- nfit_spa->spa->range_index, rc);
- if (rc == 0 || rc == -EBUSY)
- return 1;
- dev_err(dev, "ARS: range %d ARS failed (%d)\n",
- nfit_spa->spa->range_index, rc);
- set_bit(ARS_FAILED, &nfit_spa->ars_state);
+
+ /* prefer short ARS requests first */
+ if (test_bit(ARS_REQ_SHORT, &nfit_spa->ars_state))
+ req_type = ARS_REQ_SHORT;
+ else if (test_bit(ARS_REQ_LONG, &nfit_spa->ars_state))
+ req_type = ARS_REQ_LONG;
+ else
+ continue;
+ rc = ars_start(acpi_desc, nfit_spa, req_type);
+
+ dev = nd_region_dev(nfit_spa->nd_region);
+ dev_dbg(dev, "ARS: range %d ARS start %s (%d)\n",
+ nfit_spa->spa->range_index,
+ req_type == ARS_REQ_SHORT ? "short" : "long",
+ rc);
+ /*
+ * Hmm, we raced someone else starting ARS? Try again in
+ * a bit.
+ */
+ if (rc == -EBUSY)
+ return 1;
+ if (rc == 0) {
+ dev_WARN_ONCE(dev, acpi_desc->scrub_spa,
+ "scrub start while range %d active\n",
+ acpi_desc->scrub_spa->spa->range_index);
+ clear_bit(req_type, &nfit_spa->ars_state);
+ acpi_desc->scrub_spa = nfit_spa;
+ /*
+ * Consider this spa last for future scrub
+ * requests
+ */
+ list_move_tail(&nfit_spa->list, &acpi_desc->spas);
+ return 1;
}
+
+ dev_err(dev, "ARS: range %d ARS failed (%d)\n",
+ nfit_spa->spa->range_index, rc);
+ set_bit(ARS_FAILED, &nfit_spa->ars_state);
}
return 0;
}
@@ -2994,6 +3033,7 @@ static void acpi_nfit_init_ars(struct acpi_nfit_desc *acpi_desc,
struct nd_cmd_ars_cap ars_cap;
int rc;
+ set_bit(ARS_FAILED, &nfit_spa->ars_state);
memset(&ars_cap, 0, sizeof(ars_cap));
rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa);
if (rc < 0)
@@ -3010,16 +3050,14 @@ static void acpi_nfit_init_ars(struct acpi_nfit_desc *acpi_desc,
nfit_spa->clear_err_unit = ars_cap.clear_err_unit;
acpi_desc->max_ars = max(nfit_spa->max_ars, acpi_desc->max_ars);
clear_bit(ARS_FAILED, &nfit_spa->ars_state);
- set_bit(ARS_REQ, &nfit_spa->ars_state);
}
static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
{
struct nfit_spa *nfit_spa;
- int rc, query_rc;
+ int rc;
list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
- set_bit(ARS_FAILED, &nfit_spa->ars_state);
switch (nfit_spa_type(nfit_spa->spa)) {
case NFIT_SPA_VOLATILE:
case NFIT_SPA_PM:
@@ -3028,20 +3066,12 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
}
}
- /*
- * Reap any results that might be pending before starting new
- * short requests.
- */
- query_rc = acpi_nfit_query_poison(acpi_desc);
- if (query_rc == 0)
- ars_complete_all(acpi_desc);
-
list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
switch (nfit_spa_type(nfit_spa->spa)) {
case NFIT_SPA_VOLATILE:
case NFIT_SPA_PM:
/* register regions and kick off initial ARS run */
- rc = ars_register(acpi_desc, nfit_spa, &query_rc);
+ rc = ars_register(acpi_desc, nfit_spa);
if (rc)
return rc;
break;
@@ -3236,7 +3266,8 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
return 0;
}
-int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags)
+int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc,
+ enum nfit_ars_state req_type)
{
struct device *dev = acpi_desc->dev;
int scheduled = 0, busy = 0;
@@ -3256,13 +3287,10 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags)
if (test_bit(ARS_FAILED, &nfit_spa->ars_state))
continue;
- if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state))
+ if (test_and_set_bit(req_type, &nfit_spa->ars_state))
busy++;
- else {
- if (test_bit(ARS_SHORT, &flags))
- set_bit(ARS_SHORT, &nfit_spa->ars_state);
+ else
scheduled++;
- }
}
if (scheduled) {
sched_ars(acpi_desc);
@@ -3448,10 +3476,11 @@ static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle)
static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle)
{
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev);
- unsigned long flags = (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON) ?
- 0 : 1 << ARS_SHORT;
- acpi_nfit_ars_rescan(acpi_desc, flags);
+ if (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON)
+ acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG);
+ else
+ acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_SHORT);
}
void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event)
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
index a97ff42fe311..02c10de50386 100644
--- a/drivers/acpi/nfit/nfit.h
+++ b/drivers/acpi/nfit/nfit.h
@@ -118,9 +118,8 @@ enum nfit_dimm_notifiers {
};
enum nfit_ars_state {
- ARS_REQ,
- ARS_DONE,
- ARS_SHORT,
+ ARS_REQ_SHORT,
+ ARS_REQ_LONG,
ARS_FAILED,
};
@@ -197,6 +196,7 @@ struct acpi_nfit_desc {
struct device *dev;
u8 ars_start_flags;
struct nd_cmd_ars_status *ars_status;
+ struct nfit_spa *scrub_spa;
struct delayed_work dwork;
struct list_head list;
struct kernfs_node *scrub_count_state;
@@ -251,7 +251,8 @@ struct nfit_blk {
extern struct list_head acpi_descs;
extern struct mutex acpi_desc_lock;
-int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags);
+int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc,
+ enum nfit_ars_state req_type);
#ifdef CONFIG_X86_MCE
void nfit_mce_register(void);
2 years, 2 months
Hacking Alert! You account was hacked
by linux-nvdimm@lists.01.org
Dear user of lists.01.org!
I am a spyware software developer.
Your account has been hacked by me in the summer of 2018.
I understand that it is hard to believe, but here is my evidence (I sent you this email from your account).
The hacking was carried out using a hardware vulnerability through which you went online (Cisco router, vulnerability CVE-2018-0296).
I went around the security system in the router, installed an exploit there.
When you went online, my exploit downloaded my malicious code (rootkit) to your device.
This is driver software, I constantly updated it, so your antivirus is silent all time.
Since then I have been following you (I can connect to your device via the VNC protocol).
That is, I can see absolutely everything that you do, view and download your files and any data to yourself.
I also have access to the camera on your device, and I periodically take photos and videos with you.
At the moment, I have harvested a solid dirt... on you...
I saved all your email and chats from your messangers. I also saved the entire history of the sites you visit.
I note that it is useless to change the passwords. My malware update passwords from your accounts every times.
I know what you like hard funs (adult sites).
Oh, yes .. I'm know your secret life, which you are hiding from everyone.
Oh my God, what are your like... I saw THIS ... Oh, you dirty naughty person ... :)
I took photos and videos of your most passionate funs with adult content, and synchronized them in real time with the image of your camera.
Believe it turned out very high quality!
So, to the business!
I'm sure you don't want to show these files and visiting history to all your contacts.
Transfer $830 to my Bitcoin cryptocurrency wallet: 19qL8vdRtk5xJcGNVk3WruuSyitVfSAy7f
Just copy and paste the wallet number when transferring.
If you do not know how to do this - ask Google.
My system automatically recognizes the translation.
As soon as the specified amount is received, all your data will be destroyed from my server, and the rootkit will be automatically removed from your system.
Do not worry, I really will delete everything, since I am 'working' with many people who have fallen into your position.
You will only have to inform your provider about the vulnerabilities in the router so that other hackers will not use it.
Since opening this letter you have 48 hours.
If funds not will be received, after the specified time has elapsed, the disk of your device will be formatted,
and from my server will automatically send email and sms to all your contacts with compromising material.
I advise you to remain prudent and not engage in nonsense (all files on my server).
Good luck!
2 years, 2 months
Security Alert. You account has been hacked. Password must be need changed.
by linux-nvdimm@lists.01.org
Dear user of lists.01.org!
I am a spyware software developer.
Your account has been hacked by me in the summer of 2018.
I understand that it is hard to believe, but here is my evidence (I sent you this email from your account).
The hacking was carried out using a hardware vulnerability through which you went online (Cisco router, vulnerability CVE-2018-0296).
I went around the security system in the router, installed an exploit there.
When you went online, my exploit downloaded my malicious code (rootkit) to your device.
This is driver software, I constantly updated it, so your antivirus is silent all time.
Since then I have been following you (I can connect to your device via the VNC protocol).
That is, I can see absolutely everything that you do, view and download your files and any data to yourself.
I also have access to the camera on your device, and I periodically take photos and videos with you.
At the moment, I have harvested a solid dirt... on you...
I saved all your email and chats from your messangers. I also saved the entire history of the sites you visit.
I note that it is useless to change the passwords. My malware update passwords from your accounts every times.
I know what you like hard funs (adult sites).
Oh, yes .. I'm know your secret life, which you are hiding from everyone.
Oh my God, what are your like... I saw THIS ... Oh, you dirty naughty person ... :)
I took photos and videos of your most passionate funs with adult content, and synchronized them in real time with the image of your camera.
Believe it turned out very high quality!
So, to the business!
I'm sure you don't want to show these files and visiting history to all your contacts.
Transfer $822 to my Bitcoin cryptocurrency wallet: 19qL8vdRtk5xJcGNVk3WruuSyitVfSAy7f
Just copy and paste the wallet number when transferring.
If you do not know how to do this - ask Google.
My system automatically recognizes the translation.
As soon as the specified amount is received, all your data will be destroyed from my server, and the rootkit will be automatically removed from your system.
Do not worry, I really will delete everything, since I am 'working' with many people who have fallen into your position.
You will only have to inform your provider about the vulnerabilities in the router so that other hackers will not use it.
Since opening this letter you have 48 hours.
If funds not will be received, after the specified time has elapsed, the disk of your device will be formatted,
and from my server will automatically send email and sms to all your contacts with compromising material.
I advise you to remain prudent and not engage in nonsense (all files on my server).
Good luck!
2 years, 2 months
[linux-nvdimm:for-5.0/nvdimm-security 2/17] arch/powerpc//platforms/pseries/papr_scm.c:219:14: error: too few arguments to function 'nvdimm_create'
by kbuild test robot
tree: https://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git for-5.0/nvdimm-security
head: bddbf9de5dcd455addac2862e8bc3f41881d29f7
commit: 625fea4fc86b6dca5a43b5882f23f537088571a6 [2/17] acpi/nfit, libnvdimm: Store dimm id as a member to struct nvdimm
config: powerpc64-allyesconfig (attached as .config)
compiler: powerpc64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout 625fea4fc86b6dca5a43b5882f23f537088571a6
# save the attached .config to linux build tree
GCC_VERSION=7.2.0 make.cross ARCH=powerpc64
Note: the linux-nvdimm/for-5.0/nvdimm-security HEAD bddbf9de5dcd455addac2862e8bc3f41881d29f7 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
arch/powerpc//platforms/pseries/papr_scm.c: In function 'papr_scm_nvdimm_init':
>> arch/powerpc//platforms/pseries/papr_scm.c:219:14: error: too few arguments to function 'nvdimm_create'
p->nvdimm = nvdimm_create(p->bus, p, papr_scm_dimm_groups,
^~~~~~~~~~~~~
In file included from arch/powerpc//platforms/pseries/papr_scm.c:12:0:
include/linux/libnvdimm.h:178:16: note: declared here
struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
^~~~~~~~~~~~~
vim +/nvdimm_create +219 arch/powerpc//platforms/pseries/papr_scm.c
b5beae5e Oliver O'Halloran 2018-10-15 193
b5beae5e Oliver O'Halloran 2018-10-15 194 static int papr_scm_nvdimm_init(struct papr_scm_priv *p)
b5beae5e Oliver O'Halloran 2018-10-15 195 {
b5beae5e Oliver O'Halloran 2018-10-15 196 struct device *dev = &p->pdev->dev;
b5beae5e Oliver O'Halloran 2018-10-15 197 struct nd_mapping_desc mapping;
b5beae5e Oliver O'Halloran 2018-10-15 198 struct nd_region_desc ndr_desc;
b5beae5e Oliver O'Halloran 2018-10-15 199 unsigned long dimm_flags;
b5beae5e Oliver O'Halloran 2018-10-15 200
b5beae5e Oliver O'Halloran 2018-10-15 201 p->bus_desc.ndctl = papr_scm_ndctl;
b5beae5e Oliver O'Halloran 2018-10-15 202 p->bus_desc.module = THIS_MODULE;
b5beae5e Oliver O'Halloran 2018-10-15 203 p->bus_desc.of_node = p->pdev->dev.of_node;
b5beae5e Oliver O'Halloran 2018-10-15 204 p->bus_desc.attr_groups = bus_attr_groups;
b5beae5e Oliver O'Halloran 2018-10-15 205 p->bus_desc.provider_name = kstrdup(p->pdev->name, GFP_KERNEL);
b5beae5e Oliver O'Halloran 2018-10-15 206
b5beae5e Oliver O'Halloran 2018-10-15 207 if (!p->bus_desc.provider_name)
b5beae5e Oliver O'Halloran 2018-10-15 208 return -ENOMEM;
b5beae5e Oliver O'Halloran 2018-10-15 209
b5beae5e Oliver O'Halloran 2018-10-15 210 p->bus = nvdimm_bus_register(NULL, &p->bus_desc);
b5beae5e Oliver O'Halloran 2018-10-15 211 if (!p->bus) {
b5beae5e Oliver O'Halloran 2018-10-15 212 dev_err(dev, "Error creating nvdimm bus %pOF\n", p->dn);
b5beae5e Oliver O'Halloran 2018-10-15 213 return -ENXIO;
b5beae5e Oliver O'Halloran 2018-10-15 214 }
b5beae5e Oliver O'Halloran 2018-10-15 215
b5beae5e Oliver O'Halloran 2018-10-15 216 dimm_flags = 0;
b5beae5e Oliver O'Halloran 2018-10-15 217 set_bit(NDD_ALIASING, &dimm_flags);
b5beae5e Oliver O'Halloran 2018-10-15 218
b5beae5e Oliver O'Halloran 2018-10-15 @219 p->nvdimm = nvdimm_create(p->bus, p, papr_scm_dimm_groups,
b5beae5e Oliver O'Halloran 2018-10-15 220 dimm_flags, PAPR_SCM_DIMM_CMD_MASK, 0, NULL);
b5beae5e Oliver O'Halloran 2018-10-15 221 if (!p->nvdimm) {
b5beae5e Oliver O'Halloran 2018-10-15 222 dev_err(dev, "Error creating DIMM object for %pOF\n", p->dn);
b5beae5e Oliver O'Halloran 2018-10-15 223 goto err;
b5beae5e Oliver O'Halloran 2018-10-15 224 }
b5beae5e Oliver O'Halloran 2018-10-15 225
b5beae5e Oliver O'Halloran 2018-10-15 226 /* now add the region */
b5beae5e Oliver O'Halloran 2018-10-15 227
b5beae5e Oliver O'Halloran 2018-10-15 228 memset(&mapping, 0, sizeof(mapping));
b5beae5e Oliver O'Halloran 2018-10-15 229 mapping.nvdimm = p->nvdimm;
b5beae5e Oliver O'Halloran 2018-10-15 230 mapping.start = 0;
b5beae5e Oliver O'Halloran 2018-10-15 231 mapping.size = p->blocks * p->block_size; // XXX: potential overflow?
b5beae5e Oliver O'Halloran 2018-10-15 232
b5beae5e Oliver O'Halloran 2018-10-15 233 memset(&ndr_desc, 0, sizeof(ndr_desc));
b5beae5e Oliver O'Halloran 2018-10-15 234 ndr_desc.attr_groups = region_attr_groups;
b5beae5e Oliver O'Halloran 2018-10-15 235 ndr_desc.numa_node = dev_to_node(&p->pdev->dev);
b5beae5e Oliver O'Halloran 2018-10-15 236 ndr_desc.res = &p->res;
b5beae5e Oliver O'Halloran 2018-10-15 237 ndr_desc.of_node = p->dn;
b5beae5e Oliver O'Halloran 2018-10-15 238 ndr_desc.provider_data = p;
b5beae5e Oliver O'Halloran 2018-10-15 239 ndr_desc.mapping = &mapping;
b5beae5e Oliver O'Halloran 2018-10-15 240 ndr_desc.num_mappings = 1;
b5beae5e Oliver O'Halloran 2018-10-15 241 ndr_desc.nd_set = &p->nd_set;
b5beae5e Oliver O'Halloran 2018-10-15 242 set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
b5beae5e Oliver O'Halloran 2018-10-15 243
b5beae5e Oliver O'Halloran 2018-10-15 244 p->region = nvdimm_pmem_region_create(p->bus, &ndr_desc);
b5beae5e Oliver O'Halloran 2018-10-15 245 if (!p->region) {
b5beae5e Oliver O'Halloran 2018-10-15 246 dev_err(dev, "Error registering region %pR from %pOF\n",
b5beae5e Oliver O'Halloran 2018-10-15 247 ndr_desc.res, p->dn);
b5beae5e Oliver O'Halloran 2018-10-15 248 goto err;
b5beae5e Oliver O'Halloran 2018-10-15 249 }
b5beae5e Oliver O'Halloran 2018-10-15 250
b5beae5e Oliver O'Halloran 2018-10-15 251 return 0;
b5beae5e Oliver O'Halloran 2018-10-15 252
:::::: The code at line 219 was first introduced by commit
:::::: b5beae5e224f1c72c4482b0ab36fc3d89481a6b2 powerpc/pseries: Add driver for PAPR SCM regions
:::::: TO: Oliver O'Halloran <oohall(a)gmail.com>
:::::: CC: Michael Ellerman <mpe(a)ellerman.id.au>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
2 years, 2 months
nfit_test.ko.xz needs unknown symbol ....
by Dorau, Lukasz
Hi,
I am building and installing the linux kernel from the 'libnvdimm-for-next' branch at git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git with the 'nfit_test' kernel module.
I have set in the .config file:
CONFIG_X86_PMEM_LEGACY=m
CONFIG_ZONE_DEVICE=y
CONFIG_LIBNVDIMM=m
CONFIG_BLK_DEV_PMEM=m
CONFIG_ND_BLK=m
CONFIG_BTT=y
CONFIG_NVDIMM_PFN=y
CONFIG_NVDIMM_DAX=y
CONFIG_DEV_DAX_PMEM=m
I ran:
$ make
$ make M=tools/testing/nvdimm
$ sudo make M=tools/testing/nvdimm modules_install
$ sudo make modules_install
and I got:
[...]
DEPMOD 4.19.0-rc4-nfit_test
depmod: WARNING: /lib/modules/4.19.0-rc4-nfit_test/extra/test/nfit_test.ko.xz needs unknown symbol libnvdimm_test
depmod: WARNING: /lib/modules/4.19.0-rc4-nfit_test/extra/test/nfit_test.ko.xz needs unknown symbol acpi_nfit_test
depmod: WARNING: /lib/modules/4.19.0-rc4-nfit_test/extra/test/nfit_test.ko.xz needs unknown symbol pmem_test
depmod: WARNING: /lib/modules/4.19.0-rc4-nfit_test/extra/test/nfit_test.ko.xz needs unknown symbol device_dax_test
Does anyone know what could be wrong here?
--
Lukasz
2 years, 2 months
[PATCH] ndctl: fix zero-labels to handle firmware error properly
by Toshi Kani
ndctl zero-labels completes with a large number of zeroed nmems when
it fails to do zeroing on a protected NVDIMM.
# ndctl zero-labels nmem1
zeroed 65504 nmems
do_cmd() called from ndctl_dimm_zero_labels() sets a transfer size to
rc when FW status is non-zero. This transfer size gets mistreated as
zeroed nmems count in the end.
Fix ndctl_dimm_zero_labels() to handle this FW error case properly.
Reported-by: Robert Elliott <elliott(a)hpe.com>
Signed-off-by: Toshi Kani <toshi.kani(a)hpe.com>
Cc: Vishal Verma <vishal.l.verma(a)intel.com>
Cc: Dan Williams <dan.j.williams(a)intel.com>
---
ndctl/lib/dimm.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c
index 5e41734..79e2ca0 100644
--- a/ndctl/lib/dimm.c
+++ b/ndctl/lib/dimm.c
@@ -537,8 +537,12 @@ NDCTL_EXPORT int ndctl_dimm_zero_labels(struct ndctl_dimm *dimm)
goto out_write;
}
rc = ndctl_cmd_submit(cmd_write);
- if (rc || ndctl_cmd_get_firmware_status(cmd_write))
+ if (rc < 0)
goto out_write;
+ if (ndctl_cmd_get_firmware_status(cmd_write)) {
+ rc = -ENXIO;
+ goto out_write;
+ }
/*
* If the dimm is already disabled the kernel is not holding a cached
2 years, 2 months
[daxctl PATCH] daxctl: Opt-in to /sys/bus/dax ABI
by Dan Williams
In support of the kernel's conversion of the dax-subsystem from a
'class' to a 'bus', teach the libdaxctl subsystem-layout-specific code
to parse the new layout. The kernel changes do not effect the primary
ndctl use case of putting namespaces into 'dax' mode since that uses
libnvdimm namespace device relative paths, but it does break 'ndctl list
-X' and 'daxctl list'. For that reason the kernel provides a
dax_pmem_compat driver to support the old layout and give time for
userspace components to switch.
Installation of the latest libdaxctl package arranges for a daxctl
configuration file to be dropped in /etc/modprobe.d. The modprobe
configuration blacklists dax_pmem_compat modules and sets the proper
alias for the dax_pmem module. The modprobe configuration upgrades the
default kernel handling to the /sys/bus/dax scheme.
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
daxctl/lib/Makefile.am | 3 ++
daxctl/lib/daxctl.conf | 2 +
daxctl/lib/libdaxctl-private.h | 11 ++++++
daxctl/lib/libdaxctl.c | 70 +++++++++++++++++++++++++++++-----------
ndctl.spec.in | 1 +
util/sysfs.c | 2 +
6 files changed, 68 insertions(+), 21 deletions(-)
create mode 100644 daxctl/lib/daxctl.conf
diff --git a/daxctl/lib/Makefile.am b/daxctl/lib/Makefile.am
index 0167e3995b00..749d54a2e397 100644
--- a/daxctl/lib/Makefile.am
+++ b/daxctl/lib/Makefile.am
@@ -18,6 +18,9 @@ libdaxctl_la_SOURCES =\
libdaxctl_la_LIBADD =\
$(UUID_LIBS)
+daxctlconfdir=$(sysconfdir)/modprobe.d
+daxctlconf_DATA = daxctl.conf
+
EXTRA_DIST += libdaxctl.sym
libdaxctl_la_LDFLAGS = $(AM_LDFLAGS) \
diff --git a/daxctl/lib/daxctl.conf b/daxctl/lib/daxctl.conf
new file mode 100644
index 000000000000..c64a088cbc0b
--- /dev/null
+++ b/daxctl/lib/daxctl.conf
@@ -0,0 +1,2 @@
+blacklist dax_pmem_compat
+alias nd:t7* dax_pmem
diff --git a/daxctl/lib/libdaxctl-private.h b/daxctl/lib/libdaxctl-private.h
index f7667324026f..4a462e7245d2 100644
--- a/daxctl/lib/libdaxctl-private.h
+++ b/daxctl/lib/libdaxctl-private.h
@@ -15,6 +15,17 @@
#define DAXCTL_EXPORT __attribute__ ((visibility("default")))
+enum dax_subsystem {
+ DAX_UNKNOWN,
+ DAX_CLASS,
+ DAX_BUS,
+};
+
+static const char *dax_subsystems[] = {
+ [DAX_CLASS] = "/sys/class/dax",
+ [DAX_BUS] = "/sys/bus/dax/devices",
+};
+
/**
* struct daxctl_region - container for dax_devices
*/
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
index 22f4210a7ea0..c2e3a52d6c7c 100644
--- a/daxctl/lib/libdaxctl.c
+++ b/daxctl/lib/libdaxctl.c
@@ -444,26 +444,38 @@ static void dax_devices_init(struct daxctl_region *region)
{
struct daxctl_ctx *ctx = daxctl_region_get_ctx(region);
char daxdev_fmt[50];
- char *region_path;
+ size_t i;
if (region->devices_init)
return;
region->devices_init = 1;
sprintf(daxdev_fmt, "dax%d.", region->id);
- if (asprintf(®ion_path, "%s/dax", region->region_path) < 0) {
- dbg(ctx, "region path alloc fail\n");
- return;
+ for (i = 0; i < ARRAY_SIZE(dax_subsystems); i++) {
+ char *region_path;
+
+ if (i == DAX_BUS)
+ region_path = region->region_path;
+ else if (i == DAX_CLASS) {
+ if (asprintf(®ion_path, "%s/dax",
+ region->region_path) < 0) {
+ dbg(ctx, "region path alloc fail\n");
+ continue;
+ }
+ } else
+ continue;
+ sysfs_device_parse(ctx, region_path, daxdev_fmt, region,
+ add_dax_dev);
+ if (i == DAX_CLASS)
+ free(region_path);
}
- sysfs_device_parse(ctx, region_path, daxdev_fmt, region, add_dax_dev);
- free(region_path);
}
-static char *dax_region_path(const char *base, const char *device)
+static char *dax_region_path(const char *device, enum dax_subsystem subsys)
{
char *path, *region_path, *c;
- if (asprintf(&path, "%s/%s", base, device) < 0)
+ if (asprintf(&path, "%s/%s", dax_subsystems[subsys], device) < 0)
return NULL;
/* dax_region must be the instance's direct parent */
@@ -472,7 +484,11 @@ static char *dax_region_path(const char *base, const char *device)
if (!region_path)
return NULL;
- /* 'region_path' is now regionX/dax/daxX.Y', trim back to regionX */
+ /*
+ * 'region_path' is now regionX/dax/daxX.Y' (DAX_CLASS), or
+ * regionX/daxX.Y (DAX_BUS), trim it back to the regionX
+ * component
+ */
c = strrchr(region_path, '/');
if (!c) {
free(region_path);
@@ -480,6 +496,9 @@ static char *dax_region_path(const char *base, const char *device)
}
*c = '\0';
+ if (subsys == DAX_BUS)
+ return region_path;
+
c = strrchr(region_path, '/');
if (!c) {
free(region_path);
@@ -490,20 +509,15 @@ static char *dax_region_path(const char *base, const char *device)
return region_path;
}
-static void dax_regions_init(struct daxctl_ctx *ctx)
+static void __dax_regions_init(struct daxctl_ctx *ctx, enum dax_subsystem subsys)
{
- const char *base = "/sys/class/dax";
struct dirent *de;
- DIR *dir;
+ DIR *dir = NULL;
- if (ctx->regions_init)
- return;
-
- ctx->regions_init = 1;
-
- dir = opendir(base);
+ dir = opendir(dax_subsystems[subsys]);
if (!dir) {
- dbg(ctx, "no dax regions found\n");
+ dbg(ctx, "no dax regions found via: %s\n",
+ dax_subsystems[subsys]);
return;
}
@@ -516,7 +530,7 @@ static void dax_regions_init(struct daxctl_ctx *ctx)
continue;
if (sscanf(de->d_name, "dax%d.%d", ®ion_id, &id) != 2)
continue;
- dev_path = dax_region_path(base, de->d_name);
+ dev_path = dax_region_path(de->d_name, subsys);
if (!dev_path) {
err(ctx, "dax region path allocation failure\n");
continue;
@@ -529,6 +543,22 @@ static void dax_regions_init(struct daxctl_ctx *ctx)
closedir(dir);
}
+static void dax_regions_init(struct daxctl_ctx *ctx)
+{
+ size_t i;
+
+ if (ctx->regions_init)
+ return;
+
+ ctx->regions_init = 1;
+
+ for (i = 0; i < ARRAY_SIZE(dax_subsystems); i++) {
+ if (i == DAX_UNKNOWN)
+ continue;
+ __dax_regions_init(ctx, i);
+ }
+}
+
DAXCTL_EXPORT struct daxctl_dev *daxctl_dev_get_first(struct daxctl_region *region)
{
dax_devices_init(region);
diff --git a/ndctl.spec.in b/ndctl.spec.in
index 26396d4abad7..60d9e6fedf71 100644
--- a/ndctl.spec.in
+++ b/ndctl.spec.in
@@ -136,6 +136,7 @@ make check
%defattr(-,root,root)
%doc README.md
%license COPYING licenses/BSD-MIT licenses/CC0
+%config(noreplace) %{_sysconfdir}/modprobe.d/daxctl.conf
%{_libdir}/libdaxctl.so.*
%files -n DNAME
diff --git a/util/sysfs.c b/util/sysfs.c
index 0440fd0f49a3..9f7bc1f4930f 100644
--- a/util/sysfs.c
+++ b/util/sysfs.c
@@ -91,7 +91,7 @@ int __sysfs_device_parse(struct log_ctx *ctx, const char *base_path,
struct dirent *de;
DIR *dir;
- log_dbg(ctx, "base: %s dev: %s\n", base_path, dev_name);
+ log_dbg(ctx, "base: '%s' dev: '%s'\n", base_path, dev_name);
dir = opendir(base_path);
if (!dir) {
log_dbg(ctx, "no \"%s\" devices found\n", dev_name);
2 years, 2 months
[PATCH] libnvdimm: Fix __nd_ioctl() to check error in cmd_rc
by Toshi Kani
ndctl zero-labels completes with a large number of zeroed nmems when
it fails to do zeroing on a protected NVDIMM.
# ndctl zero-labels nmem1
zeroed 65504 nmems
When an ACPI call completes with error, xlat_status() called from
acpi_nfit_ctl() sets error to *cmd_rc. __nd_ioctl(), however, does
not check this error and returns with success.
Fix __nd_ioctl() to check this error in cmd_rc.
Fixes: 006358b35c73a ("libnvdimm: add support for clear poison list and badblocks for device dax")
Reported-by: Robert Elliott <elliott(a)hpe.com>
Signed-off-by: Toshi Kani <toshi.kani(a)hpe.com>
Cc: Dan Williams <dan.j.williams(a)intel.com>
Cc: Vishal Verma <vishal.l.verma(a)intel.com>
Cc: Dave Jiang <dave.jiang(a)intel.com>
Cc: <stable(a)vger.kernel.org>
---
drivers/nvdimm/bus.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index f1fb39921236..af12817d8a02 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -1050,6 +1050,10 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, &cmd_rc);
if (rc < 0)
goto out_unlock;
+ if (cmd_rc < 0) {
+ rc = cmd_rc;
+ goto out_unlock;
+ }
if (!nvdimm && cmd == ND_CMD_CLEAR_ERROR && cmd_rc >= 0) {
struct nd_cmd_clear_error *clear_err = buf;
2 years, 2 months
Question about unit test for acpi_nfit_notify().
by Masayoshi Mizuma
Let me ask a question about unit test for acpi_nfit_notify().
The unit test was introduced by commit c14a868a5a14 ("tools/testing/nvdimm:
unit test for acpi_nfit_notify()"), however, it seems that it doesn't
work currently. When I road the nfit_test.ko, I got the following
message.
nfit_test nfit_test.0: failed to evaluate _FIT
That is because the 2nd argument of __acpi_nfit_notify(), nfit_test,
isn't allocated as nfit_test_resource structure, so
__wrap_acpi_evaluate_object() doesn't do anything, just call
acpi_evaluate_object(). The nfit_test is passed to acpi_evaluate_object()
as the 1st argument, handle. The nfit_test isn't useful for the
handle, so I got the error message.
nfit_test->_fit is allocated as nfit_test_resource structure,
so I thought it is fixed by the change look like as following.
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index cffc2c5a778d..3bae4a879f5f 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -2670,7 +2670,7 @@ static int nfit_test_probe(struct platform_device *pdev)
obj->buffer.length = nfit_test->nfit_size;
obj->buffer.pointer = nfit_test->nfit_buf;
*(nfit_test->_fit) = obj;
- __acpi_nfit_notify(&pdev->dev, nfit_test, 0x80);
+ __acpi_nfit_notify(&pdev->dev, nfit_test->_fit, 0x80);
/* associate dimm devices with nfit_mem data for notification testing */
mutex_lock(&acpi_desc->init_mutex);
However, if so, obj, which is allocated before calling __acpi_nfit_notify(),
gets meaningless...
I would like to fix this issue but I'm confusing now... Am I missing
something? I would applicate if someone could help.
Thanks!
Masa
2 years, 2 months