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@xxxxxxxxxxxxxxx> Cc: <linux-nvdimm@xxxxxxxxxxxx> Cc: Dan Williams <dan.j.williams@xxxxxxxxx> Cc: Robert Moore <robert.moore@xxxxxxxxx> Cc: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> Signed-off-by: Vishal Verma <vishal.l.verma@xxxxxxxxx> --- drivers/nvdimm/btt.c | 8 +++++++- drivers/nvdimm/pmem.c | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 48382ca9..25b576d 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -11,6 +11,7 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ +#include <linux/sched/mm.h> #include <linux/highmem.h> #include <linux/debugfs.h> #include <linux/blkdev.h> @@ -494,17 +495,22 @@ static int arena_clear_freelist_error(struct arena_info *arena, u32 lane) if (arena->freelist[lane].has_err) { u32 lba = arena->freelist[lane].block; u64 nsoff = to_namespace_offset(arena, lba); + unsigned int noio_flag; void *zerobuf; + noio_flag = memalloc_noio_save(); zerobuf = kzalloc(arena->sector_size, GFP_KERNEL); - if (!zerobuf) + if (!zerobuf) { + memalloc_noio_restore(noio_flag); return -ENOMEM; + } mutex_lock(&arena->freelist[lane].err_lock); ret = arena_write_bytes(arena, nsoff, zerobuf, arena->sector_size, 0); arena->freelist[lane].has_err = 0; mutex_unlock(&arena->freelist[lane].err_lock); + memalloc_noio_restore(noio_flag); kfree(zerobuf); } return ret; diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 5c45e17..468e032 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -24,6 +24,7 @@ #include <linux/moduleparam.h> #include <linux/badblocks.h> #include <linux/memremap.h> +#include <linux/sched/mm.h> #include <linux/vmalloc.h> #include <linux/blk-mq.h> #include <linux/pfn_t.h> @@ -53,12 +54,14 @@ static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, unsigned int len) { struct device *dev = to_dev(pmem); + unsigned int noio_flag; sector_t sector; long cleared; int rc = 0; sector = (offset - pmem->data_offset) / 512; + noio_flag = memalloc_noio_save(); cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len); if (cleared < len) rc = -EIO; @@ -69,6 +72,7 @@ static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, cleared > 1 ? "s" : ""); badblocks_clear(&pmem->bb, sector, cleared); } + memalloc_noio_restore(noio_flag); invalidate_pmem(pmem->virt_addr + offset, len); -- 2.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html