aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVishal Verma <vishal.l.verma@intel.com>2017-08-30 21:36:02 -0400
committerDan Williams <dan.j.williams@intel.com>2017-08-31 18:05:10 -0400
commit0930a750c35be3c2f5aacebc0d20ddeaf727c208 (patch)
tree9fdf04c2bea121e8d9405e816d1cadfef4389b8c
parent75892004508260df72ed3d319f10d2acd516220e (diff)
libnvdimm: fix potential deadlock while clearing errors
With the ACPI NFIT 'DSM' methods, acpi can be called from IO paths. Specifically, the DSM to clear media errors is called during writes, so that we can provide a writes-fix-errors model. However it is easy to imagine a scenario like: -> write through the nvdimm driver -> acpi allocation -> writeback, causes more IO through the nvdimm driver -> deadlock Fix this by using memalloc_noio_{save,restore}, which sets the GFP_NOIO flag for the current scope when issuing commands/IOs that are expected to clear errors. Cc: <linux-acpi@vger.kernel.org> Cc: <linux-nvdimm@lists.01.org> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Robert Moore <robert.moore@intel.com> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/nvdimm/bus.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 937fafa1886a..a18c2914f4b6 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -11,6 +11,7 @@
11 * General Public License for more details. 11 * General Public License for more details.
12 */ 12 */
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14#include <linux/sched/mm.h>
14#include <linux/vmalloc.h> 15#include <linux/vmalloc.h>
15#include <linux/uaccess.h> 16#include <linux/uaccess.h>
16#include <linux/module.h> 17#include <linux/module.h>
@@ -234,6 +235,7 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
234 struct nd_cmd_clear_error clear_err; 235 struct nd_cmd_clear_error clear_err;
235 struct nd_cmd_ars_cap ars_cap; 236 struct nd_cmd_ars_cap ars_cap;
236 u32 clear_err_unit, mask; 237 u32 clear_err_unit, mask;
238 unsigned int noio_flag;
237 int cmd_rc, rc; 239 int cmd_rc, rc;
238 240
239 if (!nvdimm_bus) 241 if (!nvdimm_bus)
@@ -250,8 +252,10 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
250 memset(&ars_cap, 0, sizeof(ars_cap)); 252 memset(&ars_cap, 0, sizeof(ars_cap));
251 ars_cap.address = phys; 253 ars_cap.address = phys;
252 ars_cap.length = len; 254 ars_cap.length = len;
255 noio_flag = memalloc_noio_save();
253 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, &ars_cap, 256 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, &ars_cap,
254 sizeof(ars_cap), &cmd_rc); 257 sizeof(ars_cap), &cmd_rc);
258 memalloc_noio_restore(noio_flag);
255 if (rc < 0) 259 if (rc < 0)
256 return rc; 260 return rc;
257 if (cmd_rc < 0) 261 if (cmd_rc < 0)
@@ -266,8 +270,10 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
266 memset(&clear_err, 0, sizeof(clear_err)); 270 memset(&clear_err, 0, sizeof(clear_err));
267 clear_err.address = phys; 271 clear_err.address = phys;
268 clear_err.length = len; 272 clear_err.length = len;
273 noio_flag = memalloc_noio_save();
269 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CLEAR_ERROR, &clear_err, 274 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CLEAR_ERROR, &clear_err,
270 sizeof(clear_err), &cmd_rc); 275 sizeof(clear_err), &cmd_rc);
276 memalloc_noio_restore(noio_flag);
271 if (rc < 0) 277 if (rc < 0)
272 return rc; 278 return rc;
273 if (cmd_rc < 0) 279 if (cmd_rc < 0)