Skip to content

Commit

Permalink
RDMA/siw: Fix handling of zero-sized Read and Receive Queues.
Browse files Browse the repository at this point in the history
During connection setup, the application may choose to zero-size
inbound and outbound READ queues, as well as the Receive queue.
This patch fixes handling of zero-sized queues.

Reported-by: Kamal Heib <kamalheib1@gmail.com>
Reported-by: Yi Zhang <yi.zhang@redhat.com>
Signed-off-by: Bernard Metzler <bmt@zurich.ibm.com>
  • Loading branch information
BernardMetzler authored and intel-lab-lkp committed Dec 15, 2020
1 parent d21a124 commit 2626590
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 36 deletions.
2 changes: 1 addition & 1 deletion drivers/infiniband/sw/siw/siw.h
Expand Up @@ -653,7 +653,7 @@ static inline struct siw_sqe *orq_get_free(struct siw_qp *qp)
{
struct siw_sqe *orq_e = orq_get_tail(qp);

if (orq_e && READ_ONCE(orq_e->flags) == 0)
if (READ_ONCE(orq_e->flags) == 0)
return orq_e;

return NULL;
Expand Down
54 changes: 33 additions & 21 deletions drivers/infiniband/sw/siw/siw_qp.c
Expand Up @@ -199,26 +199,28 @@ void siw_qp_llp_write_space(struct sock *sk)

static int siw_qp_readq_init(struct siw_qp *qp, int irq_size, int orq_size)
{
irq_size = roundup_pow_of_two(irq_size);
orq_size = roundup_pow_of_two(orq_size);

qp->attrs.irq_size = irq_size;
qp->attrs.orq_size = orq_size;

qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe));
if (!qp->irq) {
siw_dbg_qp(qp, "irq malloc for %d failed\n", irq_size);
qp->attrs.irq_size = 0;
return -ENOMEM;
if (irq_size) {
irq_size = roundup_pow_of_two(irq_size);
qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe));
if (!qp->irq) {
siw_dbg_qp(qp, "irq malloc for %d failed\n", irq_size);
qp->attrs.irq_size = 0;
return -ENOMEM;
}
}
qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe));
if (!qp->orq) {
siw_dbg_qp(qp, "orq malloc for %d failed\n", orq_size);
qp->attrs.orq_size = 0;
qp->attrs.irq_size = 0;
vfree(qp->irq);
return -ENOMEM;
if (orq_size) {
orq_size = roundup_pow_of_two(orq_size);
qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe));
if (!qp->orq) {
siw_dbg_qp(qp, "orq malloc for %d failed\n", orq_size);
qp->attrs.orq_size = 0;
qp->attrs.irq_size = 0;
vfree(qp->irq);
return -ENOMEM;
}
}
qp->attrs.irq_size = irq_size;
qp->attrs.orq_size = orq_size;
siw_dbg_qp(qp, "ORD %d, IRD %d\n", orq_size, irq_size);
return 0;
}
Expand Down Expand Up @@ -288,13 +290,14 @@ int siw_qp_mpa_rts(struct siw_qp *qp, enum mpa_v2_ctrl ctrl)
if (ctrl & MPA_V2_RDMA_WRITE_RTR)
wqe->sqe.opcode = SIW_OP_WRITE;
else if (ctrl & MPA_V2_RDMA_READ_RTR) {
struct siw_sqe *rreq;
struct siw_sqe *rreq = NULL;

wqe->sqe.opcode = SIW_OP_READ;

spin_lock(&qp->orq_lock);

rreq = orq_get_free(qp);
if (qp->attrs.orq_size)
rreq = orq_get_free(qp);
if (rreq) {
siw_read_to_orq(rreq, &wqe->sqe);
qp->orq_put++;
Expand Down Expand Up @@ -889,6 +892,9 @@ int siw_activate_tx(struct siw_qp *qp)
struct siw_wqe *wqe = tx_wqe(qp);
int rv = 1;

if (!qp->attrs.irq_size)
goto no_irq;

irqe = &qp->irq[qp->irq_get % qp->attrs.irq_size];

if (irqe->flags & SIW_WQE_VALID) {
Expand Down Expand Up @@ -933,6 +939,7 @@ int siw_activate_tx(struct siw_qp *qp)

goto out;
}
no_irq:
sqe = sq_get_next(qp);
if (sqe) {
skip_irq:
Expand Down Expand Up @@ -971,7 +978,7 @@ int siw_activate_tx(struct siw_qp *qp)
}
spin_lock(&qp->orq_lock);

if (!siw_orq_empty(qp)) {
if (qp->attrs.orq_size && !siw_orq_empty(qp)) {
qp->tx_ctx.orq_fence = 1;
rv = 0;
}
Expand All @@ -981,6 +988,11 @@ int siw_activate_tx(struct siw_qp *qp)
wqe->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
struct siw_sqe *rreq;

if (unlikely(!qp->attrs.orq_size)) {
/* We negotiated not to send READ req's */
rv = -EINVAL;
goto out;
}
wqe->sqe.num_sge = 1;

spin_lock(&qp->orq_lock);
Expand Down
26 changes: 18 additions & 8 deletions drivers/infiniband/sw/siw/siw_qp_rx.c
Expand Up @@ -678,6 +678,10 @@ static int siw_init_rresp(struct siw_qp *qp, struct siw_rx_stream *srx)
DDP_ECODE_UT_INVALID_MSN_RANGE, 0);
return -EPROTO;
}
if (unlikely(!qp->attrs.irq_size)) {
run_sq = 0;
goto error_irq;
}
spin_lock_irqsave(&qp->sq_lock, flags);

if (tx_work->wr_status == SIW_WR_IDLE) {
Expand Down Expand Up @@ -712,8 +716,9 @@ static int siw_init_rresp(struct siw_qp *qp, struct siw_rx_stream *srx)
/* RRESP now valid as current TX wqe or placed into IRQ */
smp_store_mb(resp->flags, SIW_WQE_VALID);
} else {
pr_warn("siw: [QP %u]: irq %d exceeded %d\n", qp_id(qp),
qp->irq_put % qp->attrs.irq_size, qp->attrs.irq_size);
error_irq:
pr_warn("siw: [QP %u]: IRQ exceeded or null, size %d\n",
qp_id(qp), qp->attrs.irq_size);

siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
RDMAP_ETYPE_REMOTE_OPERATION,
Expand All @@ -740,6 +745,9 @@ static int siw_orqe_start_rx(struct siw_qp *qp)
struct siw_sqe *orqe;
struct siw_wqe *wqe = NULL;

if (unlikely(!qp->attrs.orq_size))
return -EPROTO;

/* make sure ORQ indices are current */
smp_mb();

Expand Down Expand Up @@ -796,8 +804,8 @@ int siw_proc_rresp(struct siw_qp *qp)
*/
rv = siw_orqe_start_rx(qp);
if (rv) {
pr_warn("siw: [QP %u]: ORQ empty at idx %d\n",
qp_id(qp), qp->orq_get % qp->attrs.orq_size);
pr_warn("siw: [QP %u]: ORQ empty, size %d\n",
qp_id(qp), qp->attrs.orq_size);
goto error_term;
}
rv = siw_rresp_check_ntoh(srx, frx);
Expand Down Expand Up @@ -1290,11 +1298,13 @@ static int siw_rdmap_complete(struct siw_qp *qp, int error)
wc_status);
siw_wqe_put_mem(wqe, SIW_OP_READ);

if (!error)
if (!error) {
rv = siw_check_tx_fence(qp);
else
/* Disable current ORQ eleement */
WRITE_ONCE(orq_get_current(qp)->flags, 0);
} else {
/* Disable current ORQ element */
if (qp->attrs.orq_size)
WRITE_ONCE(orq_get_current(qp)->flags, 0);
}
break;

case RDMAP_RDMA_READ_REQ:
Expand Down
4 changes: 2 additions & 2 deletions drivers/infiniband/sw/siw/siw_qp_tx.c
Expand Up @@ -1107,8 +1107,8 @@ int siw_qp_sq_process(struct siw_qp *qp)
/*
* RREQ may have already been completed by inbound RRESP!
*/
if (tx_type == SIW_OP_READ ||
tx_type == SIW_OP_READ_LOCAL_INV) {
if ((tx_type == SIW_OP_READ ||
tx_type == SIW_OP_READ_LOCAL_INV) && qp->attrs.orq_size) {
/* Cleanup pending entry in ORQ */
qp->orq_put--;
qp->orq[qp->orq_put % qp->attrs.orq_size].flags = 0;
Expand Down
18 changes: 14 additions & 4 deletions drivers/infiniband/sw/siw/siw_verbs.c
Expand Up @@ -365,13 +365,23 @@ struct ib_qp *siw_create_qp(struct ib_pd *pd,
if (rv)
goto err_out;

num_sqe = attrs->cap.max_send_wr;
num_rqe = attrs->cap.max_recv_wr;

/* All queue indices are derived from modulo operations
* on a free running 'get' (consumer) and 'put' (producer)
* unsigned counter. Having queue sizes at power of two
* avoids handling counter wrap around.
*/
num_sqe = roundup_pow_of_two(attrs->cap.max_send_wr);
num_rqe = roundup_pow_of_two(attrs->cap.max_recv_wr);
if (num_sqe)
num_sqe = roundup_pow_of_two(num_sqe);
else {
/* Zero sized SQ is not supported */
rv = -EINVAL;
goto err_out;
}
if (num_rqe)
num_rqe = roundup_pow_of_two(num_rqe);

if (udata)
qp->sendq = vmalloc_user(num_sqe * sizeof(struct siw_sqe));
Expand Down Expand Up @@ -966,9 +976,9 @@ int siw_post_receive(struct ib_qp *base_qp, const struct ib_recv_wr *wr,
unsigned long flags;
int rv = 0;

if (qp->srq) {
if (qp->srq || qp->attrs.rq_size == 0) {
*bad_wr = wr;
return -EOPNOTSUPP; /* what else from errno.h? */
return -EINVAL;
}
if (!rdma_is_kernel_res(&qp->base_qp.res)) {
siw_dbg_qp(qp, "no kernel post_recv for user mapped rq\n");
Expand Down

0 comments on commit 2626590

Please sign in to comment.