Commit 51976c6c authored by Chengchang Tang's avatar Chengchang Tang Committed by Leon Romanovsky
Browse files

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: default avatarChengchang Tang <tangchengchang@huawei.com>
Signed-off-by: default avatarJunxian Huang <huangjunxian6@hisilicon.com>
Link: https://patch.msgid.link/20240927103323.1897094-2-huangjunxian6@hisilicon.com


Signed-off-by: default avatarLeon Romanovsky <leon@kernel.org>
parent 8cf0b939
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -160,6 +160,8 @@ struct ib_uverbs_file {
	struct page *disassociate_page;

	struct xarray		idr;

	struct mutex disassociation_lock;
};

struct ib_uverbs_event {
+41 −2
Original line number Diff line number Diff line
@@ -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);
+8 −0
Original line number Diff line number Diff line
@@ -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,