pmem: reduce kmap_atomic sections to the memcpys only
authorVishal Verma <vishal.l.verma@intel.com>
Fri, 30 Sep 2016 23:19:30 +0000 (17:19 -0600)
committerDan Williams <dan.j.williams@intel.com>
Sat, 1 Oct 2016 00:03:45 +0000 (17:03 -0700)
pmem_do_bvec used to kmap_atomic at the begin, and only unmap at the
end. Things like nvdimm_clear_poison may want to do nvdimm subsystem
bookkeeping operations that may involve taking locks or doing memory
allocations, and we can't do that from the atomic context. Reduce the
atomic context to just what needs it - the memcpy to/from pmem.

Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/nvdimm/pmem.c

index 571a6c7ee2fc05b38d056df1423a9d741f53c5ac..42b3a82170733971a3b1d000b8de4979f0ad311b 100644 (file)
@@ -66,13 +66,32 @@ static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
        invalidate_pmem(pmem->virt_addr + offset, len);
 }
 
+static void write_pmem(void *pmem_addr, struct page *page,
+               unsigned int off, unsigned int len)
+{
+       void *mem = kmap_atomic(page);
+
+       memcpy_to_pmem(pmem_addr, mem + off, len);
+       kunmap_atomic(mem);
+}
+
+static int read_pmem(struct page *page, unsigned int off,
+               void *pmem_addr, unsigned int len)
+{
+       int rc;
+       void *mem = kmap_atomic(page);
+
+       rc = memcpy_from_pmem(mem + off, pmem_addr, len);
+       kunmap_atomic(mem);
+       return rc;
+}
+
 static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
                        unsigned int len, unsigned int off, bool is_write,
                        sector_t sector)
 {
        int rc = 0;
        bool bad_pmem = false;
-       void *mem = kmap_atomic(page);
        phys_addr_t pmem_off = sector * 512 + pmem->data_offset;
        void *pmem_addr = pmem->virt_addr + pmem_off;
 
@@ -83,7 +102,7 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
                if (unlikely(bad_pmem))
                        rc = -EIO;
                else {
-                       rc = memcpy_from_pmem(mem + off, pmem_addr, len);
+                       rc = read_pmem(page, off, pmem_addr, len);
                        flush_dcache_page(page);
                }
        } else {
@@ -102,14 +121,13 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
                 * after clear poison.
                 */
                flush_dcache_page(page);
-               memcpy_to_pmem(pmem_addr, mem + off, len);
+               write_pmem(pmem_addr, page, off, len);
                if (unlikely(bad_pmem)) {
                        pmem_clear_poison(pmem, pmem_off, len);
-                       memcpy_to_pmem(pmem_addr, mem + off, len);
+                       write_pmem(pmem_addr, page, off, len);
                }
        }
 
-       kunmap_atomic(mem);
        return rc;
 }