@@ -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;
@@ -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);
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> --- drivers/nvdimm/btt.c | 8 +++++++- drivers/nvdimm/pmem.c | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-)