From: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
To: target-devel <target-devel@vger.kernel.org>,
linux-rdma <linux-rdma@vger.kernel.org>
Cc: linux-scsi <linux-scsi@vger.kernel.org>,
Roland Dreier <roland@purestorage.com>,
Bart Van Assche <bvanassche@acm.org>,
"Nicholas A. Bellinger" <nab@linux-iscsi.org>
Subject: [PATCH 2/9] ib_srpt: Avoid failed multipart RDMA transfers
Date: Mon, 24 Oct 2011 05:33:35 +0000 [thread overview]
Message-ID: <1319434422-15354-3-git-send-email-nab@linux-iscsi.org> (raw)
In-Reply-To: <1319434422-15354-1-git-send-email-nab@linux-iscsi.org>
From: Bart Van Assche <bvanassche@acm.org>
Multipart RDMA transfers can fail after one or more but not all RDMA
transfers have been initiated because either an IB cable has been pulled
or the ib_srpt kernel module has been unloaded while an RDMA transfer is
being setup.
This is a bugfix port from SCST svn r3632 as recommended by Bart Van
Assche.
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: Roland Dreier <roland@purestorage.com>
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
---
drivers/infiniband/ulp/srpt/ib_srpt.c | 101 +++++++++++++++++++++-----------
drivers/infiniband/ulp/srpt/ib_srpt.h | 26 +++++++-
2 files changed, 88 insertions(+), 39 deletions(-)
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 383994d..6aba709 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -807,7 +807,7 @@ static int srpt_post_recv(struct srpt_device *sdev,
struct ib_recv_wr wr, *bad_wr;
BUG_ON(!sdev);
- wr.wr_id = encode_wr_id(IB_WC_RECV, ioctx->ioctx.index);
+ wr.wr_id = encode_wr_id(SRPT_RECV, ioctx->ioctx.index);
list.addr = ioctx->ioctx.dma;
list.length = srp_max_req_size;
@@ -849,7 +849,7 @@ static int srpt_post_send(struct srpt_rdma_ch *ch,
list.lkey = sdev->mr->lkey;
wr.next = NULL;
- wr.wr_id = encode_wr_id(IB_WC_SEND, ioctx->ioctx.index);
+ wr.wr_id = encode_wr_id(SRPT_SEND, ioctx->ioctx.index);
wr.sg_list = &list;
wr.num_sge = 1;
wr.opcode = IB_WR_SEND;
@@ -1494,17 +1494,26 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
* check_stop_free() callback.
*/
static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
- struct srpt_send_ioctx *ioctx)
+ struct srpt_send_ioctx *ioctx,
+ enum srpt_opcode opcode)
{
WARN_ON(ioctx->n_rdma <= 0);
atomic_add(ioctx->n_rdma, &ch->sq_wr_avail);
- if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
- SRPT_STATE_DATA_IN))
- transport_generic_handle_data(&ioctx->cmd);
- else
- printk(KERN_ERR "%s[%d]: wrong state = %d\n", __func__,
- __LINE__, srpt_get_cmd_state(ioctx));
+ if (opcode == SRPT_RDMA_READ_LAST) {
+ if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
+ SRPT_STATE_DATA_IN))
+ transport_generic_handle_data(&ioctx->cmd);
+ else
+ printk(KERN_ERR "%s[%d]: wrong state = %d\n", __func__,
+ __LINE__, srpt_get_cmd_state(ioctx));
+ } else if (opcode == SRPT_RDMA_ABORT) {
+ ioctx->rdma_aborted = true;
+ } else {
+ WARN_ON(opcode != SRPT_RDMA_READ_LAST);
+ printk(KERN_ERR "%s[%d]: scmnd == NULL (opcode %d)", __func__,
+ __LINE__, opcode);
+ }
}
/**
@@ -1512,7 +1521,7 @@ static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
*/
static void srpt_handle_rdma_err_comp(struct srpt_rdma_ch *ch,
struct srpt_send_ioctx *ioctx,
- u8 opcode)
+ enum srpt_opcode opcode)
{
struct se_cmd *cmd;
enum srpt_command_state state;
@@ -1520,7 +1529,7 @@ static void srpt_handle_rdma_err_comp(struct srpt_rdma_ch *ch,
cmd = &ioctx->cmd;
state = srpt_get_cmd_state(ioctx);
switch (opcode) {
- case IB_WC_RDMA_READ:
+ case SRPT_RDMA_READ_LAST:
if (ioctx->n_rdma <= 0) {
printk(KERN_ERR "Received invalid RDMA read"
" error completion with idx %d\n",
@@ -1534,9 +1543,8 @@ static void srpt_handle_rdma_err_comp(struct srpt_rdma_ch *ch,
printk(KERN_ERR "%s[%d]: wrong state = %d\n",
__func__, __LINE__, state);
break;
- case IB_WC_RDMA_WRITE:
- atomic_set(&ioctx->cmd.transport_lun_stop,
- 1);
+ case SRPT_RDMA_WRITE_LAST:
+ atomic_set(&ioctx->cmd.transport_lun_stop, 1);
break;
default:
printk(KERN_ERR "%s[%d]: opcode = %u\n", __func__,
@@ -2041,33 +2049,32 @@ static void srpt_process_send_completion(struct ib_cq *cq,
{
struct srpt_send_ioctx *send_ioctx;
uint32_t index;
- u8 opcode;
+ enum srpt_opcode opcode;
index = idx_from_wr_id(wc->wr_id);
opcode = opcode_from_wr_id(wc->wr_id);
send_ioctx = ch->ioctx_ring[index];
if (wc->status == IB_WC_SUCCESS) {
- if (opcode == IB_WC_SEND)
+ if (opcode == SRPT_SEND)
srpt_handle_send_comp(ch, send_ioctx);
else {
- WARN_ON(wc->opcode != IB_WC_RDMA_READ);
- srpt_handle_rdma_comp(ch, send_ioctx);
+ WARN_ON(opcode != SRPT_RDMA_ABORT &&
+ wc->opcode != IB_WC_RDMA_READ);
+ srpt_handle_rdma_comp(ch, send_ioctx, opcode);
}
} else {
- if (opcode == IB_WC_SEND) {
+ if (opcode == SRPT_SEND) {
printk(KERN_INFO "sending response for idx %u failed"
" with status %d\n", index, wc->status);
srpt_handle_send_err_comp(ch, wc->wr_id);
- } else {
- printk(KERN_INFO "RDMA %s for idx %u failed with status"
- " %d\n", opcode == IB_WC_RDMA_READ ? "read"
- : opcode == IB_WC_RDMA_WRITE ? "write"
- : "???", index, wc->status);
+ } else if (opcode != SRPT_RDMA_MID) {
+ printk(KERN_INFO "RDMA t %d for idx %u failed with"
+ " status %d", opcode, index, wc->status);
srpt_handle_rdma_err_comp(ch, send_ioctx, opcode);
}
}
- while (unlikely(opcode == IB_WC_SEND
+ while (unlikely(opcode == SRPT_SEND
&& !list_empty(&ch->cmd_wait_list)
&& srpt_get_ch_state(ch) == CH_LIVE
&& (send_ioctx = srpt_get_send_ioctx(ch)) != NULL)) {
@@ -2091,7 +2098,7 @@ static void srpt_process_completion(struct ib_cq *cq, struct srpt_rdma_ch *ch)
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
while ((n = ib_poll_cq(cq, ARRAY_SIZE(ch->wc), wc)) > 0) {
for (i = 0; i < n; i++) {
- if (opcode_from_wr_id(wc[i].wr_id) & IB_WC_RECV)
+ if (opcode_from_wr_id(wc[i].wr_id) == SRPT_RECV)
srpt_process_rcv_completion(cq, ch, &wc[i]);
else
srpt_process_send_completion(cq, ch, &wc[i]);
@@ -2882,32 +2889,37 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch,
int ret;
int sq_wr_avail;
enum dma_data_direction dir;
+ const int n_rdma = ioctx->n_rdma;
dir = ioctx->cmd.data_direction;
if (dir == DMA_TO_DEVICE) {
/* write */
ret = -ENOMEM;
- sq_wr_avail = atomic_sub_return(ioctx->n_rdma,
- &ch->sq_wr_avail);
+ sq_wr_avail = atomic_sub_return(n_rdma, &ch->sq_wr_avail);
if (sq_wr_avail < 0) {
printk(KERN_WARNING "IB send queue full (needed %d)\n",
- ioctx->n_rdma);
+ n_rdma);
goto out;
}
}
+ ioctx->rdma_aborted = false;
ret = 0;
riu = ioctx->rdma_ius;
memset(&wr, 0, sizeof wr);
- for (i = 0; i < ioctx->n_rdma; ++i, ++riu) {
+ for (i = 0; i < n_rdma; ++i, ++riu) {
if (dir == DMA_FROM_DEVICE) {
wr.opcode = IB_WR_RDMA_WRITE;
- wr.wr_id = encode_wr_id(IB_WC_RDMA_WRITE,
+ wr.wr_id = encode_wr_id(i == n_rdma - 1 ?
+ SRPT_RDMA_WRITE_LAST :
+ SRPT_RDMA_MID,
ioctx->ioctx.index);
} else {
wr.opcode = IB_WR_RDMA_READ;
- wr.wr_id = encode_wr_id(IB_WC_RDMA_READ,
+ wr.wr_id = encode_wr_id(i == n_rdma - 1 ?
+ SRPT_RDMA_READ_LAST :
+ SRPT_RDMA_MID,
ioctx->ioctx.index);
}
wr.next = NULL;
@@ -2917,17 +2929,36 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch,
wr.sg_list = riu->sge;
/* only get completion event for the last rdma write */
- if (i == (ioctx->n_rdma - 1) && dir == DMA_TO_DEVICE)
+ if (i == (n_rdma - 1) && dir == DMA_TO_DEVICE)
wr.send_flags = IB_SEND_SIGNALED;
ret = ib_post_send(ch->qp, &wr, &bad_wr);
if (ret)
- goto out;
+ break;
}
+ if (ret)
+ printk(KERN_ERR "%s[%d]: ib_post_send() returned %d for %d/%d",
+ __func__, __LINE__, ret, i, n_rdma);
+ if (ret && i > 0) {
+ wr.num_sge = 0;
+ wr.wr_id = encode_wr_id(SRPT_RDMA_ABORT, ioctx->ioctx.index);
+ wr.send_flags = IB_SEND_SIGNALED;
+ while (ch->state == CH_LIVE &&
+ ib_post_send(ch->qp, &wr, &bad_wr) != 0) {
+ printk(KERN_INFO "Trying to abort failed RDMA transfer [%d]",
+ ioctx->ioctx.index);
+ msleep(1000);
+ }
+ while (ch->state != CH_RELEASING && !ioctx->rdma_aborted) {
+ printk(KERN_INFO "Waiting until RDMA abort finished [%d]",
+ ioctx->ioctx.index);
+ msleep(1000);
+ }
+ }
out:
if (unlikely(dir == DMA_TO_DEVICE && ret < 0))
- atomic_add(ioctx->n_rdma, &ch->sq_wr_avail);
+ atomic_add(n_rdma, &ch->sq_wr_avail);
return ret;
}
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h
index 045fb7b..59ee2d7 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.h
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.h
@@ -127,12 +127,27 @@ enum {
DEFAULT_MAX_RDMA_SIZE = 65536,
};
+enum srpt_opcode {
+ SRPT_RECV,
+ SRPT_SEND,
+ SRPT_RDMA_MID,
+ SRPT_RDMA_ABORT,
+ SRPT_RDMA_READ_LAST,
+ SRPT_RDMA_WRITE_LAST,
+};
+
static inline u64 encode_wr_id(u8 opcode, u32 idx)
-{ return ((u64)opcode << 32) | idx; }
-static inline u8 opcode_from_wr_id(u64 wr_id)
-{ return wr_id >> 32; }
+{
+ return ((u64)opcode << 32) | idx;
+}
+static inline enum srpt_opcode opcode_from_wr_id(u64 wr_id)
+{
+ return wr_id >> 32;
+}
static inline u32 idx_from_wr_id(u64 wr_id)
-{ return (u32)wr_id; }
+{
+ return (u32)wr_id;
+}
struct rdma_iu {
u64 raddr;
@@ -204,6 +219,8 @@ struct srpt_recv_ioctx {
* @tag: Tag of the received SRP information unit.
* @spinlock: Protects 'state'.
* @state: I/O context state.
+ * @rdma_aborted: If initiating a multipart RDMA transfer failed, whether
+ * the already initiated transfers have finished.
* @cmd: Target core command data structure.
* @sense_data: SCSI sense data.
*/
@@ -218,6 +235,7 @@ struct srpt_send_ioctx {
struct list_head free_list;
spinlock_t spinlock;
enum srpt_command_state state;
+ bool rdma_aborted;
struct se_cmd cmd;
struct completion tx_done;
u64 tag;
--
1.7.2.5
next prev parent reply other threads:[~2011-10-24 5:33 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-24 5:33 [PATCH 0/9] ib_srpt: Changes from RFC for v3.2-rc1 mainline merge Nicholas A. Bellinger
2011-10-24 5:33 ` [PATCH 1/9] ib_srpt: Fix potential out-of-bounds array access Nicholas A. Bellinger
2011-10-24 5:33 ` Nicholas A. Bellinger [this message]
2011-10-24 5:33 ` [PATCH 3/9] ib_srpt: Fix srpt_alloc_fabric_acl failure case return value Nicholas A. Bellinger
2011-10-24 5:33 ` [PATCH 4/9] ib_srpt: Update comments to reference $driver/$port layout Nicholas A. Bellinger
2011-10-24 5:33 ` [PATCH 5/9] ib_srpt: Fix sport->port_guid formatting code Nicholas A. Bellinger
[not found] ` <1319434422-15354-6-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2011-10-24 19:57 ` Bart Van Assche
2011-10-24 20:25 ` Nicholas A. Bellinger
[not found] ` <1319487952.17450.72.camel-Y1+j5t8j3WgjMeEPmliV8E/sVC8ogwMJ@public.gmane.org>
2011-10-26 18:23 ` Bart Van Assche
[not found] ` <CAO+b5-qjOT2rqeLn=DJi5ogk+KTV8_Fi0tYwj4gECtcSNNhHRQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-10-27 0:37 ` Nicholas A. Bellinger
2011-10-24 5:33 ` [PATCH 6/9] ib_srpt: Remove legacy use_port_guid_in_session_name module parameter Nicholas A. Bellinger
[not found] ` <1319434422-15354-7-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2011-10-24 18:24 ` Bart Van Assche
2011-10-24 5:33 ` [PATCH 7/9] ib_srpt: Convert srp_max_rdma_size into per port configfs attribute Nicholas A. Bellinger
[not found] ` <1319434422-15354-8-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2011-10-24 16:34 ` Bart Van Assche
2011-10-24 18:27 ` Nicholas A. Bellinger
2011-10-24 20:29 ` Nicholas A. Bellinger
[not found] ` <1319488195.17450.73.camel-Y1+j5t8j3WgjMeEPmliV8E/sVC8ogwMJ@public.gmane.org>
2011-10-25 6:22 ` Nicholas A. Bellinger
2011-10-25 10:32 ` Bart Van Assche
[not found] ` <CAO+b5-p9xXB_sWes=uet6skkFn=xWD+vKuoOeuGwjbxYhE-ctg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-10-25 10:35 ` Nicholas A. Bellinger
2011-10-24 5:33 ` [PATCH 8/9] ib_srpt: Convert srp_max_rsp_size " Nicholas A. Bellinger
[not found] ` <1319434422-15354-9-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2011-10-24 19:44 ` Bart Van Assche
[not found] ` <CAO+b5-p24uYKbwqCRWVik63gL-ZABgcJrqAi7ULJZEP+CK1WEg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-10-24 19:49 ` Nicholas A. Bellinger
[not found] ` <1319485752.17450.57.camel-Y1+j5t8j3WgjMeEPmliV8E/sVC8ogwMJ@public.gmane.org>
2011-10-24 19:58 ` Bart Van Assche
2011-10-24 20:05 ` Nicholas A. Bellinger
[not found] ` <1319486723.17450.59.camel-Y1+j5t8j3WgjMeEPmliV8E/sVC8ogwMJ@public.gmane.org>
2011-10-24 20:11 ` Bart Van Assche
2011-10-24 20:19 ` Nicholas A. Bellinger
2011-10-24 20:16 ` Bart Van Assche
[not found] ` <CAO+b5-rzo478a07CuaYS2itAdV9dK65+GHj2Si4PZFM6qkmL3A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-10-24 20:22 ` Nicholas A. Bellinger
2011-10-24 5:33 ` [PATCH 9/9] ib_srpt: Convert srpt_sq_size " Nicholas A. Bellinger
[not found] ` <1319434422-15354-10-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2011-10-24 18:32 ` Bart Van Assche
2011-10-24 18:39 ` Nicholas A. Bellinger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1319434422-15354-3-git-send-email-nab@linux-iscsi.org \
--to=nab@linux-iscsi.org \
--cc=bvanassche@acm.org \
--cc=linux-rdma@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=roland@purestorage.com \
--cc=target-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox