]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
RDMA: Convert put_page() to put_user_page*()
authorJohn Hubbard <jhubbard@nvidia.com>
Sat, 25 May 2019 01:45:22 +0000 (18:45 -0700)
committerJason Gunthorpe <jgg@mellanox.com>
Mon, 27 May 2019 23:11:11 +0000 (20:11 -0300)
For infiniband code that retains pages via get_user_pages*(), release
those pages via the new put_user_page(), or put_user_pages*(), instead of
put_page()

This is a tiny part of the second step of fixing the problem described in
[1]. The steps are:

1) Provide put_user_page*() routines, intended to be used for releasing
   pages that were pinned via get_user_pages*().

2) Convert all of the call sites for get_user_pages*(), to invoke
   put_user_page*(), instead of put_page(). This involves dozens of call
   sites, and will take some time.

3) After (2) is complete, use get_user_pages*() and put_user_page*() to
   implement tracking of these pages. This tracking will be separate from
   the existing struct page refcounting.

4) Use the tracking and identification of these pages, to implement
   special handling (especially in writeback paths) when the pages are
   backed by a filesystem. Again, [1] provides details as to why that is
   desirable.

[1] https://lwn.net/Articles/753027/ : "The Trouble with get_user_pages()"

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Jérôme Glisse <jglisse@redhat.com>
Acked-by: Jason Gunthorpe <jgg@mellanox.com>
Tested-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/core/umem.c
drivers/infiniband/core/umem_odp.c
drivers/infiniband/hw/hfi1/user_pages.c
drivers/infiniband/hw/mthca/mthca_memfree.c
drivers/infiniband/hw/qib/qib_user_pages.c
drivers/infiniband/hw/qib/qib_user_sdma.c
drivers/infiniband/hw/usnic/usnic_uiom.c

index 7edc5839606bda18f3009ffe771c39f6c658ac31..54628ef879f0ceee39d4c26e592d8d88b4e0a26f 100644 (file)
@@ -54,9 +54,10 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
 
        for_each_sg_page(umem->sg_head.sgl, &sg_iter, umem->sg_nents, 0) {
                page = sg_page_iter_page(&sg_iter);
-               if (!PageDirty(page) && umem->writable && dirty)
-                       set_page_dirty_lock(page);
-               put_page(page);
+               if (umem->writable && dirty)
+                       put_user_pages_dirty_lock(&page, 1);
+               else
+                       put_user_page(page);
        }
 
        sg_free_table(&umem->sg_head);
index c3b3c523401f94304f1ad68792e557dad9b1202f..9001cc10770a24a05b02528b7a49873c0b3bc13c 100644 (file)
@@ -482,7 +482,7 @@ void ib_umem_odp_release(struct ib_umem_odp *umem_odp)
  * The function returns -EFAULT if the DMA mapping operation fails. It returns
  * -EAGAIN if a concurrent invalidation prevents us from updating the page.
  *
- * The page is released via put_page even if the operation failed. For
+ * The page is released via put_user_page even if the operation failed. For
  * on-demand pinning, the page is released whenever it isn't stored in the
  * umem.
  */
@@ -530,7 +530,7 @@ static int ib_umem_odp_map_dma_single_page(
        }
 
 out:
-       put_page(page);
+       put_user_page(page);
 
        if (remove_existing_mapping) {
                ib_umem_notifier_start_account(umem_odp);
@@ -653,7 +653,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt,
                                        ret = -EFAULT;
                                        break;
                                }
-                               put_page(local_page_list[j]);
+                               put_user_page(local_page_list[j]);
                                continue;
                        }
 
@@ -680,8 +680,8 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt,
                         * ib_umem_odp_map_dma_single_page().
                         */
                        if (npages - (j + 1) > 0)
-                               release_pages(&local_page_list[j+1],
-                                             npages - (j + 1));
+                               put_user_pages(&local_page_list[j+1],
+                                              npages - (j + 1));
                        break;
                }
        }
index 02eee8eff1db138d69d1dc4c2b8c29f4b3a8b599..b89a9b9aef7ae71ca9cc4a076206f41aab91f418 100644 (file)
@@ -118,13 +118,10 @@ int hfi1_acquire_user_pages(struct mm_struct *mm, unsigned long vaddr, size_t np
 void hfi1_release_user_pages(struct mm_struct *mm, struct page **p,
                             size_t npages, bool dirty)
 {
-       size_t i;
-
-       for (i = 0; i < npages; i++) {
-               if (dirty)
-                       set_page_dirty_lock(p[i]);
-               put_page(p[i]);
-       }
+       if (dirty)
+               put_user_pages_dirty_lock(p, npages);
+       else
+               put_user_pages(p, npages);
 
        if (mm) { /* during close after signal, mm can be NULL */
                atomic64_sub(npages, &mm->pinned_vm);
index 8ff0e90d756485764645de4259c9e6945402b68c..edccfd6e178f020f229789c9cc235ea850479bfd 100644 (file)
@@ -482,7 +482,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
 
        ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
        if (ret < 0) {
-               put_page(pages[0]);
+               put_user_page(pages[0]);
                goto out;
        }
 
@@ -490,7 +490,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
                                 mthca_uarc_virt(dev, uar, i));
        if (ret) {
                pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
-               put_page(sg_page(&db_tab->page[i].mem));
+               put_user_page(sg_page(&db_tab->page[i].mem));
                goto out;
        }
 
@@ -556,7 +556,7 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
                if (db_tab->page[i].uvirt) {
                        mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1);
                        pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
-                       put_page(sg_page(&db_tab->page[i].mem));
+                       put_user_page(sg_page(&db_tab->page[i].mem));
                }
        }
 
index f712fb7fa82f995b2bbef7c24ddc7bb29cada4f2..bfbfbb7e0ff461299520d3d072d388bd13ab0420 100644 (file)
 static void __qib_release_user_pages(struct page **p, size_t num_pages,
                                     int dirty)
 {
-       size_t i;
-
-       for (i = 0; i < num_pages; i++) {
-               if (dirty)
-                       set_page_dirty_lock(p[i]);
-               put_page(p[i]);
-       }
+       if (dirty)
+               put_user_pages_dirty_lock(p, num_pages);
+       else
+               put_user_pages(p, num_pages);
 }
 
 /**
index 0c204776263f2da7911126de46a37ff7219a3fcc..ac5bdb02144fc54d7219269ccb14011aa9a7b237 100644 (file)
@@ -317,7 +317,7 @@ static int qib_user_sdma_page_to_frags(const struct qib_devdata *dd,
                 * the caller can ignore this page.
                 */
                if (put) {
-                       put_page(page);
+                       put_user_page(page);
                } else {
                        /* coalesce case */
                        kunmap(page);
@@ -631,7 +631,7 @@ static void qib_user_sdma_free_pkt_frag(struct device *dev,
                        kunmap(pkt->addr[i].page);
 
                if (pkt->addr[i].put_page)
-                       put_page(pkt->addr[i].page);
+                       put_user_page(pkt->addr[i].page);
                else
                        __free_page(pkt->addr[i].page);
        } else if (pkt->addr[i].kvaddr) {
@@ -706,7 +706,7 @@ static int qib_user_sdma_pin_pages(const struct qib_devdata *dd,
        /* if error, return all pages not managed by pkt */
 free_pages:
        while (i < j)
-               put_page(pages[i++]);
+               put_user_page(pages[i++]);
 
 done:
        return ret;
index e312f522a66de7a3e333d931955474bcaf907916..0b0237d41613fc4cb61ba4f1cd02430aeda74490 100644 (file)
@@ -75,9 +75,10 @@ static void usnic_uiom_put_pages(struct list_head *chunk_list, int dirty)
                for_each_sg(chunk->page_list, sg, chunk->nents, i) {
                        page = sg_page(sg);
                        pa = sg_phys(sg);
-                       if (!PageDirty(page) && dirty)
-                               set_page_dirty_lock(page);
-                       put_page(page);
+                       if (dirty)
+                               put_user_pages_dirty_lock(&page, 1);
+                       else
+                               put_user_page(page);
                        usnic_dbg("pa: %pa\n", &pa);
                }
                kfree(chunk);