Commit fcc76093 authored by wenglianfa's avatar wenglianfa Committed by Chengchang Tang
Browse files

RDMA/hns: Fix sleeping in spin_lock critical section

driver inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IAL7SX



----------------------------------------------------------------------

Sleep is not allowed in the spinlock critical section, but
ib_umem_release() may sleep in the spinlock critical sectio.
To fix it, use mutex_lock() instead of spin_lock().

Fixes: 431c875e ("RDMA/hns: Fix simultaneous reset and resource deregistration")
Signed-off-by: default avatarwenglianfa <wenglianfa@huawei.com>
Signed-off-by: default avatarXinghai Cen <cenxinghai@h-partners.com>
parent d2356f8f
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1228,9 +1228,9 @@ struct hns_roce_dev {
	struct rdma_notify_mem *notify_tbl;
	size_t notify_num;
	struct list_head mtr_unfree_list; /* list of unfree mtr on this dev */
	spinlock_t mtr_unfree_list_lock; /* protect mtr_unfree_list */
	struct mutex mtr_unfree_list_mutex; /* protect mtr_unfree_list */
	struct list_head umem_unfree_list; /* list of unfree umem on this dev */
	spinlock_t umem_unfree_list_lock; /* protect umem_unfree_list */
	struct mutex umem_unfree_list_mutex; /* protect umem_unfree_list */
};

static inline struct hns_roce_dev *to_hr_dev(struct ib_device *ib_dev)
+8 −3
Original line number Diff line number Diff line
@@ -1314,6 +1314,8 @@ static void hns_roce_teardown_hca(struct hns_roce_dev *hr_dev)
		hns_roce_cleanup_dca(hr_dev);

	hns_roce_cleanup_bitmap(hr_dev);
	mutex_destroy(&hr_dev->umem_unfree_list_mutex);
	mutex_destroy(&hr_dev->mtr_unfree_list_mutex);
	mutex_destroy(&hr_dev->uctx_list_mutex);

	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_CQ_RECORD_DB ||
@@ -1342,10 +1344,10 @@ static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev)
	mutex_init(&hr_dev->uctx_list_mutex);

	INIT_LIST_HEAD(&hr_dev->mtr_unfree_list);
	spin_lock_init(&hr_dev->mtr_unfree_list_lock);
	mutex_init(&hr_dev->mtr_unfree_list_mutex);

	INIT_LIST_HEAD(&hr_dev->umem_unfree_list);
	spin_lock_init(&hr_dev->umem_unfree_list_lock);
	mutex_init(&hr_dev->umem_unfree_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) {
@@ -1387,7 +1389,10 @@ static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev)

err_uar_table_free:
	ida_destroy(&hr_dev->uar_ida.ida);
	mutex_destroy(&hr_dev->umem_unfree_list_mutex);
	mutex_destroy(&hr_dev->mtr_unfree_list_mutex);
	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)
		mutex_destroy(&hr_dev->pgdir_mutex);
@@ -1597,9 +1602,9 @@ void hns_roce_exit(struct hns_roce_dev *hr_dev, bool bond_cleanup)

	if (hr_dev->hw->hw_exit)
		hr_dev->hw->hw_exit(hr_dev);
	hns_roce_teardown_hca(hr_dev);
	hns_roce_free_unfree_umem(hr_dev);
	hns_roce_free_unfree_mtr(hr_dev);
	hns_roce_teardown_hca(hr_dev);
	hns_roce_cleanup_hem(hr_dev);

	if (hr_dev->cmd_mod)
+8 −8
Original line number Diff line number Diff line
@@ -1296,22 +1296,22 @@ void hns_roce_add_unfree_mtr(struct hns_roce_mtr_node *pos,
{
	hns_roce_copy_mtr(&pos->mtr, mtr);

	spin_lock(&hr_dev->mtr_unfree_list_lock);
	mutex_lock(&hr_dev->mtr_unfree_list_mutex);
	list_add_tail(&pos->list, &hr_dev->mtr_unfree_list);
	spin_unlock(&hr_dev->mtr_unfree_list_lock);
	mutex_unlock(&hr_dev->mtr_unfree_list_mutex);
}

void hns_roce_free_unfree_mtr(struct hns_roce_dev *hr_dev)
{
	struct hns_roce_mtr_node *pos, *next;

	spin_lock(&hr_dev->mtr_unfree_list_lock);
	mutex_lock(&hr_dev->mtr_unfree_list_mutex);
	list_for_each_entry_safe(pos, next, &hr_dev->mtr_unfree_list, list) {
		list_del(&pos->list);
		hns_roce_mtr_destroy(hr_dev, &pos->mtr);
		kvfree(pos);
	}
	spin_unlock(&hr_dev->mtr_unfree_list_lock);
	mutex_unlock(&hr_dev->mtr_unfree_list_mutex);
}

void hns_roce_add_unfree_umem(struct hns_roce_user_db_page *user_page,
@@ -1321,20 +1321,20 @@ void hns_roce_add_unfree_umem(struct hns_roce_user_db_page *user_page,

	pos->umem = user_page->umem;

	spin_lock(&hr_dev->umem_unfree_list_lock);
	mutex_lock(&hr_dev->umem_unfree_list_mutex);
	list_add_tail(&pos->list, &hr_dev->umem_unfree_list);
	spin_unlock(&hr_dev->umem_unfree_list_lock);
	mutex_unlock(&hr_dev->umem_unfree_list_mutex);
}

void hns_roce_free_unfree_umem(struct hns_roce_dev *hr_dev)
{
	struct hns_roce_umem_node *pos, *next;

	spin_lock(&hr_dev->umem_unfree_list_lock);
	mutex_lock(&hr_dev->umem_unfree_list_mutex);
	list_for_each_entry_safe(pos, next, &hr_dev->umem_unfree_list, list) {
		list_del(&pos->list);
		ib_umem_release(pos->umem);
		kvfree(pos);
	}
	spin_unlock(&hr_dev->umem_unfree_list_lock);
	mutex_unlock(&hr_dev->umem_unfree_list_mutex);
}