]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
RDMA/core: Provide rdma_user_mmap_disassociate() to disassociate mmap pages
authorChengchang Tang <tangchengchang@huawei.com>
Fri, 27 Sep 2024 10:33:22 +0000 (18:33 +0800)
committerLeon Romanovsky <leon@kernel.org>
Mon, 7 Oct 2024 05:53:23 +0000 (08:53 +0300)
Provide a new api rdma_user_mmap_disassociate() for drivers to
disassociate mmap pages for a device.

Since drivers can now disassociate mmaps by calling this api,
introduce a new disassociation_lock to specifically prevent
races between this disassociation process and new mmaps. And
thus the old hw_destroy_rwsem is not needed in this api.

Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
Signed-off-by: Junxian Huang <huangjunxian6@hisilicon.com>
Link: https://patch.msgid.link/20240927103323.1897094-2-huangjunxian6@hisilicon.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_main.c
include/rdma/ib_verbs.h

index 821d93c8f7123ce1da41d91e88fba9f044dc8e79..dfd2e5a86e6fe5f3b6e027b90924d7802d729eaf 100644 (file)
@@ -160,6 +160,8 @@ struct ib_uverbs_file {
        struct page *disassociate_page;
 
        struct xarray           idr;
+
+       struct mutex disassociation_lock;
 };
 
 struct ib_uverbs_event {
index 94454186ed81d54f6d74c1ab093eaeab2660a013..85cfc790a7bb3649086d5cc1c29e2e8658cf7e21 100644 (file)
@@ -76,6 +76,7 @@ static dev_t dynamic_uverbs_dev;
 static DEFINE_IDA(uverbs_ida);
 static int ib_uverbs_add_one(struct ib_device *device);
 static void ib_uverbs_remove_one(struct ib_device *device, void *client_data);
+static struct ib_client uverbs_client;
 
 static char *uverbs_devnode(const struct device *dev, umode_t *mode)
 {
@@ -217,6 +218,7 @@ void ib_uverbs_release_file(struct kref *ref)
 
        if (file->disassociate_page)
                __free_pages(file->disassociate_page, 0);
+       mutex_destroy(&file->disassociation_lock);
        mutex_destroy(&file->umap_lock);
        mutex_destroy(&file->ucontext_lock);
        kfree(file);
@@ -698,8 +700,13 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
                ret = PTR_ERR(ucontext);
                goto out;
        }
+
+       mutex_lock(&file->disassociation_lock);
+
        vma->vm_ops = &rdma_umap_ops;
        ret = ucontext->device->ops.mmap(ucontext, vma);
+
+       mutex_unlock(&file->disassociation_lock);
 out:
        srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
        return ret;
@@ -721,6 +728,8 @@ static void rdma_umap_open(struct vm_area_struct *vma)
        /* We are racing with disassociation */
        if (!down_read_trylock(&ufile->hw_destroy_rwsem))
                goto out_zap;
+       mutex_lock(&ufile->disassociation_lock);
+
        /*
         * Disassociation already completed, the VMA should already be zapped.
         */
@@ -732,10 +741,12 @@ static void rdma_umap_open(struct vm_area_struct *vma)
                goto out_unlock;
        rdma_umap_priv_init(priv, vma, opriv->entry);
 
+       mutex_unlock(&ufile->disassociation_lock);
        up_read(&ufile->hw_destroy_rwsem);
        return;
 
 out_unlock:
+       mutex_unlock(&ufile->disassociation_lock);
        up_read(&ufile->hw_destroy_rwsem);
 out_zap:
        /*
@@ -819,7 +830,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
 {
        struct rdma_umap_priv *priv, *next_priv;
 
-       lockdep_assert_held(&ufile->hw_destroy_rwsem);
+       mutex_lock(&ufile->disassociation_lock);
 
        while (1) {
                struct mm_struct *mm = NULL;
@@ -845,8 +856,10 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
                        break;
                }
                mutex_unlock(&ufile->umap_lock);
-               if (!mm)
+               if (!mm) {
+                       mutex_unlock(&ufile->disassociation_lock);
                        return;
+               }
 
                /*
                 * The umap_lock is nested under mmap_lock since it used within
@@ -876,7 +889,31 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
                mmap_read_unlock(mm);
                mmput(mm);
        }
+
+       mutex_unlock(&ufile->disassociation_lock);
+}
+
+/**
+ * rdma_user_mmap_disassociate() - Revoke mmaps for a device
+ * @device: device to revoke
+ *
+ * This function should be called by drivers that need to disable mmaps for the
+ * device, for instance because it is going to be reset.
+ */
+void rdma_user_mmap_disassociate(struct ib_device *device)
+{
+       struct ib_uverbs_device *uverbs_dev =
+               ib_get_client_data(device, &uverbs_client);
+       struct ib_uverbs_file *ufile;
+
+       mutex_lock(&uverbs_dev->lists_mutex);
+       list_for_each_entry(ufile, &uverbs_dev->uverbs_file_list, list) {
+               if (ufile->ucontext)
+                       uverbs_user_mmap_disassociate(ufile);
+       }
+       mutex_unlock(&uverbs_dev->lists_mutex);
 }
+EXPORT_SYMBOL(rdma_user_mmap_disassociate);
 
 /*
  * ib_uverbs_open() does not need the BKL:
@@ -947,6 +984,8 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
        mutex_init(&file->umap_lock);
        INIT_LIST_HEAD(&file->umaps);
 
+       mutex_init(&file->disassociation_lock);
+
        filp->private_data = file;
        list_add_tail(&file->list, &dev->uverbs_file_list);
        mutex_unlock(&dev->lists_mutex);
index aa8ede439905cb331a3529dc6bbc454e60b4f5ed..9cb8b5fe7eee4c91f3157088246a8ae4f1c212a8 100644 (file)
@@ -2948,6 +2948,14 @@ int rdma_user_mmap_entry_insert_range(struct ib_ucontext *ucontext,
                                      size_t length, u32 min_pgoff,
                                      u32 max_pgoff);
 
+#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
+void rdma_user_mmap_disassociate(struct ib_device *device);
+#else
+static inline void rdma_user_mmap_disassociate(struct ib_device *device)
+{
+}
+#endif
+
 static inline int
 rdma_user_mmap_entry_insert_exact(struct ib_ucontext *ucontext,
                                  struct rdma_user_mmap_entry *entry,