RDMA/core: Provide rdma_user_mmap_disassociate() to disassociate mmap pages
BugLink: https://bugs.launchpad.net/bugs/2101915 [ Upstream commit 51976c6cd786151b6a1bdf8b8b3334beac0ba99c ] 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> Stable-dep-of: 615b94746a54 ("RDMA/hns: Disassociate mmap pages for all uctx when HW is being reset") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Koichiro Den <koichiro.den@canonical.com> Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
This commit is contained in:
committed by
Stefan Bader
parent
9286a8e586
commit
bb15b80c7b
@@ -160,6 +160,8 @@ struct ib_uverbs_file {
|
||||
struct page *disassociate_page;
|
||||
|
||||
struct xarray idr;
|
||||
|
||||
struct mutex disassociation_lock;
|
||||
};
|
||||
|
||||
struct ib_uverbs_event {
|
||||
|
||||
@@ -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);
|
||||
@@ -700,8 +702,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;
|
||||
@@ -723,6 +730,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.
|
||||
*/
|
||||
@@ -734,10 +743,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:
|
||||
/*
|
||||
@@ -821,7 +832,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;
|
||||
@@ -847,8 +858,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
|
||||
@@ -878,8 +891,32 @@ 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:
|
||||
*
|
||||
@@ -949,6 +986,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);
|
||||
|
||||
@@ -2940,6 +2940,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,
|
||||
|
||||
Reference in New Issue
Block a user