struct rds_connection *conn, *parent = NULL;
struct hlist_head *head = rds_conn_bucket(laddr, faddr);
struct rds_transport *loop_trans;
+ struct rds_conn_path *free_cp = NULL;
unsigned long flags;
int ret, i;
int npaths = (trans->t_mp_capable ? RDS_MPATH_WORKERS : 1);
__rds_conn_path_init(conn, &conn->c_path[i],
is_outgoing);
conn->c_path[i].cp_index = i;
- conn->c_path[i].cp_wq = rds_wq;
+ conn->c_path[i].cp_wq =
+ alloc_ordered_workqueue("krds_cp_wq#%lu/%d", 0,
+ rds_conn_count, i);
+ if (!conn->c_path[i].cp_wq)
+ conn->c_path[i].cp_wq = rds_wq;
}
rcu_read_lock();
if (rds_destroy_pending(conn))
ret = trans->conn_alloc(conn, GFP_ATOMIC);
if (ret) {
rcu_read_unlock();
- kfree(conn->c_path);
+ free_cp = conn->c_path;
kmem_cache_free(rds_conn_slab, conn);
conn = ERR_PTR(ret);
goto out;
/* Creating passive conn */
if (parent->c_passive) {
trans->conn_free(conn->c_path[0].cp_transport_data);
- kfree(conn->c_path);
+ free_cp = conn->c_path;
kmem_cache_free(rds_conn_slab, conn);
conn = parent->c_passive;
} else {
if (cp->cp_transport_data)
trans->conn_free(cp->cp_transport_data);
}
- kfree(conn->c_path);
+ free_cp = conn->c_path;
kmem_cache_free(rds_conn_slab, conn);
conn = found;
} else {
rcu_read_unlock();
out:
+ if (free_cp) {
+ for (i = 0; i < npaths; i++)
+ if (free_cp[i].cp_wq != rds_wq)
+ destroy_workqueue(free_cp[i].cp_wq);
+ kfree(free_cp);
+ }
+
return conn;
}
WARN_ON(delayed_work_pending(&cp->cp_conn_w));
WARN_ON(work_pending(&cp->cp_down_w));
+ if (cp->cp_wq != rds_wq) {
+ destroy_workqueue(cp->cp_wq);
+ cp->cp_wq = NULL;
+ }
+
cp->cp_conn->c_trans->conn_free(cp->cp_transport_data);
}