mirror of
https://github.com/torvalds/linux.git
synced 2026-09-26 01:52:03 +02:00
RDMA/core: Provide rdma_user_mmap_disassociate() to disassociate mmap pages
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>
This commit is contained in:
parent
8cf0b93919
commit
51976c6cd7
|
|
@ -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);
|
||||
|
|
@ -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,8 +889,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:
|
||||
*
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user