From: Ajaykumar Hotchandani Date: Thu, 14 Apr 2016 20:58:46 +0000 (-0700) Subject: RDS: IB: invoke connection destruction in worker X-Git-Tag: v4.1.12-92~108^2~10 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=092d30306ee4f30c63dc27267bef7993b5c55e4b;p=users%2Fjedix%2Flinux-maple.git RDS: IB: invoke connection destruction in worker This is to avoid deadlock with c_cm_lock mutex. In event handling path of Infiniband, whenever connection destruction is required; we should invoke worker in order to avoid deadlock with mutex. Orabug: 23222944 Acked-by: Santosh Shilimkar Signed-off-by: Ajaykumar Hotchandani --- diff --git a/net/rds/ib.h b/net/rds/ib.h index c1c7a629a2e7..0202c1c8f479 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -406,6 +406,11 @@ struct rds_ib_conn_drop_work { struct rds_connection *conn; }; +struct rds_ib_conn_destroy_work { + struct delayed_work work; + struct rds_connection *conn; +}; + struct rds_ib_addr_change_work { struct delayed_work work; __be32 addr; @@ -581,6 +586,7 @@ int rds_ib_cm_initiate_connect(struct rdma_cm_id *cm_id); void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_event *event); void rds_ib_init_frag(unsigned int version); +void rds_ib_conn_destroy_init(struct rds_connection *conn); #define rds_ib_conn_error(conn, fmt...) \ __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 316383fc4647..0c99711240cd 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -220,17 +220,13 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even if (conn->c_version < RDS_PROTOCOL_VERSION) { if (conn->c_version != RDS_PROTOCOL_COMPAT_VERSION) { - /* - * BUG: destroying connection here can deadlock with - * the CM event handler on the c_cm_lock. - */ printk(KERN_NOTICE "RDS/IB: Connection to" " %u.%u.%u.%u version %u.%u failed," " no longer supported\n", NIPQUAD(conn->c_faddr), RDS_PROTOCOL_MAJOR(conn->c_version), RDS_PROTOCOL_MINOR(conn->c_version)); - rds_conn_destroy(conn); + rds_ib_conn_destroy_init(conn); return; } } @@ -989,6 +985,31 @@ out: return destroy; } +void rds_ib_conn_destroy_worker(struct work_struct *_work) +{ + struct rds_ib_conn_destroy_work *work = + container_of(_work, struct rds_ib_conn_destroy_work, work.work); + struct rds_connection *conn = work->conn; + + rds_conn_destroy(conn); + + kfree(work); +} + +void rds_ib_conn_destroy_init(struct rds_connection *conn) +{ + struct rds_ib_conn_destroy_work *work; + + work = kzalloc(sizeof *work, GFP_ATOMIC); + if (!work) { + pr_err("RDS/IB: failed to allocate connection destroy work\n"); + return; + } + + work->conn = conn; + INIT_DELAYED_WORK(&work->work, rds_ib_conn_destroy_worker); + queue_delayed_work(rds_aux_wq, &work->work, 0); +} int rds_ib_cm_initiate_connect(struct rdma_cm_id *cm_id) {