summaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/ulp/rtrs/rtrs-srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/ulp/rtrs/rtrs-srv.c')
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-srv.c199
1 files changed, 118 insertions, 81 deletions
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
index 0fa116cabc44..3df290086169 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
@@ -67,59 +67,33 @@ static inline struct rtrs_srv_sess *to_srv_sess(struct rtrs_sess *s)
return container_of(s, struct rtrs_srv_sess, s);
}
-static bool __rtrs_srv_change_state(struct rtrs_srv_sess *sess,
- enum rtrs_srv_state new_state)
+static bool rtrs_srv_change_state(struct rtrs_srv_sess *sess,
+ enum rtrs_srv_state new_state)
{
enum rtrs_srv_state old_state;
bool changed = false;
- lockdep_assert_held(&sess->state_lock);
+ spin_lock_irq(&sess->state_lock);
old_state = sess->state;
switch (new_state) {
case RTRS_SRV_CONNECTED:
- switch (old_state) {
- case RTRS_SRV_CONNECTING:
+ if (old_state == RTRS_SRV_CONNECTING)
changed = true;
- fallthrough;
- default:
- break;
- }
break;
case RTRS_SRV_CLOSING:
- switch (old_state) {
- case RTRS_SRV_CONNECTING:
- case RTRS_SRV_CONNECTED:
+ if (old_state == RTRS_SRV_CONNECTING ||
+ old_state == RTRS_SRV_CONNECTED)
changed = true;
- fallthrough;
- default:
- break;
- }
break;
case RTRS_SRV_CLOSED:
- switch (old_state) {
- case RTRS_SRV_CLOSING:
+ if (old_state == RTRS_SRV_CLOSING)
changed = true;
- fallthrough;
- default:
- break;
- }
break;
default:
break;
}
if (changed)
sess->state = new_state;
-
- return changed;
-}
-
-static bool rtrs_srv_change_state(struct rtrs_srv_sess *sess,
- enum rtrs_srv_state new_state)
-{
- bool changed;
-
- spin_lock_irq(&sess->state_lock);
- changed = __rtrs_srv_change_state(sess, new_state);
spin_unlock_irq(&sess->state_lock);
return changed;
@@ -137,7 +111,6 @@ static void rtrs_srv_free_ops_ids(struct rtrs_srv_sess *sess)
struct rtrs_srv *srv = sess->srv;
int i;
- WARN_ON(atomic_read(&sess->ids_inflight));
if (sess->ops_ids) {
for (i = 0; i < srv->queue_depth; i++)
free_id(sess->ops_ids[i]);
@@ -152,11 +125,19 @@ static struct ib_cqe io_comp_cqe = {
.done = rtrs_srv_rdma_done
};
+static inline void rtrs_srv_inflight_ref_release(struct percpu_ref *ref)
+{
+ struct rtrs_srv_sess *sess = container_of(ref, struct rtrs_srv_sess, ids_inflight_ref);
+
+ percpu_ref_exit(&sess->ids_inflight_ref);
+ complete(&sess->complete_done);
+}
+
static int rtrs_srv_alloc_ops_ids(struct rtrs_srv_sess *sess)
{
struct rtrs_srv *srv = sess->srv;
struct rtrs_srv_op *id;
- int i;
+ int i, ret;
sess->ops_ids = kcalloc(srv->queue_depth, sizeof(*sess->ops_ids),
GFP_KERNEL);
@@ -170,8 +151,14 @@ static int rtrs_srv_alloc_ops_ids(struct rtrs_srv_sess *sess)
sess->ops_ids[i] = id;
}
- init_waitqueue_head(&sess->ids_waitq);
- atomic_set(&sess->ids_inflight, 0);
+
+ ret = percpu_ref_init(&sess->ids_inflight_ref,
+ rtrs_srv_inflight_ref_release, 0, GFP_KERNEL);
+ if (ret) {
+ pr_err("Percpu reference init failed\n");
+ goto err;
+ }
+ init_completion(&sess->complete_done);
return 0;
@@ -182,21 +169,14 @@ err:
static inline void rtrs_srv_get_ops_ids(struct rtrs_srv_sess *sess)
{
- atomic_inc(&sess->ids_inflight);
+ percpu_ref_get(&sess->ids_inflight_ref);
}
static inline void rtrs_srv_put_ops_ids(struct rtrs_srv_sess *sess)
{
- if (atomic_dec_and_test(&sess->ids_inflight))
- wake_up(&sess->ids_waitq);
+ percpu_ref_put(&sess->ids_inflight_ref);
}
-static void rtrs_srv_wait_ops_ids(struct rtrs_srv_sess *sess)
-{
- wait_event(sess->ids_waitq, !atomic_read(&sess->ids_inflight));
-}
-
-
static void rtrs_srv_reg_mr_done(struct ib_cq *cq, struct ib_wc *wc)
{
struct rtrs_srv_con *con = to_srv_con(wc->qp->qp_context);
@@ -773,7 +753,40 @@ static void rtrs_srv_sess_down(struct rtrs_srv_sess *sess)
mutex_unlock(&srv->paths_ev_mutex);
}
+static bool exist_sessname(struct rtrs_srv_ctx *ctx,
+ const char *sessname, const uuid_t *path_uuid)
+{
+ struct rtrs_srv *srv;
+ struct rtrs_srv_sess *sess;
+ bool found = false;
+
+ mutex_lock(&ctx->srv_mutex);
+ list_for_each_entry(srv, &ctx->srv_list, ctx_list) {
+ mutex_lock(&srv->paths_mutex);
+
+ /* when a client with same uuid and same sessname tried to add a path */
+ if (uuid_equal(&srv->paths_uuid, path_uuid)) {
+ mutex_unlock(&srv->paths_mutex);
+ continue;
+ }
+
+ list_for_each_entry(sess, &srv->paths_list, s.entry) {
+ if (strlen(sess->s.sessname) == strlen(sessname) &&
+ !strcmp(sess->s.sessname, sessname)) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&srv->paths_mutex);
+ if (found)
+ break;
+ }
+ mutex_unlock(&ctx->srv_mutex);
+ return found;
+}
+
static int post_recv_sess(struct rtrs_srv_sess *sess);
+static int rtrs_rdma_do_reject(struct rdma_cm_id *cm_id, int errno);
static int process_info_req(struct rtrs_srv_con *con,
struct rtrs_msg_info_req *msg)
@@ -792,10 +805,17 @@ static int process_info_req(struct rtrs_srv_con *con,
rtrs_err(s, "post_recv_sess(), err: %d\n", err);
return err;
}
+
+ if (exist_sessname(sess->srv->ctx,
+ msg->sessname, &sess->srv->paths_uuid)) {
+ rtrs_err(s, "sessname is duplicated: %s\n", msg->sessname);
+ return -EPERM;
+ }
+ strscpy(sess->s.sessname, msg->sessname, sizeof(sess->s.sessname));
+
rwr = kcalloc(sess->mrs_num, sizeof(*rwr), GFP_KERNEL);
if (unlikely(!rwr))
return -ENOMEM;
- strlcpy(sess->s.sessname, msg->sessname, sizeof(sess->s.sessname));
tx_sz = sizeof(*rsp);
tx_sz += sizeof(rsp->desc[0]) * sess->mrs_num;
@@ -1276,7 +1296,7 @@ int rtrs_srv_get_sess_name(struct rtrs_srv *srv, char *sessname, size_t len)
list_for_each_entry(sess, &srv->paths_list, s.entry) {
if (sess->state != RTRS_SRV_CONNECTED)
continue;
- strlcpy(sessname, sess->s.sessname,
+ strscpy(sessname, sess->s.sessname,
min_t(size_t, sizeof(sess->s.sessname), len));
err = 0;
break;
@@ -1288,7 +1308,7 @@ int rtrs_srv_get_sess_name(struct rtrs_srv *srv, char *sessname, size_t len)
EXPORT_SYMBOL(rtrs_srv_get_sess_name);
/**
- * rtrs_srv_get_sess_qdepth() - Get rtrs_srv qdepth.
+ * rtrs_srv_get_queue_depth() - Get rtrs_srv qdepth.
* @srv: Session
*/
int rtrs_srv_get_queue_depth(struct rtrs_srv *srv)
@@ -1356,8 +1376,10 @@ static struct rtrs_srv *get_or_create_srv(struct rtrs_srv_ctx *ctx,
* If this request is not the first connection request from the
* client for this session then fail and return error.
*/
- if (!first_conn)
+ if (!first_conn) {
+ pr_err_ratelimited("Error: Not the first connection request for this session\n");
return ERR_PTR(-ENXIO);
+ }
/* need to allocate a new srv */
srv = kzalloc(sizeof(*srv), GFP_KERNEL);
@@ -1481,6 +1503,7 @@ static void free_sess(struct rtrs_srv_sess *sess)
kobject_del(&sess->kobj);
kobject_put(&sess->kobj);
} else {
+ kfree(sess->stats);
kfree(sess);
}
}
@@ -1503,8 +1526,15 @@ static void rtrs_srv_close_work(struct work_struct *work)
rdma_disconnect(con->c.cm_id);
ib_drain_qp(con->c.qp);
}
- /* Wait for all inflights */
- rtrs_srv_wait_ops_ids(sess);
+
+ /*
+ * Degrade ref count to the usual model with a single shared
+ * atomic_t counter
+ */
+ percpu_ref_kill(&sess->ids_inflight_ref);
+
+ /* Wait for all completion */
+ wait_for_completion(&sess->complete_done);
/* Notify upper layer if we are the last path */
rtrs_srv_sess_down(sess);
@@ -1604,7 +1634,7 @@ static int create_con(struct rtrs_srv_sess *sess,
struct rtrs_sess *s = &sess->s;
struct rtrs_srv_con *con;
- u32 cq_size, wr_queue_size;
+ u32 cq_num, max_send_wr, max_recv_wr, wr_limit;
int err, cq_vector;
con = kzalloc(sizeof(*con), GFP_KERNEL);
@@ -1619,36 +1649,42 @@ static int create_con(struct rtrs_srv_sess *sess,
con->c.sess = &sess->s;
con->c.cid = cid;
atomic_set(&con->wr_cnt, 1);
+ wr_limit = sess->s.dev->ib_dev->attrs.max_qp_wr;
if (con->c.cid == 0) {
/*
* All receive and all send (each requiring invalidate)
* + 2 for drain and heartbeat
*/
- wr_queue_size = SERVICE_CON_QUEUE_DEPTH * 3 + 2;
- cq_size = wr_queue_size;
+ max_send_wr = min_t(int, wr_limit,
+ SERVICE_CON_QUEUE_DEPTH * 2 + 2);
+ max_recv_wr = max_send_wr;
} else {
+ /* when always_invlaidate enalbed, we need linv+rinv+mr+imm */
+ if (always_invalidate)
+ max_send_wr =
+ min_t(int, wr_limit,
+ srv->queue_depth * (1 + 4) + 1);
+ else
+ max_send_wr =
+ min_t(int, wr_limit,
+ srv->queue_depth * (1 + 2) + 1);
+
+ max_recv_wr = srv->queue_depth + 1;
/*
* If we have all receive requests posted and
* all write requests posted and each read request
* requires an invalidate request + drain
* and qp gets into error state.
*/
- cq_size = srv->queue_depth * 3 + 1;
- /*
- * In theory we might have queue_depth * 32
- * outstanding requests if an unsafe global key is used
- * and we have queue_depth read requests each consisting
- * of 32 different addresses. div 3 for mlx5.
- */
- wr_queue_size = sess->s.dev->ib_dev->attrs.max_qp_wr / 3;
}
- atomic_set(&con->sq_wr_avail, wr_queue_size);
+ cq_num = max_send_wr + max_recv_wr;
+ atomic_set(&con->sq_wr_avail, max_send_wr);
cq_vector = rtrs_srv_get_next_cq_vector(sess);
/* TODO: SOFTIRQ can be faster, but be careful with softirq context */
- err = rtrs_cq_qp_create(&sess->s, &con->c, 1, cq_vector, cq_size,
- wr_queue_size, wr_queue_size,
+ err = rtrs_cq_qp_create(&sess->s, &con->c, 1, cq_vector, cq_num,
+ max_send_wr, max_recv_wr,
IB_POLL_WORKQUEUE);
if (err) {
rtrs_err(s, "rtrs_cq_qp_create(), err: %d\n", err);
@@ -1728,7 +1764,7 @@ static struct rtrs_srv_sess *__alloc_sess(struct rtrs_srv *srv,
path.src = &sess->s.src_addr;
path.dst = &sess->s.dst_addr;
rtrs_addr_to_str(&path, str, sizeof(str));
- strlcpy(sess->s.sessname, str, sizeof(sess->s.sessname));
+ strscpy(sess->s.sessname, str, sizeof(sess->s.sessname));
sess->s.con_num = con_num;
sess->s.recon_cnt = recon_cnt;
@@ -1780,38 +1816,39 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
u16 version, con_num, cid;
u16 recon_cnt;
- int err;
+ int err = -ECONNRESET;
if (len < sizeof(*msg)) {
pr_err("Invalid RTRS connection request\n");
- goto reject_w_econnreset;
+ goto reject_w_err;
}
if (le16_to_cpu(msg->magic) != RTRS_MAGIC) {
pr_err("Invalid RTRS magic\n");
- goto reject_w_econnreset;
+ goto reject_w_err;
}
version = le16_to_cpu(msg->version);
if (version >> 8 != RTRS_PROTO_VER_MAJOR) {
pr_err("Unsupported major RTRS version: %d, expected %d\n",
version >> 8, RTRS_PROTO_VER_MAJOR);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
con_num = le16_to_cpu(msg->cid_num);
if (con_num > 4096) {
/* Sanity check */
pr_err("Too many connections requested: %d\n", con_num);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
cid = le16_to_cpu(msg->cid);
if (cid >= con_num) {
/* Sanity check */
pr_err("Incorrect cid: %d >= %d\n", cid, con_num);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
recon_cnt = le16_to_cpu(msg->recon_cnt);
srv = get_or_create_srv(ctx, &msg->paths_uuid, msg->first_conn);
if (IS_ERR(srv)) {
err = PTR_ERR(srv);
+ pr_err("get_or_create_srv(), error %d\n", err);
goto reject_w_err;
}
mutex_lock(&srv->paths_mutex);
@@ -1826,7 +1863,7 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
rtrs_err(s, "Session in wrong state: %s\n",
rtrs_srv_state_str(sess->state));
mutex_unlock(&srv->paths_mutex);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
/*
* Sanity checks
@@ -1835,13 +1872,13 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
rtrs_err(s, "Incorrect request: %d, %d\n",
cid, con_num);
mutex_unlock(&srv->paths_mutex);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
if (s->con[cid]) {
rtrs_err(s, "Connection already exists: %d\n",
cid);
mutex_unlock(&srv->paths_mutex);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
} else {
sess = __alloc_sess(srv, cm_id, con_num, recon_cnt,
@@ -1850,11 +1887,13 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
mutex_unlock(&srv->paths_mutex);
put_srv(srv);
err = PTR_ERR(sess);
+ pr_err("RTRS server session allocation failed: %d\n", err);
goto reject_w_err;
}
}
err = create_con(sess, cm_id, cid);
if (err) {
+ rtrs_err((&sess->s), "create_con(), error %d\n", err);
(void)rtrs_rdma_do_reject(cm_id, err);
/*
* Since session has other connections we follow normal way
@@ -1865,6 +1904,7 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
}
err = rtrs_rdma_do_accept(sess, cm_id);
if (err) {
+ rtrs_err((&sess->s), "rtrs_rdma_do_accept(), error %d\n", err);
(void)rtrs_rdma_do_reject(cm_id, err);
/*
* Since current connection was successfully added to the
@@ -1882,9 +1922,6 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
reject_w_err:
return rtrs_rdma_do_reject(cm_id, err);
-reject_w_econnreset:
- return rtrs_rdma_do_reject(cm_id, -ECONNRESET);
-
close_and_return_err:
mutex_unlock(&srv->paths_mutex);
close_sess(sess);
@@ -2177,9 +2214,9 @@ static int check_module_params(void)
sess_queue_depth, 1, MAX_SESS_QUEUE_DEPTH);
return -EINVAL;
}
- if (max_chunk_size < 4096 || !is_power_of_2(max_chunk_size)) {
+ if (max_chunk_size < MIN_CHUNK_SIZE || !is_power_of_2(max_chunk_size)) {
pr_err("Invalid max_chunk_size value %d, has to be >= %d and should be power of two.\n",
- max_chunk_size, 4096);
+ max_chunk_size, MIN_CHUNK_SIZE);
return -EINVAL;
}