From 6abef3d29cc072351a08867267a575461600b80b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 12 Jul 2021 03:12:48 +0000 Subject: [PATCH] isert-scst: Fix handling of RDMA_CV_EVENT_ADDR_CHANGE During processing RDMA_CM_EVENT_ADDR_CHANGE event rdma_bind_addr in isert_setup_id function from isert_cm_evt_listener_handler returns error -98 [EADDRINUSE]. In principle, it is logical, because at that time the socket address was still bound to the old cma_id which will be destroyed via rdma_destroy_id only after processing the RDMA_CM_EVENT_ADDR_CHANGE event. Move the creation of the cma_id in workqueue context and delete old cma_id directly, not through returning the error code to the upper level. Signed-off-by: Chesnokov Gleb git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9484 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/isert-scst/iser.h | 2 ++ iscsi-scst/kernel/isert-scst/iser_rdma.c | 42 +++++++++++++++++++----- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/iscsi-scst/kernel/isert-scst/iser.h b/iscsi-scst/kernel/isert-scst/iser.h index b372324ed..9dbadf816 100644 --- a/iscsi-scst/kernel/isert-scst/iser.h +++ b/iscsi-scst/kernel/isert-scst/iser.h @@ -66,6 +66,8 @@ struct isert_portal { /* protected by dev_list_mutex */ struct list_head conn_list; /* head of conns list */ enum isert_portal_state state; + struct work_struct work; + struct workqueue_struct *reinit_id_wq; int refcnt; }; diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index 7709708df..0a8c0627e 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -1649,10 +1649,25 @@ static int isert_handle_failure(struct isert_conn *conn) return 0; } +static void isert_portal_reinit_id_work(struct work_struct *w) +{ + struct isert_portal *portal = container_of(w, struct isert_portal, work); + + rdma_destroy_id(portal->cm_id); + + portal->cm_id = isert_setup_id(portal); + if (IS_ERR(portal->cm_id)) { + PRINT_ERROR("Failed to create rdma id, err:%ld\n", + PTR_ERR(portal->cm_id)); + portal->cm_id = NULL; + } +} + static int isert_cm_evt_listener_handler(struct rdma_cm_id *cm_id, enum rdma_cm_event_type event) { struct isert_portal *portal; + int ret = -1; portal = cm_id->context; @@ -1661,12 +1676,8 @@ static int isert_cm_evt_listener_handler(struct rdma_cm_id *cm_id, portal->cm_id = NULL; break; case RDMA_CM_EVENT_ADDR_CHANGE: - portal->cm_id = isert_setup_id(portal); - if (IS_ERR(portal->cm_id)) { - PRINT_ERROR("Failed to create rdma id, err:%ld\n", - PTR_ERR(portal->cm_id)); - portal->cm_id = NULL; - } + queue_work(portal->reinit_id_wq, &portal->work); + ret = 0; break; default: PRINT_INFO("Listener event:%s(%d), ignored", @@ -1674,7 +1685,7 @@ static int isert_cm_evt_listener_handler(struct rdma_cm_id *cm_id, break; } - return -1; + return ret; } static int isert_cm_disconnect_handler(struct rdma_cm_id *cm_id, @@ -1872,6 +1883,15 @@ struct isert_portal *isert_portal_create(struct sockaddr *sa, size_t addr_len) goto err_alloc; } + portal->reinit_id_wq = alloc_ordered_workqueue("isert_reinit_id_wq", WQ_MEM_RECLAIM); + if (unlikely(!portal->reinit_id_wq)) { + PRINT_ERROR("Unable to allocate reinit workqueue"); + err = -ENOMEM; + goto free_portal; + } + + INIT_WORK(&portal->work, isert_portal_reinit_id_work); + INIT_LIST_HEAD(&portal->conn_list); isert_portal_list_add(portal); @@ -1881,7 +1901,7 @@ struct isert_portal *isert_portal_create(struct sockaddr *sa, size_t addr_len) if (IS_ERR(cm_id)) { err = PTR_ERR(cm_id); PRINT_ERROR("Failed to create rdma id, err:%d", err); - goto create_id_err; + goto free_wq; } portal->cm_id = cm_id; @@ -1890,7 +1910,9 @@ struct isert_portal *isert_portal_create(struct sockaddr *sa, size_t addr_len) out: return portal; -create_id_err: +free_wq: + destroy_workqueue(portal->reinit_id_wq); +free_portal: kfree(portal); portal = ERR_PTR(err); err_alloc: @@ -1905,6 +1927,8 @@ static void isert_portal_free(struct isert_portal *portal) if (portal->refcnt > 0) return; + destroy_workqueue(portal->reinit_id_wq); + kfree(portal); module_put(THIS_MODULE);