drivers/mic/scif: do not use mmap_sem
authorDavidlohr Bueso <dave@stgolabs.net>
Wed, 6 Feb 2019 17:59:16 +0000 (09:59 -0800)
committerJason Gunthorpe <jgg@mellanox.com>
Thu, 7 Feb 2019 19:54:02 +0000 (12:54 -0700)
The driver uses mmap_sem for both pinned_vm accounting and
get_user_pages(). By using gup_fast() and letting the mm handle the lock
if needed, we can no longer rely on the semaphore and simplify the whole
thing.

Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/misc/mic/scif/scif_rma.c

index 2448368..263b8ad 100644 (file)
@@ -272,21 +272,12 @@ static inline void __scif_release_mm(struct mm_struct *mm)
 
 static inline int
 __scif_dec_pinned_vm_lock(struct mm_struct *mm,
-                         int nr_pages, bool try_lock)
+                         int nr_pages)
 {
        if (!mm || !nr_pages || !scif_ulimit_check)
                return 0;
-       if (try_lock) {
-               if (!down_write_trylock(&mm->mmap_sem)) {
-                       dev_err(scif_info.mdev.this_device,
-                               "%s %d err\n", __func__, __LINE__);
-                       return -1;
-               }
-       } else {
-               down_write(&mm->mmap_sem);
-       }
+
        atomic64_sub(nr_pages, &mm->pinned_vm);
-       up_write(&mm->mmap_sem);
        return 0;
 }
 
@@ -298,16 +289,16 @@ static inline int __scif_check_inc_pinned_vm(struct mm_struct *mm,
        if (!mm || !nr_pages || !scif_ulimit_check)
                return 0;
 
-       locked = nr_pages;
-       locked += atomic64_read(&mm->pinned_vm);
        lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+       locked = atomic64_add_return(nr_pages, &mm->pinned_vm);
+
        if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
+               atomic64_sub(nr_pages, &mm->pinned_vm);
                dev_err(scif_info.mdev.this_device,
                        "locked(%lu) > lock_limit(%lu)\n",
                        locked, lock_limit);
                return -ENOMEM;
        }
-       atomic64_set(&mm->pinned_vm, locked);
        return 0;
 }
 
@@ -326,7 +317,7 @@ int scif_destroy_window(struct scif_endpt *ep, struct scif_window *window)
 
        might_sleep();
        if (!window->temp && window->mm) {
-               __scif_dec_pinned_vm_lock(window->mm, window->nr_pages, 0);
+               __scif_dec_pinned_vm_lock(window->mm, window->nr_pages);
                __scif_release_mm(window->mm);
                window->mm = NULL;
        }
@@ -737,7 +728,7 @@ done:
                                            ep->rma_info.dma_chan);
                } else {
                        if (!__scif_dec_pinned_vm_lock(window->mm,
-                                                      window->nr_pages, 1)) {
+                                                      window->nr_pages)) {
                                __scif_release_mm(window->mm);
                                window->mm = NULL;
                        }
@@ -1385,28 +1376,23 @@ int __scif_pin_pages(void *addr, size_t len, int *out_prot,
                prot |= SCIF_PROT_WRITE;
 retry:
                mm = current->mm;
-               down_write(&mm->mmap_sem);
                if (ulimit) {
                        err = __scif_check_inc_pinned_vm(mm, nr_pages);
                        if (err) {
-                               up_write(&mm->mmap_sem);
                                pinned_pages->nr_pages = 0;
                                goto error_unmap;
                        }
                }
 
-               pinned_pages->nr_pages = get_user_pages(
+               pinned_pages->nr_pages = get_user_pages_fast(
                                (u64)addr,
                                nr_pages,
                                (prot & SCIF_PROT_WRITE) ? FOLL_WRITE : 0,
-                               pinned_pages->pages,
-                               NULL);
-               up_write(&mm->mmap_sem);
+                               pinned_pages->pages);
                if (nr_pages != pinned_pages->nr_pages) {
                        if (try_upgrade) {
                                if (ulimit)
-                                       __scif_dec_pinned_vm_lock(mm,
-                                                                 nr_pages, 0);
+                                       __scif_dec_pinned_vm_lock(mm, nr_pages);
                                /* Roll back any pinned pages */
                                for (i = 0; i < pinned_pages->nr_pages; i++) {
                                        if (pinned_pages->pages[i])
@@ -1433,7 +1419,7 @@ retry:
        return err;
 dec_pinned:
        if (ulimit)
-               __scif_dec_pinned_vm_lock(mm, nr_pages, 0);
+               __scif_dec_pinned_vm_lock(mm, nr_pages);
        /* Something went wrong! Rollback */
 error_unmap:
        pinned_pages->nr_pages = nr_pages;