mirror of
https://github.com/torvalds/linux.git
synced 2026-09-26 10:02:02 +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 page *disassociate_page;
|
||||||
|
|
||||||
struct xarray idr;
|
struct xarray idr;
|
||||||
|
|
||||||
|
struct mutex disassociation_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ib_uverbs_event {
|
struct ib_uverbs_event {
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ static dev_t dynamic_uverbs_dev;
|
||||||
static DEFINE_IDA(uverbs_ida);
|
static DEFINE_IDA(uverbs_ida);
|
||||||
static int ib_uverbs_add_one(struct ib_device *device);
|
static int ib_uverbs_add_one(struct ib_device *device);
|
||||||
static void ib_uverbs_remove_one(struct ib_device *device, void *client_data);
|
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)
|
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)
|
if (file->disassociate_page)
|
||||||
__free_pages(file->disassociate_page, 0);
|
__free_pages(file->disassociate_page, 0);
|
||||||
|
mutex_destroy(&file->disassociation_lock);
|
||||||
mutex_destroy(&file->umap_lock);
|
mutex_destroy(&file->umap_lock);
|
||||||
mutex_destroy(&file->ucontext_lock);
|
mutex_destroy(&file->ucontext_lock);
|
||||||
kfree(file);
|
kfree(file);
|
||||||
|
|
@ -698,8 +700,13 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||||
ret = PTR_ERR(ucontext);
|
ret = PTR_ERR(ucontext);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&file->disassociation_lock);
|
||||||
|
|
||||||
vma->vm_ops = &rdma_umap_ops;
|
vma->vm_ops = &rdma_umap_ops;
|
||||||
ret = ucontext->device->ops.mmap(ucontext, vma);
|
ret = ucontext->device->ops.mmap(ucontext, vma);
|
||||||
|
|
||||||
|
mutex_unlock(&file->disassociation_lock);
|
||||||
out:
|
out:
|
||||||
srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
|
srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -721,6 +728,8 @@ static void rdma_umap_open(struct vm_area_struct *vma)
|
||||||
/* We are racing with disassociation */
|
/* We are racing with disassociation */
|
||||||
if (!down_read_trylock(&ufile->hw_destroy_rwsem))
|
if (!down_read_trylock(&ufile->hw_destroy_rwsem))
|
||||||
goto out_zap;
|
goto out_zap;
|
||||||
|
mutex_lock(&ufile->disassociation_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disassociation already completed, the VMA should already be zapped.
|
* 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;
|
goto out_unlock;
|
||||||
rdma_umap_priv_init(priv, vma, opriv->entry);
|
rdma_umap_priv_init(priv, vma, opriv->entry);
|
||||||
|
|
||||||
|
mutex_unlock(&ufile->disassociation_lock);
|
||||||
up_read(&ufile->hw_destroy_rwsem);
|
up_read(&ufile->hw_destroy_rwsem);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
|
mutex_unlock(&ufile->disassociation_lock);
|
||||||
up_read(&ufile->hw_destroy_rwsem);
|
up_read(&ufile->hw_destroy_rwsem);
|
||||||
out_zap:
|
out_zap:
|
||||||
/*
|
/*
|
||||||
|
|
@ -819,7 +830,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
|
||||||
{
|
{
|
||||||
struct rdma_umap_priv *priv, *next_priv;
|
struct rdma_umap_priv *priv, *next_priv;
|
||||||
|
|
||||||
lockdep_assert_held(&ufile->hw_destroy_rwsem);
|
mutex_lock(&ufile->disassociation_lock);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct mm_struct *mm = NULL;
|
struct mm_struct *mm = NULL;
|
||||||
|
|
@ -845,8 +856,10 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mutex_unlock(&ufile->umap_lock);
|
mutex_unlock(&ufile->umap_lock);
|
||||||
if (!mm)
|
if (!mm) {
|
||||||
|
mutex_unlock(&ufile->disassociation_lock);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The umap_lock is nested under mmap_lock since it used within
|
* 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);
|
mmap_read_unlock(mm);
|
||||||
mmput(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:
|
* 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);
|
mutex_init(&file->umap_lock);
|
||||||
INIT_LIST_HEAD(&file->umaps);
|
INIT_LIST_HEAD(&file->umaps);
|
||||||
|
|
||||||
|
mutex_init(&file->disassociation_lock);
|
||||||
|
|
||||||
filp->private_data = file;
|
filp->private_data = file;
|
||||||
list_add_tail(&file->list, &dev->uverbs_file_list);
|
list_add_tail(&file->list, &dev->uverbs_file_list);
|
||||||
mutex_unlock(&dev->lists_mutex);
|
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,
|
size_t length, u32 min_pgoff,
|
||||||
u32 max_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
|
static inline int
|
||||||
rdma_user_mmap_entry_insert_exact(struct ib_ucontext *ucontext,
|
rdma_user_mmap_entry_insert_exact(struct ib_ucontext *ucontext,
|
||||||
struct rdma_user_mmap_entry *entry,
|
struct rdma_user_mmap_entry *entry,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user