* [PATCH for-next 1/3] RDMA/core: Provide rdma_user_mmap_disassociate() to disassociate mmap pages
2024-07-26 7:19 [PATCH for-next 0/3] RDMA: Provide an API for drivers to disassociate mmap pages Junxian Huang
@ 2024-07-26 7:19 ` Junxian Huang
2024-07-26 7:19 ` [PATCH for-next 2/3] RDMA/hns: Link all uctx to uctx_list on a device Junxian Huang
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Junxian Huang @ 2024-07-26 7:19 UTC (permalink / raw)
To: jgg, leon; +Cc: linux-rdma, linuxarm, linux-kernel, huangjunxian6
From: Chengchang Tang <tangchengchang@huawei.com>
Provide a new api rdma_user_mmap_disassociate() for drivers to
disassociate mmap pages for ucontext.
This api relies on uverbs_user_mmap_disassociate() in ib_uverbs,
causing ib_core relying on ib_uverbs. To avoid this, move
uverbs_user_mmap_disassociate() to ib_core_uverbs.c.
Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
Signed-off-by: Junxian Huang <huangjunxian6@hisilicon.com>
---
drivers/infiniband/core/ib_core_uverbs.c | 85 ++++++++++++++++++++++++
drivers/infiniband/core/rdma_core.h | 1 -
drivers/infiniband/core/uverbs_main.c | 64 ------------------
include/rdma/ib_verbs.h | 3 +
4 files changed, 88 insertions(+), 65 deletions(-)
diff --git a/drivers/infiniband/core/ib_core_uverbs.c b/drivers/infiniband/core/ib_core_uverbs.c
index b51bd7087a88..4e27389a75ad 100644
--- a/drivers/infiniband/core/ib_core_uverbs.c
+++ b/drivers/infiniband/core/ib_core_uverbs.c
@@ -5,6 +5,7 @@
* Copyright 2019 Marvell. All rights reserved.
*/
#include <linux/xarray.h>
+#include <linux/sched/mm.h>
#include "uverbs.h"
#include "core_priv.h"
@@ -365,3 +366,87 @@ int rdma_user_mmap_entry_insert(struct ib_ucontext *ucontext,
U32_MAX);
}
EXPORT_SYMBOL(rdma_user_mmap_entry_insert);
+
+void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
+{
+ struct rdma_umap_priv *priv, *next_priv;
+
+ lockdep_assert_held(&ufile->hw_destroy_rwsem);
+
+ while (1) {
+ struct mm_struct *mm = NULL;
+
+ /* Get an arbitrary mm pointer that hasn't been cleaned yet */
+ mutex_lock(&ufile->umap_lock);
+ while (!list_empty(&ufile->umaps)) {
+ int ret;
+
+ priv = list_first_entry(&ufile->umaps,
+ struct rdma_umap_priv, list);
+ mm = priv->vma->vm_mm;
+ ret = mmget_not_zero(mm);
+ if (!ret) {
+ list_del_init(&priv->list);
+ if (priv->entry) {
+ rdma_user_mmap_entry_put(priv->entry);
+ priv->entry = NULL;
+ }
+ mm = NULL;
+ continue;
+ }
+ break;
+ }
+ mutex_unlock(&ufile->umap_lock);
+ if (!mm)
+ return;
+
+ /*
+ * The umap_lock is nested under mmap_lock since it used within
+ * the vma_ops callbacks, so we have to clean the list one mm
+ * at a time to get the lock ordering right. Typically there
+ * will only be one mm, so no big deal.
+ */
+ mmap_read_lock(mm);
+ mutex_lock(&ufile->umap_lock);
+ list_for_each_entry_safe(priv, next_priv, &ufile->umaps, list) {
+ struct vm_area_struct *vma = priv->vma;
+
+ if (vma->vm_mm != mm)
+ continue;
+ list_del_init(&priv->list);
+
+ zap_vma_ptes(vma, vma->vm_start,
+ vma->vm_end - vma->vm_start);
+
+ if (priv->entry) {
+ rdma_user_mmap_entry_put(priv->entry);
+ priv->entry = NULL;
+ }
+ }
+ mutex_unlock(&ufile->umap_lock);
+ mmap_read_unlock(mm);
+ mmput(mm);
+ }
+}
+EXPORT_SYMBOL(uverbs_user_mmap_disassociate);
+
+/**
+ * rdma_user_mmap_disassociate() - disassociate the mmap from the ucontext.
+ *
+ * @ucontext: associated user context.
+ *
+ * This function should be called by drivers that need to disable mmap for
+ * some ucontexts.
+ */
+void rdma_user_mmap_disassociate(struct ib_ucontext *ucontext)
+{
+ struct ib_uverbs_file *ufile = ucontext->ufile;
+
+ /* Racing with uverbs_destroy_ufile_hw */
+ if (!down_read_trylock(&ufile->hw_destroy_rwsem))
+ return;
+
+ uverbs_user_mmap_disassociate(ufile);
+ up_read(&ufile->hw_destroy_rwsem);
+}
+EXPORT_SYMBOL(rdma_user_mmap_disassociate);
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index 33706dad6c0f..ad01fbd52c48 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -149,7 +149,6 @@ void uverbs_disassociate_api(struct uverbs_api *uapi);
void uverbs_destroy_api(struct uverbs_api *uapi);
void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm,
unsigned int num_attrs);
-void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
extern const struct uapi_definition uverbs_def_obj_async_fd[];
extern const struct uapi_definition uverbs_def_obj_counters[];
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index bc099287de9a..e7cacbc3fe03 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -45,7 +45,6 @@
#include <linux/cdev.h>
#include <linux/anon_inodes.h>
#include <linux/slab.h>
-#include <linux/sched/mm.h>
#include <linux/uaccess.h>
@@ -817,69 +816,6 @@ static const struct vm_operations_struct rdma_umap_ops = {
.fault = rdma_umap_fault,
};
-void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
-{
- struct rdma_umap_priv *priv, *next_priv;
-
- lockdep_assert_held(&ufile->hw_destroy_rwsem);
-
- while (1) {
- struct mm_struct *mm = NULL;
-
- /* Get an arbitrary mm pointer that hasn't been cleaned yet */
- mutex_lock(&ufile->umap_lock);
- while (!list_empty(&ufile->umaps)) {
- int ret;
-
- priv = list_first_entry(&ufile->umaps,
- struct rdma_umap_priv, list);
- mm = priv->vma->vm_mm;
- ret = mmget_not_zero(mm);
- if (!ret) {
- list_del_init(&priv->list);
- if (priv->entry) {
- rdma_user_mmap_entry_put(priv->entry);
- priv->entry = NULL;
- }
- mm = NULL;
- continue;
- }
- break;
- }
- mutex_unlock(&ufile->umap_lock);
- if (!mm)
- return;
-
- /*
- * The umap_lock is nested under mmap_lock since it used within
- * the vma_ops callbacks, so we have to clean the list one mm
- * at a time to get the lock ordering right. Typically there
- * will only be one mm, so no big deal.
- */
- mmap_read_lock(mm);
- mutex_lock(&ufile->umap_lock);
- list_for_each_entry_safe (priv, next_priv, &ufile->umaps,
- list) {
- struct vm_area_struct *vma = priv->vma;
-
- if (vma->vm_mm != mm)
- continue;
- list_del_init(&priv->list);
-
- zap_vma_ptes(vma, vma->vm_start,
- vma->vm_end - vma->vm_start);
-
- if (priv->entry) {
- rdma_user_mmap_entry_put(priv->entry);
- priv->entry = NULL;
- }
- }
- mutex_unlock(&ufile->umap_lock);
- mmap_read_unlock(mm);
- mmput(mm);
- }
-}
-
/*
* ib_uverbs_open() does not need the BKL:
*
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 6c5712ae559d..4175e3588b77 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -2947,6 +2947,7 @@ int rdma_user_mmap_entry_insert_range(struct ib_ucontext *ucontext,
struct rdma_user_mmap_entry *entry,
size_t length, u32 min_pgoff,
u32 max_pgoff);
+void rdma_user_mmap_disassociate(struct ib_ucontext *ucontext);
static inline int
rdma_user_mmap_entry_insert_exact(struct ib_ucontext *ucontext,
@@ -4729,6 +4730,8 @@ struct ib_ucontext *ib_uverbs_get_ucontext_file(struct ib_uverbs_file *ufile);
int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs);
+void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
+
struct net_device *rdma_alloc_netdev(struct ib_device *device, u32 port_num,
enum rdma_netdev_t type, const char *name,
unsigned char name_assign_type,
--
2.33.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH for-next 2/3] RDMA/hns: Link all uctx to uctx_list on a device
2024-07-26 7:19 [PATCH for-next 0/3] RDMA: Provide an API for drivers to disassociate mmap pages Junxian Huang
2024-07-26 7:19 ` [PATCH for-next 1/3] RDMA/core: Provide rdma_user_mmap_disassociate() " Junxian Huang
@ 2024-07-26 7:19 ` Junxian Huang
2024-07-26 7:19 ` [PATCH for-next 3/3] RDMA/hns: Disassociate mmap pages for all uctx when HW is being reset Junxian Huang
2024-08-05 11:00 ` [PATCH for-next 0/3] RDMA: Provide an API for drivers to disassociate mmap pages Leon Romanovsky
3 siblings, 0 replies; 6+ messages in thread
From: Junxian Huang @ 2024-07-26 7:19 UTC (permalink / raw)
To: jgg, leon; +Cc: linux-rdma, linuxarm, linux-kernel, huangjunxian6
From: Chengchang Tang <tangchengchang@huawei.com>
Link all uctx to uctx_list on a device.
Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
Signed-off-by: Junxian Huang <huangjunxian6@hisilicon.com>
---
drivers/infiniband/hw/hns/hns_roce_device.h | 4 ++++
drivers/infiniband/hw/hns/hns_roce_main.c | 13 +++++++++++++
2 files changed, 17 insertions(+)
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index 0b1e21cb6d2d..93768660569d 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -217,6 +217,7 @@ struct hns_roce_ucontext {
struct mutex page_mutex;
struct hns_user_mmap_entry *db_mmap_entry;
u32 config;
+ struct list_head list; /* link all uctx to uctx_list on hr_dev */
};
struct hns_roce_pd {
@@ -1030,6 +1031,9 @@ struct hns_roce_dev {
u64 dwqe_page;
struct hns_roce_dev_debugfs dbgfs;
atomic64_t *dfx_cnt;
+
+ struct list_head uctx_list; /* list of all uctx on this dev */
+ struct mutex uctx_list_mutex; /* protect @uctx_list */
};
static inline struct hns_roce_dev *to_hr_dev(struct ib_device *ib_dev)
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index 4cb0af733587..e19871ebc315 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -426,6 +426,10 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,
if (ret)
goto error_fail_copy_to_udata;
+ mutex_lock(&hr_dev->uctx_list_mutex);
+ list_add(&context->list, &hr_dev->uctx_list);
+ mutex_unlock(&hr_dev->uctx_list_mutex);
+
return 0;
error_fail_copy_to_udata:
@@ -448,6 +452,10 @@ static void hns_roce_dealloc_ucontext(struct ib_ucontext *ibcontext)
struct hns_roce_ucontext *context = to_hr_ucontext(ibcontext);
struct hns_roce_dev *hr_dev = to_hr_dev(ibcontext->device);
+ mutex_lock(&hr_dev->uctx_list_mutex);
+ list_del(&context->list);
+ mutex_unlock(&hr_dev->uctx_list_mutex);
+
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_CQ_RECORD_DB ||
hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_RECORD_DB)
mutex_destroy(&context->page_mutex);
@@ -943,6 +951,7 @@ static int hns_roce_init_hem(struct hns_roce_dev *hr_dev)
static void hns_roce_teardown_hca(struct hns_roce_dev *hr_dev)
{
hns_roce_cleanup_bitmap(hr_dev);
+ mutex_destroy(&hr_dev->uctx_list_mutex);
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_CQ_RECORD_DB ||
hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_RECORD_DB)
@@ -961,6 +970,9 @@ static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev)
spin_lock_init(&hr_dev->sm_lock);
+ INIT_LIST_HEAD(&hr_dev->uctx_list);
+ mutex_init(&hr_dev->uctx_list_mutex);
+
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_CQ_RECORD_DB ||
hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_RECORD_DB) {
INIT_LIST_HEAD(&hr_dev->pgdir_list);
@@ -1000,6 +1012,7 @@ static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev)
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_CQ_RECORD_DB ||
hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_RECORD_DB)
mutex_destroy(&hr_dev->pgdir_mutex);
+ mutex_destroy(&hr_dev->uctx_list_mutex);
return ret;
}
--
2.33.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH for-next 3/3] RDMA/hns: Disassociate mmap pages for all uctx when HW is being reset
2024-07-26 7:19 [PATCH for-next 0/3] RDMA: Provide an API for drivers to disassociate mmap pages Junxian Huang
2024-07-26 7:19 ` [PATCH for-next 1/3] RDMA/core: Provide rdma_user_mmap_disassociate() " Junxian Huang
2024-07-26 7:19 ` [PATCH for-next 2/3] RDMA/hns: Link all uctx to uctx_list on a device Junxian Huang
@ 2024-07-26 7:19 ` Junxian Huang
2024-08-05 11:00 ` [PATCH for-next 0/3] RDMA: Provide an API for drivers to disassociate mmap pages Leon Romanovsky
3 siblings, 0 replies; 6+ messages in thread
From: Junxian Huang @ 2024-07-26 7:19 UTC (permalink / raw)
To: jgg, leon; +Cc: linux-rdma, linuxarm, linux-kernel, huangjunxian6
From: Chengchang Tang <tangchengchang@huawei.com>
When HW is being reset, userspace should not ring doorbell otherwise
it may lead to abnormal consequence such as RAS.
Disassociate mmap pages for all uctx to prevent userspace from ringing
doorbell to HW.
Fixes: 9a4435375cd1 ("IB/hns: Add driver files for hns RoCE driver")
Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
Signed-off-by: Junxian Huang <huangjunxian6@hisilicon.com>
---
drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index 621b057fb9da..8adf8430212d 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -7012,6 +7012,18 @@ static void hns_roce_hw_v2_uninit_instance(struct hnae3_handle *handle,
handle->rinfo.instance_state = HNS_ROCE_STATE_NON_INIT;
}
+
+static void hns_roce_v2_reset_notify_user(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_ucontext *uctx, *tmp;
+
+ mutex_lock(&hr_dev->uctx_list_mutex);
+ list_for_each_entry_safe(uctx, tmp, &hr_dev->uctx_list, list) {
+ rdma_user_mmap_disassociate(&uctx->ibucontext);
+ }
+ mutex_unlock(&hr_dev->uctx_list_mutex);
+}
+
static int hns_roce_hw_v2_reset_notify_down(struct hnae3_handle *handle)
{
struct hns_roce_dev *hr_dev;
@@ -7030,6 +7042,9 @@ static int hns_roce_hw_v2_reset_notify_down(struct hnae3_handle *handle)
hr_dev->active = false;
hr_dev->dis_db = true;
+
+ hns_roce_v2_reset_notify_user(hr_dev);
+
hr_dev->state = HNS_ROCE_DEVICE_STATE_RST_DOWN;
return 0;
--
2.33.0
^ permalink raw reply related [flat|nested] 6+ messages in thread