- Added counter that keeps track of the number of work requests posted on

the per-channel queue pair. This counter is used to prevent that
  ib_post_send() triggers a queue overflow.
- Fixed error handling in srpt_xfer_data(): srpt_unmap_sg_to_ib_sge() is now
  called before returning an error code.
- Simplified implementation of the sysfs attribute login_info.


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1353 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2009-11-22 18:42:35 +00:00
parent c918eb371e
commit 495257b44e
2 changed files with 111 additions and 42 deletions

View File

@@ -135,6 +135,9 @@ static void srpt_unregister_mad_agent(struct srpt_device *sdev);
#ifdef CONFIG_SCST_PROC
static void srpt_unregister_procfs_entry(struct scst_tgt_template *tgt);
#endif /*CONFIG_SCST_PROC*/
static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
struct srpt_ioctx *ioctx,
struct scst_cmd *scmnd);
static struct ib_client srpt_client = {
.name = DRV_NAME,
@@ -804,6 +807,14 @@ static int srpt_post_send(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx,
struct ib_sge list;
struct ib_send_wr wr, *bad_wr;
struct srpt_device *sdev = ch->sport->sdev;
int ret;
ret = -ENOMEM;
if (atomic_dec_return(&ch->qp_wr_avail) < 0) {
atomic_inc(&ch->qp_wr_avail);
PRINT_ERROR("%s[%d]: SRQ full", __func__, __LINE__);
goto out;
}
ib_dma_sync_single_for_device(sdev->device, ioctx->dma,
len, DMA_TO_DEVICE);
@@ -819,7 +830,10 @@ static int srpt_post_send(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx,
wr.opcode = IB_WR_SEND;
wr.send_flags = IB_SEND_SIGNALED;
return ib_post_send(ch->qp, &wr, &bad_wr);
ret = ib_post_send(ch->qp, &wr, &bad_wr);
out:
return ret;
}
static int srpt_get_desc_tbl(struct srpt_ioctx *ioctx, struct srp_cmd *srp_cmd,
@@ -1572,8 +1586,17 @@ static void srpt_completion(struct ib_cq *cq, void *ctx)
} else
srpt_handle_new_iu(ch, ioctx);
continue;
} else
} else {
ioctx = sdev->ioctx_ring[wc.wr_id];
if (wc.opcode == IB_WC_SEND)
atomic_inc(&ch->qp_wr_avail);
else {
WARN_ON(wc.opcode != IB_WC_RDMA_READ);
WARN_ON(ioctx->n_rdma <= 0);
atomic_add(ioctx->n_rdma,
&ch->qp_wr_avail);
}
}
if (thread) {
ioctx->ch = ch;
@@ -1653,6 +1676,8 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
goto out;
}
atomic_set(&ch->qp_wr_avail, qp_init->cap.max_send_wr);
TRACE_DBG("%s: max_cqe= %d max_sge= %d cm_id= %p",
__func__, ch->cq->cqe, qp_init->cap.max_send_sge,
ch->cm_id);
@@ -2269,6 +2294,7 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
++riu->sge_cnt;
if (rsize > 0 && riu->sge_cnt == SRPT_DEF_SG_PER_WQE) {
++ioctx->n_rdma;
riu->sge =
kmalloc(riu->sge_cnt * sizeof *riu->sge,
scst_cmd_atomic(scmnd)
@@ -2276,7 +2302,6 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
if (!riu->sge)
goto free_mem;
++ioctx->n_rdma;
++riu;
riu->sge_cnt = 0;
riu->raddr = raddr;
@@ -2284,14 +2309,12 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
}
}
++ioctx->n_rdma;
riu->sge = kmalloc(riu->sge_cnt * sizeof *riu->sge,
scst_cmd_atomic(scmnd)
? GFP_ATOMIC : GFP_KERNEL);
if (!riu->sge)
goto free_mem;
++ioctx->n_rdma;
}
db = ioctx->rbufs;
@@ -2348,19 +2371,43 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
return 0;
free_mem:
while (ioctx->n_rdma)
kfree(ioctx->rdma_ius[ioctx->n_rdma--].sge);
kfree(ioctx->rdma_ius);
WARN_ON(scat == NULL);
ib_dma_unmap_sg(ch->sport->sdev->device,
scat, scst_cmd_get_sg_cnt(scmnd),
scst_to_tgt_dma_dir(dir));
srpt_unmap_sg_to_ib_sge(ch, ioctx, scmnd);
return -ENOMEM;
}
static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
struct srpt_ioctx *ioctx,
struct scst_cmd *scmnd)
{
struct scatterlist *scat;
scst_data_direction dir;
TRACE_ENTRY();
scat = scst_cmd_get_sg(scmnd);
TRACE_DBG("n_rdma = %d; rdma_ius = %p; scat = %p\n",
ioctx->n_rdma, ioctx->rdma_ius, scat);
BUG_ON(ioctx->n_rdma && !ioctx->rdma_ius);
while (ioctx->n_rdma)
kfree(ioctx->rdma_ius[--ioctx->n_rdma].sge);
kfree(ioctx->rdma_ius);
ioctx->rdma_ius = NULL;
if (scat) {
dir = scst_cmd_get_data_direction(scmnd);
ib_dma_unmap_sg(ch->sport->sdev->device,
scat, scst_cmd_get_sg_cnt(scmnd),
scst_to_tgt_dma_dir(dir));
}
TRACE_EXIT();
}
static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx,
scst_data_direction dir)
{
@@ -2368,8 +2415,21 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx,
struct ib_send_wr *bad_wr;
struct rdma_iu *riu;
int i;
int ret = 0;
int ret;
int srq_wr_avail;
if (dir == SCST_DATA_WRITE) {
ret = -ENOMEM;
srq_wr_avail = atomic_sub_return(ioctx->n_rdma,
&ch->qp_wr_avail);
if (srq_wr_avail < 0) {
atomic_add(ioctx->n_rdma, &ch->qp_wr_avail);
PRINT_INFO("%s[%d]: SRQ full", __func__, __LINE__);
goto out;
}
}
ret = 0;
riu = ioctx->rdma_ius;
memset(&wr, 0, sizeof wr);
@@ -2389,9 +2449,10 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx,
ret = ib_post_send(ch->qp, &wr, &bad_wr);
if (ret)
break;
goto out;
}
out:
return ret;
}
@@ -2412,18 +2473,25 @@ static int srpt_xfer_data(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx,
ret = srpt_perform_rdmas(ch, ioctx, scst_cmd_get_data_direction(scmnd));
if (ret) {
PRINT_ERROR("%s[%d] ret=%d", __func__, __LINE__, ret);
if (ret == -EAGAIN || ret == -ENOMEM)
if (ret == -EAGAIN || ret == -ENOMEM) {
PRINT_INFO("%s[%d] queue full -- ret=%d",
__func__, __LINE__, ret);
ret = SCST_TGT_RES_QUEUE_FULL;
else
} else {
PRINT_ERROR("%s[%d] fatal error -- ret=%d",
__func__, __LINE__, ret);
ret = SCST_TGT_RES_FATAL_ERROR;
goto out;
}
goto out_unmap;
}
ret = SCST_TGT_RES_SUCCESS;
out:
return ret;
out_unmap:
srpt_unmap_sg_to_ib_sge(ch, ioctx, scmnd);
goto out;
}
/*
@@ -2811,6 +2879,9 @@ static struct scst_tgt_template srpt_template = {
/*
* The callback function srpt_release_class_dev() is called whenever a
* device is removed from the /sys/class/infiniband_srpt device class.
* Although this function has been left empty, a release function has been
* defined such that upon module removal no complaint is logged about a
* missing release function.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
static void srpt_release_class_dev(struct class_device *class_dev)
@@ -2843,20 +2914,6 @@ static struct scst_proc_data srpt_log_proc_data = {
#endif /* CONFIG_SCST_PROC */
static struct class_attribute srpt_class_attrs[] = {
__ATTR_NULL,
};
static struct class srpt_class = {
.name = "infiniband_srpt",
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
.release = srpt_release_class_dev,
#else
.dev_release = srpt_release_class_dev,
#endif
.class_attrs = srpt_class_attrs,
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
static ssize_t show_login_info(struct class_device *class_dev, char *buf)
#else
@@ -2897,11 +2954,25 @@ static ssize_t show_login_info(struct device *dev,
return len;
}
static struct class_attribute srpt_class_attrs[] = {
__ATTR_NULL,
};
static struct device_attribute srpt_dev_attrs[] = {
__ATTR(login_info, S_IRUGO, show_login_info, NULL),
__ATTR_NULL,
};
static struct class srpt_class = {
.name = "infiniband_srpt",
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
static CLASS_DEVICE_ATTR(login_info, S_IRUGO, show_login_info, NULL);
.release = srpt_release_class_dev,
#else
static DEVICE_ATTR(login_info, S_IRUGO, show_login_info, NULL);
.dev_release = srpt_release_class_dev,
#endif
.class_attrs = srpt_class_attrs,
.dev_attrs = srpt_dev_attrs,
};
/*
* Callback function called by the InfiniBand core when either an InfiniBand
@@ -2943,14 +3014,9 @@ static void srpt_add_one(struct ib_device *device)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
if (class_device_register(&sdev->class_dev))
goto free_dev;
if (class_device_create_file(&sdev->class_dev,
&class_device_attr_login_info))
goto err_dev;
#else
if (device_register(&sdev->dev))
goto free_dev;
if (device_create_file(&sdev->dev, &dev_attr_login_info))
goto err_dev;
#endif
if (ib_query_device(device, &sdev->dev_attr))

View File

@@ -160,7 +160,10 @@ enum rdma_ch_state {
struct srpt_rdma_ch {
struct ib_cm_id *cm_id;
/* IB queue pair. */
struct ib_qp *qp;
/* Number of WR's in the QP 'qp' that are not in use. */
atomic_t qp_wr_avail;
struct ib_cq *cq;
struct srpt_port *sport;
/* 128-bit initiator port identifier copied from SRP_LOGIN_REQ. */