Files
scst/scripts/generate-kernel-with-srp-patches
Bart Van Assche beeef55b6f Use __packed instead of __attribute__((packed)).
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3500 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2011-06-01 10:40:07 +00:00

2439 lines
70 KiB
Bash
Executable File

#!/bin/bash
# Generates a 2.6.34.*, 2.6.35.* or 2.6.36* kernel tree with the SRP_CRED_REQ
# and several other patches applied to the ib_srp initiator.
# Adjust this variable such that it points to the directory with
# linux-x.y.z.tar.bz2 and patch-x.y.z.p.bz2 files on your system
TARBALLDIR=/home/bart/software/downloads
# Local functions
usage() {
echo "$0 <kernel-version>"
}
# Source: http://git.kernel.org/?p=linux/kernel/git/roland/infiniband.git;a=patch;h=$commit
get_2_6_36_patch() {
case "$1" in
7a7008110b94dfaa90db4b0cc5b0c3f964c80506)
cat <<EOF
index ed3f9eb..4675def 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -879,21 +879,10 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
opcode = *(u8 *) iu->buf;
if (0) {
- int i;
-
shost_printk(KERN_ERR, target->scsi_host,
PFX "recv completion, opcode 0x%02x\n", opcode);
-
- for (i = 0; i < wc->byte_len; ++i) {
- if (i % 8 == 0)
- printk(KERN_ERR " [%02x] ", i);
- printk(" %02x", ((u8 *) iu->buf)[i]);
- if ((i + 1) % 8 == 0)
- printk("\n");
- }
-
- if (wc->byte_len % 8)
- printk("\n");
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1,
+ iu->buf, wc->byte_len, true);
}
switch (opcode) {
--
1.7.3
EOF
;;
c996bb47bb419b7c2f75499e11750142775e5da9)
cat <<EOF
index 4675def..ffdd2d1 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -811,6 +811,38 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
return len;
}
+static int srp_post_recv(struct srp_target_port *target)
+{
+ unsigned long flags;
+ struct srp_iu *iu;
+ struct ib_sge list;
+ struct ib_recv_wr wr, *bad_wr;
+ unsigned int next;
+ int ret;
+
+ spin_lock_irqsave(target->scsi_host->host_lock, flags);
+
+ next = target->rx_head & (SRP_RQ_SIZE - 1);
+ wr.wr_id = next;
+ iu = target->rx_ring[next];
+
+ list.addr = iu->dma;
+ list.length = iu->size;
+ list.lkey = target->srp_host->srp_dev->mr->lkey;
+
+ wr.next = NULL;
+ wr.sg_list = &list;
+ wr.num_sge = 1;
+
+ ret = ib_post_recv(target->qp, &wr, &bad_wr);
+ if (!ret)
+ ++target->rx_head;
+
+ spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
+
+ return ret;
+}
+
static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
{
struct srp_request *req;
@@ -868,6 +900,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
{
struct ib_device *dev;
struct srp_iu *iu;
+ int res;
u8 opcode;
iu = target->rx_ring[wc->wr_id];
@@ -904,6 +937,11 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len,
DMA_FROM_DEVICE);
+
+ res = srp_post_recv(target);
+ if (res != 0)
+ shost_printk(KERN_ERR, target->scsi_host,
+ PFX "Recv failed with error code %d\n", res);
}
static void srp_recv_completion(struct ib_cq *cq, void *target_ptr)
@@ -943,45 +981,6 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
}
}
-static int __srp_post_recv(struct srp_target_port *target)
-{
- struct srp_iu *iu;
- struct ib_sge list;
- struct ib_recv_wr wr, *bad_wr;
- unsigned int next;
- int ret;
-
- next = target->rx_head & (SRP_RQ_SIZE - 1);
- wr.wr_id = next;
- iu = target->rx_ring[next];
-
- list.addr = iu->dma;
- list.length = iu->size;
- list.lkey = target->srp_host->srp_dev->mr->lkey;
-
- wr.next = NULL;
- wr.sg_list = &list;
- wr.num_sge = 1;
-
- ret = ib_post_recv(target->qp, &wr, &bad_wr);
- if (!ret)
- ++target->rx_head;
-
- return ret;
-}
-
-static int srp_post_recv(struct srp_target_port *target)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
- ret = __srp_post_recv(target);
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
-
- return ret;
-}
-
/*
* Must be called with target->scsi_host->host_lock held to protect
* req_lim and tx_head. Lock cannot be dropped between call here and
@@ -1091,11 +1090,6 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
goto err;
}
- if (__srp_post_recv(target)) {
- shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n");
- goto err_unmap;
- }
-
ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len,
DMA_TO_DEVICE);
@@ -1238,6 +1232,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
int attr_mask = 0;
int comp = 0;
int opcode = 0;
+ int i;
switch (event->event) {
case IB_CM_REQ_ERROR:
@@ -1287,7 +1282,11 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
if (target->status)
break;
- target->status = srp_post_recv(target);
+ for (i = 0; i < SRP_RQ_SIZE; i++) {
+ target->status = srp_post_recv(target);
+ if (target->status)
+ break;
+ }
if (target->status)
break;
--
1.7.3
EOF
;;
89de74866b846cc48780fda3de7fd223296aaca9)
cat <<EOF
index ffdd2d1..7f8f16b 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1552,6 +1552,18 @@ static ssize_t show_orig_dgid(struct device *dev,
return sprintf(buf, "%pI6\n", target->orig_dgid);
}
+static ssize_t show_req_lim(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(dev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "%d\n", target->req_lim);
+}
+
static ssize_t show_zero_req_lim(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1586,6 +1598,7 @@ static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL);
+static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL);
static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
@@ -1597,6 +1610,7 @@ static struct device_attribute *srp_host_attrs[] = {
&dev_attr_pkey,
&dev_attr_dgid,
&dev_attr_orig_dgid,
+ &dev_attr_req_lim,
&dev_attr_zero_req_lim,
&dev_attr_local_ib_port,
&dev_attr_local_ib_device,
--
1.7.3
EOF
;;
*)
echo ERROR
;;
esac
}
# Source: https://patchwork.kernel.org/patch/$p/raw/
get_2_6_37_patch() {
case "$1" in
143381)
cat <<EOF
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 7f8f16b..07e10fa 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -291,7 +291,7 @@ static void srp_free_target_ib(struct srp_target_port *target)
for (i = 0; i < SRP_RQ_SIZE; ++i)
srp_free_iu(target->srp_host, target->rx_ring[i]);
- for (i = 0; i < SRP_SQ_SIZE + 1; ++i)
+ for (i = 0; i < SRP_SQ_SIZE; ++i)
srp_free_iu(target->srp_host, target->tx_ring[i]);
}
@@ -822,7 +822,7 @@ static int srp_post_recv(struct srp_target_port *target)
spin_lock_irqsave(target->scsi_host->host_lock, flags);
- next = target->rx_head & (SRP_RQ_SIZE - 1);
+ next = target->rx_head & SRP_RQ_MASK;
wr.wr_id = next;
iu = target->rx_ring[next];
@@ -989,19 +989,19 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
enum srp_request_type req_type)
{
- s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
+ s32 rsv = (req_type == SRP_REQ_TASK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
srp_send_completion(target->send_cq, target);
if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
return NULL;
- if (target->req_lim < min) {
+ if (target->req_lim <= rsv) {
++target->zero_req_lim;
return NULL;
}
- return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
+ return target->tx_ring[target->tx_head & SRP_SQ_MASK];
}
/*
@@ -1020,7 +1020,7 @@ static int __srp_post_send(struct srp_target_port *target,
list.lkey = target->srp_host->srp_dev->mr->lkey;
wr.next = NULL;
- wr.wr_id = target->tx_head & SRP_SQ_SIZE;
+ wr.wr_id = target->tx_head & SRP_SQ_MASK;
wr.sg_list = &list;
wr.num_sge = 1;
wr.opcode = IB_WR_SEND;
@@ -1121,7 +1121,7 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target)
goto err;
}
- for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {
+ for (i = 0; i < SRP_SQ_SIZE; ++i) {
target->tx_ring[i] = srp_alloc_iu(target->srp_host,
srp_max_iu_len,
GFP_KERNEL, DMA_TO_DEVICE);
@@ -1137,7 +1137,7 @@ err:
target->rx_ring[i] = NULL;
}
- for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {
+ for (i = 0; i < SRP_SQ_SIZE; ++i) {
srp_free_iu(target->srp_host, target->tx_ring[i]);
target->tx_ring[i] = NULL;
}
@@ -1626,9 +1626,9 @@ static struct scsi_host_template srp_template = {
.eh_abort_handler = srp_abort,
.eh_device_reset_handler = srp_reset_device,
.eh_host_reset_handler = srp_reset_host,
- .can_queue = SRP_SQ_SIZE,
+ .can_queue = SRP_CMD_SQ_SIZE,
.this_id = -1,
- .cmd_per_lun = SRP_SQ_SIZE,
+ .cmd_per_lun = SRP_CMD_SQ_SIZE,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = srp_host_attrs
};
@@ -1813,7 +1813,8 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p);
goto out;
}
- target->scsi_host->cmd_per_lun = min(token, SRP_SQ_SIZE);
+ target->scsi_host->cmd_per_lun
+ = min(token, SRP_CMD_SQ_SIZE);
break;
case SRP_OPT_IO_CLASS:
@@ -1891,7 +1892,7 @@ static ssize_t srp_create_target(struct device *dev,
INIT_LIST_HEAD(&target->free_reqs);
INIT_LIST_HEAD(&target->req_queue);
- for (i = 0; i < SRP_SQ_SIZE; ++i) {
+ for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
target->req_ring[i].index = i;
list_add_tail(&target->req_ring[i].list, &target->free_reqs);
}
@@ -2159,6 +2160,9 @@ static int __init srp_init_module(void)
{
int ret;
+ BUILD_BUG_ON_NOT_POWER_OF_2(SRP_SQ_SIZE);
+ BUILD_BUG_ON_NOT_POWER_OF_2(SRP_RQ_SIZE);
+
if (srp_sg_tablesize > 255) {
printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n");
srp_sg_tablesize = 255;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 5a80eac..7a959d5 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -59,7 +59,14 @@ enum {
SRP_RQ_SHIFT = 6,
SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT,
- SRP_SQ_SIZE = SRP_RQ_SIZE - 1,
+ SRP_RQ_MASK = SRP_RQ_SIZE - 1,
+
+ SRP_SQ_SIZE = SRP_RQ_SIZE,
+ SRP_SQ_MASK = SRP_SQ_SIZE - 1,
+ SRP_RSP_SQ_SIZE = 1,
+ SRP_REQ_SQ_SIZE = SRP_SQ_SIZE - SRP_RSP_SQ_SIZE,
+ SRP_TSK_MGMT_SQ_SIZE = 1,
+ SRP_CMD_SQ_SIZE = SRP_REQ_SQ_SIZE - SRP_TSK_MGMT_SQ_SIZE,
SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1),
@@ -144,11 +151,11 @@ struct srp_target_port {
unsigned tx_head;
unsigned tx_tail;
- struct srp_iu *tx_ring[SRP_SQ_SIZE + 1];
+ struct srp_iu *tx_ring[SRP_SQ_SIZE];
struct list_head free_reqs;
struct list_head req_queue;
- struct srp_request req_ring[SRP_SQ_SIZE];
+ struct srp_request req_ring[SRP_CMD_SQ_SIZE];
struct work_struct work;
EOF
;;
143391)
cat <<EOF
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 07e10fa..e8be7b5 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -83,6 +83,11 @@ static void srp_remove_one(struct ib_device *device);
static void srp_recv_completion(struct ib_cq *cq, void *target_ptr);
static void srp_send_completion(struct ib_cq *cq, void *target_ptr);
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
+static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
+ enum srp_tx_iu_type iu_type);
+static int __srp_post_send(struct srp_target_port *target,
+ struct srp_iu *iu, int len,
+ enum srp_send_iu_type iu_type);
static struct scsi_transport_template *ib_srp_transport_template;
@@ -896,6 +901,80 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
}
+/*
+ * Must be called with target->scsi_host->host_lock locked to protect
+ * target->req_lim.
+ */
+static void __srp_handle_cred_req(struct srp_target_port *target,
+ void *req_ptr, void *rsp_ptr)
+{
+ struct srp_cred_req *req = req_ptr;
+ struct srp_cred_rsp *rsp = rsp_ptr;
+
+ target->req_lim += be32_to_cpu(req->req_lim_delta);
+
+ memset(rsp, 0, sizeof *rsp);
+ rsp->opcode = SRP_CRED_RSP;
+ rsp->tag = req->tag;
+}
+
+/*
+ * Must be called with target->scsi_host->host_lock locked to protect
+ * target->req_lim.
+ */
+static void __srp_handle_aer_req(struct srp_target_port *target,
+ void *req_ptr, void *rsp_ptr)
+{
+ struct srp_aer_req *req = req_ptr;
+ struct srp_aer_rsp *rsp = rsp_ptr;
+
+ target->req_lim += be32_to_cpu(req->req_lim_delta);
+
+ shost_printk(KERN_ERR, target->scsi_host,
+ PFX "ignoring AER for LUN %llu\n", be64_to_cpu(req->lun));
+
+ memset(rsp, 0, sizeof *rsp);
+ rsp->opcode = SRP_AER_RSP;
+ rsp->tag = req->tag;
+}
+
+static void srp_handle_req(struct srp_target_port *target,
+ struct srp_iu *req_iu,
+ void (*req_fn)(struct srp_target_port *,
+ void *, void *))
+{
+ struct ib_device *dev;
+ u8 *req_buf;
+ unsigned long flags;
+ struct srp_iu *rsp_iu;
+ u8 *rsp_buf;
+ int res;
+
+ dev = target->srp_host->srp_dev->dev;
+ req_buf = req_iu->buf;
+
+ spin_lock_irqsave(target->scsi_host->host_lock, flags);
+
+ rsp_iu = __srp_get_tx_iu(target, SRP_IU_RSP);
+ if (!rsp_iu)
+ goto out_unlock;
+
+ rsp_buf = rsp_iu->buf;
+
+ (*req_fn)(target, req_buf, rsp_buf);
+
+ ib_dma_sync_single_for_device(dev, rsp_iu->dma, srp_max_iu_len,
+ DMA_TO_DEVICE);
+
+ res = __srp_post_send(target, rsp_iu, sizeof *rsp_iu, SRP_SEND_RSP);
+ if (res)
+ shost_printk(KERN_ERR, target->scsi_host,
+ PFX "Sending response failed -- res = %d\n", res);
+
+out_unlock:
+ spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
+}
+
static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
{
struct ib_device *dev;
@@ -929,6 +1008,14 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
PFX "Got target logout request\n");
break;
+ case SRP_CRED_REQ:
+ srp_handle_req(target, iu, __srp_handle_cred_req);
+ break;
+
+ case SRP_AER_REQ:
+ srp_handle_req(target, iu, __srp_handle_aer_req);
+ break;
+
default:
shost_printk(KERN_WARNING, target->scsi_host,
PFX "Unhandled SRP opcode 0x%02x\n", opcode);
@@ -985,18 +1072,27 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
* Must be called with target->scsi_host->host_lock held to protect
* req_lim and tx_head. Lock cannot be dropped between call here and
* call to __srp_post_send().
+ *
+ * Note:
+ * An upper limit for the number of allocated information units for each
+ * request type is:
+ * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues
+ * more than Scsi_Host.can_queue requests.
+ * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE.
+ * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than
+ * one unanswered SRP request to an initiator.
*/
static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
- enum srp_request_type req_type)
+ enum srp_tx_iu_type iu_type)
{
- s32 rsv = (req_type == SRP_REQ_TASK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
+ s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
srp_send_completion(target->send_cq, target);
if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
return NULL;
- if (target->req_lim <= rsv) {
+ if (iu_type != SRP_IU_RSP && target->req_lim <= rsv) {
++target->zero_req_lim;
return NULL;
}
@@ -1009,7 +1105,8 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
* req_lim and tx_head.
*/
static int __srp_post_send(struct srp_target_port *target,
- struct srp_iu *iu, int len)
+ struct srp_iu *iu, int len,
+ enum srp_send_iu_type iu_type)
{
struct ib_sge list;
struct ib_send_wr wr, *bad_wr;
@@ -1030,7 +1127,8 @@ static int __srp_post_send(struct srp_target_port *target,
if (!ret) {
++target->tx_head;
- --target->req_lim;
+ if (iu_type == SRP_SEND_REQ)
+ --target->req_lim;
}
return ret;
@@ -1056,7 +1154,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
return 0;
}
- iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL);
+ iu = __srp_get_tx_iu(target, SRP_IU_CMD);
if (!iu)
goto err;
@@ -1093,7 +1191,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len,
DMA_TO_DEVICE);
- if (__srp_post_send(target, iu, len)) {
+ if (__srp_post_send(target, iu, len, SRP_SEND_REQ)) {
shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
goto err_unmap;
}
@@ -1363,7 +1461,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
init_completion(&req->done);
- iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT);
+ iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT);
if (!iu)
goto out;
@@ -1376,7 +1474,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
tsk_mgmt->tsk_mgmt_func = func;
tsk_mgmt->task_tag = req->index;
- if (__srp_post_send(target, iu, sizeof *tsk_mgmt))
+ if (__srp_post_send(target, iu, sizeof *tsk_mgmt, SRP_SEND_REQ))
goto out;
req->tsk_mgmt = iu;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 7a959d5..854ec81 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -82,9 +82,15 @@ enum srp_target_state {
SRP_TARGET_REMOVED
};
-enum srp_request_type {
- SRP_REQ_NORMAL,
- SRP_REQ_TASK_MGMT,
+enum srp_tx_iu_type {
+ SRP_IU_CMD,
+ SRP_IU_TSK_MGMT,
+ SRP_IU_RSP,
+};
+
+enum srp_send_iu_type {
+ SRP_SEND_REQ,
+ SRP_SEND_RSP,
};
struct srp_device {
diff --git a/include/scsi/srp.h b/include/scsi/srp.h
index ad178fa..1ae84db 100644
--- a/include/scsi/srp.h
+++ b/include/scsi/srp.h
@@ -239,4 +239,42 @@ struct srp_rsp {
u8 data[0];
} __packed;
+struct srp_cred_req {
+ u8 opcode;
+ u8 sol_not;
+ u8 reserved[2];
+ __be32 req_lim_delta;
+ u64 tag;
+};
+
+struct srp_cred_rsp {
+ u8 opcode;
+ u8 reserved[7];
+ u64 tag;
+};
+
+/*
+ * The SRP spec defines the fixed portion of the AER_REQ structure to be
+ * 36 bytes, so it needs to be packed to avoid having it padded to 40 bytes
+ * on 64-bit architectures.
+ */
+struct srp_aer_req {
+ u8 opcode;
+ u8 sol_not;
+ u8 reserved[2];
+ __be32 req_lim_delta;
+ u64 tag;
+ u32 reserved2;
+ __be64 lun;
+ __be32 sense_data_len;
+ u32 reserved3;
+ u8 sense_data[0];
+} __packed;
+
+struct srp_aer_rsp {
+ u8 opcode;
+ u8 reserved[7];
+ u64 tag;
+};
+
#endif /* SCSI_SRP_H */
EOF
;;
143401)
cat <<EOF
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index e8be7b5..17e948d 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -83,11 +83,6 @@ static void srp_remove_one(struct ib_device *device);
static void srp_recv_completion(struct ib_cq *cq, void *target_ptr);
static void srp_send_completion(struct ib_cq *cq, void *target_ptr);
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
- enum srp_tx_iu_type iu_type);
-static int __srp_post_send(struct srp_target_port *target,
- struct srp_iu *iu, int len,
- enum srp_send_iu_type iu_type);
static struct scsi_transport_template *ib_srp_transport_template;
@@ -902,6 +897,72 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
}
/*
+ * Must be called with target->scsi_host->host_lock held to protect
+ * req_lim and tx_head. Lock cannot be dropped between call here and
+ * call to __srp_post_send().
+ *
+ * Note:
+ * An upper limit for the number of allocated information units for each
+ * request type is:
+ * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues
+ * more than Scsi_Host.can_queue requests.
+ * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE.
+ * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than
+ * one unanswered SRP request to an initiator.
+ */
+static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
+ enum srp_tx_iu_type iu_type)
+{
+ s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
+
+ srp_send_completion(target->send_cq, target);
+
+ if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
+ return NULL;
+
+ if (iu_type != SRP_IU_RSP && target->req_lim <= rsv) {
+ ++target->zero_req_lim;
+ return NULL;
+ }
+
+ return target->tx_ring[target->tx_head & SRP_SQ_MASK];
+}
+
+/*
+ * Must be called with target->scsi_host->host_lock held to protect
+ * req_lim and tx_head.
+ */
+static int __srp_post_send(struct srp_target_port *target,
+ struct srp_iu *iu, int len,
+ enum srp_send_iu_type iu_type)
+{
+ struct ib_sge list;
+ struct ib_send_wr wr, *bad_wr;
+ int ret = 0;
+
+ list.addr = iu->dma;
+ list.length = len;
+ list.lkey = target->srp_host->srp_dev->mr->lkey;
+
+ wr.next = NULL;
+ wr.wr_id = target->tx_head & SRP_SQ_MASK;
+ wr.sg_list = &list;
+ wr.num_sge = 1;
+ wr.opcode = IB_WR_SEND;
+ wr.send_flags = IB_SEND_SIGNALED;
+
+ ret = ib_post_send(target->qp, &wr, &bad_wr);
+
+ if (!ret) {
+ ++target->tx_head;
+ if (iu_type == SRP_SEND_REQ)
+ --target->req_lim;
+ }
+
+ return ret;
+}
+
+/*
* Must be called with target->scsi_host->host_lock locked to protect
* target->req_lim.
*/
@@ -1068,72 +1129,6 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
}
}
-/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head. Lock cannot be dropped between call here and
- * call to __srp_post_send().
- *
- * Note:
- * An upper limit for the number of allocated information units for each
- * request type is:
- * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues
- * more than Scsi_Host.can_queue requests.
- * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE.
- * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than
- * one unanswered SRP request to an initiator.
- */
-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
- enum srp_tx_iu_type iu_type)
-{
- s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
-
- srp_send_completion(target->send_cq, target);
-
- if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
- return NULL;
-
- if (iu_type != SRP_IU_RSP && target->req_lim <= rsv) {
- ++target->zero_req_lim;
- return NULL;
- }
-
- return target->tx_ring[target->tx_head & SRP_SQ_MASK];
-}
-
-/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head.
- */
-static int __srp_post_send(struct srp_target_port *target,
- struct srp_iu *iu, int len,
- enum srp_send_iu_type iu_type)
-{
- struct ib_sge list;
- struct ib_send_wr wr, *bad_wr;
- int ret = 0;
-
- list.addr = iu->dma;
- list.length = len;
- list.lkey = target->srp_host->srp_dev->mr->lkey;
-
- wr.next = NULL;
- wr.wr_id = target->tx_head & SRP_SQ_MASK;
- wr.sg_list = &list;
- wr.num_sge = 1;
- wr.opcode = IB_WR_SEND;
- wr.send_flags = IB_SEND_SIGNALED;
-
- ret = ib_post_send(target->qp, &wr, &bad_wr);
-
- if (!ret) {
- ++target->tx_head;
- if (iu_type == SRP_SEND_REQ)
- --target->req_lim;
- }
-
- return ret;
-}
-
static int srp_queuecommand(struct scsi_cmnd *scmnd,
void (*done)(struct scsi_cmnd *))
{
EOF
;;
143411)
cat <<EOF
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 17e948d..2de894e 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1345,8 +1345,13 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len);
target->req_lim = be32_to_cpu(rsp->req_lim_delta);
- target->scsi_host->can_queue = min(target->req_lim,
- target->scsi_host->can_queue);
+ /*
+ * Set can_queue such that we don't needlessly
+ * bounce requests back to the SCSI mid-layer.
+ */
+ target->scsi_host->can_queue
+ = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE,
+ target->scsi_host->can_queue);
} else {
shost_printk(KERN_WARNING, target->scsi_host,
PFX "Unhandled RSP opcode %#x\n", opcode);
EOF
;;
143421)
cat <<EOF
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 2de894e..a2935e3 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1157,7 +1157,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
DMA_TO_DEVICE);
- req = list_entry(target->free_reqs.next, struct srp_request, list);
+ req = list_first_entry(&target->free_reqs, struct srp_request, list);
scmnd->scsi_done = done;
scmnd->result = 0;
EOF
;;
*)
echo ERROR
;;
esac
}
get_locking_per_lun_patch() {
cat <<EOF
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index a2935e3..f2cc342 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -81,6 +81,7 @@ MODULE_PARM_DESC(mellanox_workarounds,
static void srp_add_one(struct ib_device *device);
static void srp_remove_one(struct ib_device *device);
static void srp_recv_completion(struct ib_cq *cq, void *target_ptr);
+static void __srp_send_completion(struct ib_cq *cq, void *target_ptr);
static void srp_send_completion(struct ib_cq *cq, void *target_ptr);
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
@@ -441,18 +442,30 @@ static void srp_disconnect_target(struct srp_target_port *target)
wait_for_completion(&target->done);
}
+static bool srp_port_change_state(struct srp_target_port *target,
+ enum srp_target_state old,
+ enum srp_target_state new)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&target->lock, flags);
+ if (target->state == old) {
+ target->state = new;
+ ret = true;
+ } else
+ ret = false;
+ spin_unlock_irqrestore(&target->lock, flags);
+ return ret;
+}
+
static void srp_remove_work(struct work_struct *work)
{
struct srp_target_port *target =
container_of(work, struct srp_target_port, work);
- spin_lock_irq(target->scsi_host->host_lock);
- if (target->state != SRP_TARGET_DEAD) {
- spin_unlock_irq(target->scsi_host->host_lock);
+ if (!srp_port_change_state(target, SRP_TARGET_DEAD, SRP_TARGET_REMOVED))
return;
- }
- target->state = SRP_TARGET_REMOVED;
- spin_unlock_irq(target->scsi_host->host_lock);
spin_lock(&target->srp_host->target_lock);
list_del(&target->list);
@@ -541,8 +554,13 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
static void srp_remove_req(struct srp_target_port *target, struct srp_request *req)
{
+ unsigned long flags;
+
srp_unmap_data(req->scmnd, target, req);
- list_move_tail(&req->list, &target->free_reqs);
+ req->scmnd = NULL;
+ spin_lock_irqsave(&target->lock, flags);
+ list_add_tail(&req->list, &target->free_reqs);
+ spin_unlock_irqrestore(&target->lock, flags);
}
static void srp_reset_req(struct srp_target_port *target, struct srp_request *req)
@@ -555,17 +573,14 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re
static int srp_reconnect_target(struct srp_target_port *target)
{
struct ib_qp_attr qp_attr;
- struct srp_request *req, *tmp;
struct ib_wc wc;
int ret;
+ int i;
- spin_lock_irq(target->scsi_host->host_lock);
- if (target->state != SRP_TARGET_LIVE) {
- spin_unlock_irq(target->scsi_host->host_lock);
+ if (!srp_port_change_state(target, SRP_TARGET_LIVE,
+ SRP_TARGET_CONNECTING)) {
return -EAGAIN;
}
- target->state = SRP_TARGET_CONNECTING;
- spin_unlock_irq(target->scsi_host->host_lock);
srp_disconnect_target(target);
/*
@@ -590,27 +605,20 @@ static int srp_reconnect_target(struct srp_target_port *target)
while (ib_poll_cq(target->send_cq, 1, &wc) > 0)
; /* nothing */
- spin_lock_irq(target->scsi_host->host_lock);
- list_for_each_entry_safe(req, tmp, &target->req_queue, list)
- srp_reset_req(target, req);
- spin_unlock_irq(target->scsi_host->host_lock);
-
- target->rx_head = 0;
- target->tx_head = 0;
- target->tx_tail = 0;
+ for (i = 0; i < ARRAY_SIZE(target->req_ring); ++i)
+ if (target->req_ring[i].scmnd)
+ srp_reset_req(target, &target->req_ring[i]);
target->qp_in_error = 0;
ret = srp_connect_target(target);
if (ret)
goto err;
- spin_lock_irq(target->scsi_host->host_lock);
- if (target->state == SRP_TARGET_CONNECTING) {
+ if (srp_port_change_state(target, SRP_TARGET_CONNECTING,
+ SRP_TARGET_LIVE))
ret = 0;
- target->state = SRP_TARGET_LIVE;
- } else
+ else
ret = -EAGAIN;
- spin_unlock_irq(target->scsi_host->host_lock);
return ret;
@@ -624,13 +632,11 @@ err:
* be in the context of the SCSI error handler now, which
* would deadlock if we call scsi_remove_host().
*/
- spin_lock_irq(target->scsi_host->host_lock);
- if (target->state == SRP_TARGET_CONNECTING) {
- target->state = SRP_TARGET_DEAD;
+ if (srp_port_change_state(target, SRP_TARGET_CONNECTING,
+ SRP_TARGET_DEAD)) {
INIT_WORK(&target->work, srp_remove_work);
schedule_work(&target->work);
}
- spin_unlock_irq(target->scsi_host->host_lock);
return ret;
}
@@ -811,20 +817,12 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
return len;
}
-static int srp_post_recv(struct srp_target_port *target)
+static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu)
{
- unsigned long flags;
- struct srp_iu *iu;
struct ib_sge list;
struct ib_recv_wr wr, *bad_wr;
- unsigned int next;
- int ret;
-
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
- next = target->rx_head & SRP_RQ_MASK;
- wr.wr_id = next;
- iu = target->rx_ring[next];
+ wr.wr_id = iu->index;
list.addr = iu->dma;
list.length = iu->size;
@@ -834,13 +832,7 @@ static int srp_post_recv(struct srp_target_port *target)
wr.sg_list = &list;
wr.num_sge = 1;
- ret = ib_post_recv(target->qp, &wr, &bad_wr);
- if (!ret)
- ++target->rx_head;
-
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
-
- return ret;
+ return ib_post_recv(target->qp, &wr, &bad_wr);
}
static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
@@ -852,9 +844,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
delta = (s32) be32_to_cpu(rsp->req_lim_delta);
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
-
+ spin_lock_irqsave(&target->lock, flags);
target->req_lim += delta;
+ spin_unlock_irqrestore(&target->lock, flags);
req = &target->req_ring[rsp->tag & ~SRP_TAG_TSK_MGMT];
@@ -892,14 +884,12 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
} else
req->cmd_done = 1;
}
-
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
}
/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head. Lock cannot be dropped between call here and
- * call to __srp_post_send().
+ * It is the responsability of the caller to put back the returned information
+ * unit in the target->tx_free list and to increment target->req_lim if an
+ * error occurs before __srp_post_send() is called.
*
* Note:
* An upper limit for the number of allocated information units for each
@@ -914,24 +904,29 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
enum srp_tx_iu_type iu_type)
{
s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
+ struct srp_iu *res = NULL;
+ unsigned long flags;
- srp_send_completion(target->send_cq, target);
+ spin_lock_irqsave(&target->lock, flags);
- if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
- return NULL;
+ __srp_send_completion(target->send_cq, target);
+
+ if (list_empty(&target->tx_free))
+ goto out;
if (iu_type != SRP_IU_RSP && target->req_lim <= rsv) {
++target->zero_req_lim;
- return NULL;
+ goto out;
}
- return target->tx_ring[target->tx_head & SRP_SQ_MASK];
+ --target->req_lim;
+ res = list_first_entry(&target->tx_free, struct srp_iu, list);
+ list_del(&res->list);
+out:
+ spin_unlock_irqrestore(&target->lock, flags);
+ return res;
}
-/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head.
- */
static int __srp_post_send(struct srp_target_port *target,
struct srp_iu *iu, int len,
enum srp_send_iu_type iu_type)
@@ -945,7 +940,7 @@ static int __srp_post_send(struct srp_target_port *target,
list.lkey = target->srp_host->srp_dev->mr->lkey;
wr.next = NULL;
- wr.wr_id = target->tx_head & SRP_SQ_MASK;
+ wr.wr_id = iu->index;
wr.sg_list = &list;
wr.num_sge = 1;
wr.opcode = IB_WR_SEND;
@@ -953,43 +948,45 @@ static int __srp_post_send(struct srp_target_port *target,
ret = ib_post_send(target->qp, &wr, &bad_wr);
- if (!ret) {
- ++target->tx_head;
+ if (ret) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&target->lock, flags);
if (iu_type == SRP_SEND_REQ)
- --target->req_lim;
+ target->req_lim++;
+ list_add(&iu->list, &target->tx_free);
+ spin_unlock_irqrestore(&target->lock, flags);
}
return ret;
}
-/*
- * Must be called with target->scsi_host->host_lock locked to protect
- * target->req_lim.
- */
-static void __srp_handle_cred_req(struct srp_target_port *target,
- void *req_ptr, void *rsp_ptr)
+static void srp_handle_cred_req(struct srp_target_port *target,
+ void *req_ptr, void *rsp_ptr)
{
+ unsigned long flags;
struct srp_cred_req *req = req_ptr;
struct srp_cred_rsp *rsp = rsp_ptr;
+ spin_lock_irqsave(&target->lock, flags);
target->req_lim += be32_to_cpu(req->req_lim_delta);
+ spin_unlock_irqrestore(&target->lock, flags);
memset(rsp, 0, sizeof *rsp);
rsp->opcode = SRP_CRED_RSP;
rsp->tag = req->tag;
}
-/*
- * Must be called with target->scsi_host->host_lock locked to protect
- * target->req_lim.
- */
-static void __srp_handle_aer_req(struct srp_target_port *target,
- void *req_ptr, void *rsp_ptr)
+static void srp_handle_aer_req(struct srp_target_port *target,
+ void *req_ptr, void *rsp_ptr)
{
+ unsigned long flags;
struct srp_aer_req *req = req_ptr;
struct srp_aer_rsp *rsp = rsp_ptr;
+ spin_lock_irqsave(&target->lock, flags);
target->req_lim += be32_to_cpu(req->req_lim_delta);
+ spin_unlock_irqrestore(&target->lock, flags);
shost_printk(KERN_ERR, target->scsi_host,
PFX "ignoring AER for LUN %llu\n", be64_to_cpu(req->lun));
@@ -1006,7 +1003,6 @@ static void srp_handle_req(struct srp_target_port *target,
{
struct ib_device *dev;
u8 *req_buf;
- unsigned long flags;
struct srp_iu *rsp_iu;
u8 *rsp_buf;
int res;
@@ -1014,11 +1010,9 @@ static void srp_handle_req(struct srp_target_port *target,
dev = target->srp_host->srp_dev->dev;
req_buf = req_iu->buf;
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
-
rsp_iu = __srp_get_tx_iu(target, SRP_IU_RSP);
if (!rsp_iu)
- goto out_unlock;
+ return;
rsp_buf = rsp_iu->buf;
@@ -1031,9 +1025,6 @@ static void srp_handle_req(struct srp_target_port *target,
if (res)
shost_printk(KERN_ERR, target->scsi_host,
PFX "Sending response failed -- res = %d\n", res);
-
-out_unlock:
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
}
static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
@@ -1070,11 +1061,11 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
break;
case SRP_CRED_REQ:
- srp_handle_req(target, iu, __srp_handle_cred_req);
+ srp_handle_req(target, iu, srp_handle_cred_req);
break;
case SRP_AER_REQ:
- srp_handle_req(target, iu, __srp_handle_aer_req);
+ srp_handle_req(target, iu, srp_handle_aer_req);
break;
default:
@@ -1086,7 +1077,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len,
DMA_FROM_DEVICE);
- res = srp_post_recv(target);
+ res = srp_post_recv(target, iu);
if (res != 0)
shost_printk(KERN_ERR, target->scsi_host,
PFX "Recv failed with error code %d\n", res);
@@ -1095,38 +1086,59 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
static void srp_recv_completion(struct ib_cq *cq, void *target_ptr)
{
struct srp_target_port *target = target_ptr;
- struct ib_wc wc;
+ struct ib_wc *const wc = target->recv_wc;
+ int i, n;
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
- while (ib_poll_cq(cq, 1, &wc) > 0) {
- if (wc.status) {
- shost_printk(KERN_ERR, target->scsi_host,
- PFX "failed receive status %d\n",
- wc.status);
- target->qp_in_error = 1;
- break;
- }
+ while ((n = ib_poll_cq(cq, ARRAY_SIZE(target->recv_wc), wc)) > 0) {
+ for (i = 0; i < n; ++i) {
+ if (wc[i].status) {
+ shost_printk(KERN_ERR, target->scsi_host,
+ PFX "failed receive status %d\n",
+ wc[i].status);
+ target->qp_in_error = 1;
+ goto out;
+ }
- srp_handle_recv(target, &wc);
+ srp_handle_recv(target, &wc[i]);
+ }
}
+out:
+ return;
}
-static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
+static void __srp_send_completion(struct ib_cq *cq, void *target_ptr)
{
struct srp_target_port *target = target_ptr;
- struct ib_wc wc;
+ struct ib_wc *const wc = target->send_wc;
+ int i, n;
+
+ while ((n = ib_poll_cq(cq, ARRAY_SIZE(target->send_wc), wc)) > 0) {
+ for (i = 0; i < n; ++i) {
+ if (wc[i].status) {
+ shost_printk(KERN_ERR, target->scsi_host,
+ PFX "failed send status %d\n",
+ wc[i].status);
+ target->qp_in_error = 1;
+ goto out;
+ }
- while (ib_poll_cq(cq, 1, &wc) > 0) {
- if (wc.status) {
- shost_printk(KERN_ERR, target->scsi_host,
- PFX "failed send status %d\n",
- wc.status);
- target->qp_in_error = 1;
- break;
+ list_add_tail(&target->tx_ring[wc[i].wr_id]->list,
+ &target->tx_free);
}
-
- ++target->tx_tail;
}
+out:
+ return;
+}
+
+static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
+{
+ struct srp_target_port *target = target_ptr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&target->lock, flags);
+ __srp_send_completion(cq, target_ptr);
+ spin_unlock_irqrestore(&target->lock, flags);
}
static int srp_queuecommand(struct scsi_cmnd *scmnd,
@@ -1138,6 +1150,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
struct srp_cmd *cmd;
struct ib_device *dev;
int len;
+ unsigned long flags;
if (target->state == SRP_TARGET_CONNECTING)
goto err;
@@ -1157,7 +1170,10 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
DMA_TO_DEVICE);
+ spin_lock_irqsave(&target->lock, flags);
req = list_first_entry(&target->free_reqs, struct srp_request, list);
+ list_del(&req->list);
+ spin_unlock_irqrestore(&target->lock, flags);
scmnd->scsi_done = done;
scmnd->result = 0;
@@ -1180,7 +1196,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
if (len < 0) {
shost_printk(KERN_ERR, target->scsi_host,
PFX "Failed to map data\n");
- goto err;
+ goto err_putback;
}
ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len,
@@ -1188,16 +1204,22 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
if (__srp_post_send(target, iu, len, SRP_SEND_REQ)) {
shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
+ spin_lock_irqsave(&target->lock, flags);
+ list_del(&req->list);
+ spin_unlock_irqrestore(&target->lock, flags);
goto err_unmap;
}
- list_move_tail(&req->list, &target->req_queue);
-
return 0;
err_unmap:
srp_unmap_data(scmnd, target, req);
+err_putback:
+ spin_lock_irqsave(&target->lock, flags);
+ list_add(&req->list, &target->free_reqs);
+ spin_unlock_irqrestore(&target->lock, flags);
+
err:
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1212,14 +1234,19 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target)
GFP_KERNEL, DMA_FROM_DEVICE);
if (!target->rx_ring[i])
goto err;
+ target->rx_ring[i]->index = i;
}
+ INIT_LIST_HEAD(&target->tx_free);
+
for (i = 0; i < SRP_SQ_SIZE; ++i) {
target->tx_ring[i] = srp_alloc_iu(target->srp_host,
srp_max_iu_len,
GFP_KERNEL, DMA_TO_DEVICE);
if (!target->tx_ring[i])
goto err;
+ target->tx_ring[i]->index = i;
+ list_add_tail(&target->tx_ring[i]->list, &target->tx_free);
}
return 0;
@@ -1381,7 +1408,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
break;
for (i = 0; i < SRP_RQ_SIZE; i++) {
- target->status = srp_post_recv(target);
+ target->status = srp_post_recv(target,
+ target->rx_ring[i]);
if (target->status)
break;
}
@@ -1451,8 +1479,6 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
struct srp_iu *iu;
struct srp_tsk_mgmt *tsk_mgmt;
- spin_lock_irq(target->scsi_host->host_lock);
-
if (target->state == SRP_TARGET_DEAD ||
target->state == SRP_TARGET_REMOVED) {
req->scmnd->result = DID_BAD_TARGET << 16;
@@ -1479,8 +1505,6 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
req->tsk_mgmt = iu;
- spin_unlock_irq(target->scsi_host->host_lock);
-
if (!wait_for_completion_timeout(&req->done,
msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)))
return -1;
@@ -1488,7 +1512,6 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
return 0;
out:
- spin_unlock_irq(target->scsi_host->host_lock);
return -1;
}
@@ -1519,8 +1542,6 @@ static int srp_abort(struct scsi_cmnd *scmnd)
if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
return FAILED;
- spin_lock_irq(target->scsi_host->host_lock);
-
if (req->cmd_done) {
srp_remove_req(target, req);
scmnd->scsi_done(scmnd);
@@ -1530,15 +1551,14 @@ static int srp_abort(struct scsi_cmnd *scmnd)
} else
ret = FAILED;
- spin_unlock_irq(target->scsi_host->host_lock);
-
return ret;
}
static int srp_reset_device(struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(scmnd->device->host);
- struct srp_request *req, *tmp;
+ struct srp_request *req;
+ int i;
shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
@@ -1551,14 +1571,10 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
if (req->tsk_status)
return FAILED;
- spin_lock_irq(target->scsi_host->host_lock);
-
- list_for_each_entry_safe(req, tmp, &target->req_queue, list)
- if (req->scmnd->device == scmnd->device)
+ for (i = 0; i < ARRAY_SIZE(target->req_ring); ++i)
+ if (req->scmnd && req->scmnd->device == scmnd->device)
srp_reset_req(target, req);
- spin_unlock_irq(target->scsi_host->host_lock);
-
return SUCCESS;
}
@@ -1575,6 +1591,26 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
return ret;
}
+static ssize_t show_max_host_blocked(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(dev);
+
+ return sprintf(buf, "%d\n", max(1U, host->max_host_blocked));
+}
+
+
+static ssize_t set_max_host_blocked(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *host = class_to_shost(dev);
+
+ host->max_host_blocked = max(1UL, simple_strtoul(buf, NULL, 0));
+ return count;
+}
+
static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1690,6 +1726,8 @@ static ssize_t show_local_ib_device(struct device *dev,
return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name);
}
+static DEVICE_ATTR(max_host_blocked, S_IWUSR | S_IRUGO,
+ show_max_host_blocked, set_max_host_blocked);
static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
@@ -1702,6 +1740,7 @@ static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
static struct device_attribute *srp_host_attrs[] = {
+ &dev_attr_max_host_blocked,
&dev_attr_id_ext,
&dev_attr_ioc_guid,
&dev_attr_service_id,
@@ -1981,6 +2020,7 @@ static ssize_t srp_create_target(struct device *dev,
target_host->transportt = ib_srp_transport_template;
target_host->max_lun = SRP_MAX_LUN;
target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
+ target_host->unlocked_qcmds = true;
target = host_to_target(target_host);
@@ -1988,8 +2028,9 @@ static ssize_t srp_create_target(struct device *dev,
target->scsi_host = target_host;
target->srp_host = host;
+ spin_lock_init(&target->lock);
+
INIT_LIST_HEAD(&target->free_reqs);
- INIT_LIST_HEAD(&target->req_queue);
for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
target->req_ring[i].index = i;
list_add_tail(&target->req_ring[i].list, &target->free_reqs);
@@ -2200,6 +2241,7 @@ static void srp_remove_one(struct ib_device *device)
struct srp_host *host, *tmp_host;
LIST_HEAD(target_list);
struct srp_target_port *target, *tmp_target;
+ unsigned long flags;
srp_dev = ib_get_client_data(device, &srp_client);
@@ -2217,9 +2259,9 @@ static void srp_remove_one(struct ib_device *device)
*/
spin_lock(&host->target_lock);
list_for_each_entry(target, &host->target_list, list) {
- spin_lock_irq(target->scsi_host->host_lock);
+ spin_lock_irqsave(&target->lock, flags);
target->state = SRP_TARGET_REMOVED;
- spin_unlock_irq(target->scsi_host->host_lock);
+ spin_unlock_irqrestore(&target->lock, flags);
}
spin_unlock(&host->target_lock);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 854ec81..1d5ab5d 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -146,21 +146,23 @@ struct srp_target_port {
struct ib_cq *recv_cq;
struct ib_cq *send_cq;
struct ib_qp *qp;
+ struct ib_wc send_wc[16];
+ struct ib_wc recv_wc[16];
int max_ti_iu_len;
+
+ spinlock_t lock;
+
s32 req_lim;
int zero_req_lim;
- unsigned rx_head;
struct srp_iu *rx_ring[SRP_RQ_SIZE];
- unsigned tx_head;
- unsigned tx_tail;
+ struct list_head tx_free;
struct srp_iu *tx_ring[SRP_SQ_SIZE];
struct list_head free_reqs;
- struct list_head req_queue;
struct srp_request req_ring[SRP_CMD_SQ_SIZE];
struct work_struct work;
@@ -173,9 +175,11 @@ struct srp_target_port {
};
struct srp_iu {
+ struct list_head list;
u64 dma;
void *buf;
size_t size;
+ short index;
enum dma_data_direction direction;
};
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index ad0ed21..2f9110c 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -737,23 +737,31 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
goto out;
}
- spin_lock_irqsave(host->host_lock, flags);
- /*
- * AK: unlikely race here: for some reason the timer could
- * expire before the serial number is set up below.
- *
- * TODO: kill serial or move to blk layer
- */
- scsi_cmd_get_serial(host, cmd);
+ if (!host->unlocked_qcmds) {
+ spin_lock_irqsave(host->host_lock, flags);
+ /*
+ * AK: unlikely race here: for some reason the timer could
+ * expire before the serial number is set up below.
+ *
+ * TODO: kill serial or move to blk layer
+ */
+ scsi_cmd_get_serial(host, cmd);
+ } else
+ cmd->serial_number = 1;
if (unlikely(host->shost_state == SHOST_DEL)) {
+ if (host->unlocked_qcmds)
+ spin_lock_irqsave(host->host_lock, flags);
cmd->result = (DID_NO_CONNECT << 16);
scsi_done(cmd);
+ spin_unlock_irqrestore(host->host_lock, flags);
} else {
trace_scsi_dispatch_cmd_start(cmd);
rtn = host->hostt->queuecommand(cmd, scsi_done);
+ if (!host->unlocked_qcmds)
+ spin_unlock_irqrestore(host->host_lock, flags);
}
- spin_unlock_irqrestore(host->host_lock, flags);
+
if (rtn) {
trace_scsi_dispatch_cmd_error(cmd, rtn);
if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index b7bdecb..1814c51 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -636,6 +636,9 @@ struct Scsi_Host {
/* Asynchronous scan in progress */
unsigned async_scan:1;
+ /* call queuecommand without Scsi_Host lock held */
+ unsigned unlocked_qcmds:1;
+
/*
* Optional work queue to be utilized by the transport
*/
EOF
}
# Source: http://git.kernel.dk/?p=linux-2.6-block.git;a=patch;h=$commit
get_block_layer_patch() {
case "$1" in
5a00f237eb167a5e98d5f3bb56e11e4da406a5bc)
cat <<EOF
index 32a1c12..1a9403e 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -672,40 +672,6 @@ blk_alloc_request(struct request_queue *q, int flags, int priv, gfp_t gfp_mask)
return rq;
}
-/*
- * ioc_batching returns true if the ioc is a valid batching request and
- * should be given priority access to a request.
- */
-static inline int ioc_batching(struct request_queue *q, struct io_context *ioc)
-{
- if (!ioc)
- return 0;
-
- /*
- * Make sure the process is able to allocate at least 1 request
- * even if the batch times out, otherwise we could theoretically
- * lose wakeups.
- */
- return ioc->nr_batch_requests == q->nr_batching ||
- (ioc->nr_batch_requests > 0
- && time_before(jiffies, ioc->last_waited + BLK_BATCH_TIME));
-}
-
-/*
- * ioc_set_batching sets ioc to be a new "batcher" if it is not one. This
- * will cause the process to be a "batcher" on all queues in the system. This
- * is the behaviour we want though - once it gets a wakeup it should be given
- * a nice run.
- */
-static void ioc_set_batching(struct request_queue *q, struct io_context *ioc)
-{
- if (!ioc || ioc_batching(q, ioc))
- return;
-
- ioc->nr_batch_requests = q->nr_batching;
- ioc->last_waited = jiffies;
-}
-
static void __freed_request(struct request_queue *q, int sync)
{
struct request_list *rl = &q->rq;
@@ -749,7 +715,6 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
{
struct request *rq = NULL;
struct request_list *rl = &q->rq;
- struct io_context *ioc = NULL;
const bool is_sync = rw_is_sync(rw_flags) != 0;
int may_queue, priv;
@@ -757,41 +722,6 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
if (may_queue == ELV_MQUEUE_NO)
goto rq_starved;
- if (rl->count[is_sync]+1 >= queue_congestion_on_threshold(q)) {
- if (rl->count[is_sync]+1 >= q->nr_requests) {
- ioc = current_io_context(GFP_ATOMIC, q->node);
- /*
- * The queue will fill after this allocation, so set
- * it as full, and mark this process as "batching".
- * This process will be allowed to complete a batch of
- * requests, others will be blocked.
- */
- if (!blk_queue_full(q, is_sync)) {
- ioc_set_batching(q, ioc);
- blk_set_queue_full(q, is_sync);
- } else {
- if (may_queue != ELV_MQUEUE_MUST
- && !ioc_batching(q, ioc)) {
- /*
- * The queue is full and the allocating
- * process is not a "batcher", and not
- * exempted by the IO scheduler
- */
- goto out;
- }
- }
- }
- blk_set_queue_congested(q, is_sync);
- }
-
- /*
- * Only allow batching queuers to allocate up to 50% over the defined
- * limit of requests, otherwise we could have thousands of requests
- * allocated with any setting of ->nr_requests
- */
- if (rl->count[is_sync] >= (3 * q->nr_requests / 2))
- goto out;
-
rl->count[is_sync]++;
rl->starved[is_sync] = 0;
@@ -829,15 +759,6 @@ rq_starved:
goto out;
}
- /*
- * ioc may be NULL here, and ioc_batching will be false. That's
- * OK, if the queue is under the request limit then requests need
- * not count toward the nr_batch_requests limit. There will always
- * be some limit enforced by BLK_BATCH_TIME.
- */
- if (ioc_batching(q, ioc))
- ioc->nr_batch_requests--;
-
trace_block_getrq(q, bio, rw_flags & 1);
out:
return rq;
@@ -858,7 +779,6 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags,
rq = get_request(q, rw_flags, bio, GFP_NOIO);
while (!rq) {
DEFINE_WAIT(wait);
- struct io_context *ioc;
struct request_list *rl = &q->rq;
prepare_to_wait_exclusive(&rl->wait[is_sync], &wait,
@@ -870,15 +790,6 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags,
spin_unlock_irq(q->queue_lock);
io_schedule();
- /*
- * After sleeping, we become a "batching" process and
- * will be able to allocate at least one request, and
- * up to a big batch of them for a small period time.
- * See ioc_batching, ioc_set_batching
- */
- ioc = current_io_context(GFP_NOIO, q->node);
- ioc_set_batching(q, ioc);
-
spin_lock_irq(q->queue_lock);
finish_wait(&rl->wait[is_sync], &wait);
diff --git a/block/blk-ioc.c b/block/blk-ioc.c
index d22c4c5..49beb97 100644
--- a/block/blk-ioc.c
+++ b/block/blk-ioc.c
@@ -92,8 +92,6 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
spin_lock_init(&ret->lock);
ret->ioprio_changed = 0;
ret->ioprio = 0;
- ret->last_waited = 0; /* doesn't matter... */
- ret->nr_batch_requests = 0; /* because this is 0 */
INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
INIT_HLIST_HEAD(&ret->cic_list);
ret->ioc_data = NULL;
diff --git a/block/blk-settings.c b/block/blk-settings.c
index a234f4b..4ce5d80 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -161,7 +161,6 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
q->make_request_fn = mfn;
blk_queue_dma_alignment(q, 511);
blk_queue_congestion_threshold(q);
- q->nr_batching = BLK_BATCH_REQ;
q->unplug_thresh = 4; /* hmm */
q->unplug_delay = msecs_to_jiffies(3); /* 3 milliseconds */
diff --git a/block/blk.h b/block/blk.h
index d6b911a..709e351 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -1,12 +1,6 @@
#ifndef BLK_INTERNAL_H
#define BLK_INTERNAL_H
-/* Amount of time in which a process may batch requests */
-#define BLK_BATCH_TIME (HZ/50UL)
-
-/* Number of requests a "batching" process may submit */
-#define BLK_BATCH_REQ 32
-
extern struct kmem_cache *blk_requestq_cachep;
extern struct kobj_type blk_queue_ktype;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index dd318ff..2ad9087 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -164,7 +164,6 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
unsigned long num_sync_run;
unsigned long batch_run = 0;
unsigned long limit;
- unsigned long last_waited = 0;
int force_reg = 0;
bdi = blk_get_backing_dev_info(device->bdev);
@@ -279,39 +278,6 @@ loop_lock:
*/
if (pending && bdi_write_congested(bdi) && batch_run > 8 &&
fs_info->fs_devices->open_devices > 1) {
- struct io_context *ioc;
-
- ioc = current->io_context;
-
- /*
- * the main goal here is that we don't want to
- * block if we're going to be able to submit
- * more requests without blocking.
- *
- * This code does two great things, it pokes into
- * the elevator code from a filesystem _and_
- * it makes assumptions about how batching works.
- */
- if (ioc && ioc->nr_batch_requests > 0 &&
- time_before(jiffies, ioc->last_waited + HZ/50UL) &&
- (last_waited == 0 ||
- ioc->last_waited == last_waited)) {
- /*
- * we want to go through our batch of
- * requests and stop. So, we copy out
- * the ioc->last_waited time and test
- * against it before looping
- */
- last_waited = ioc->last_waited;
- if (need_resched()) {
- if (num_sync_run) {
- blk_run_backing_dev(bdi, NULL);
- num_sync_run = 0;
- }
- cond_resched();
- }
- continue;
- }
spin_lock(&device->io_lock);
requeue_list(pending_bios, pending, tail);
device->running_pending = 1;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 2c54906..2fc7917 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -326,7 +326,6 @@ struct request_queue
unsigned long nr_requests; /* Max # of requests */
unsigned int nr_congestion_on;
unsigned int nr_congestion_off;
- unsigned int nr_batching;
void *dma_drain_buffer;
unsigned int dma_drain_size;
diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h
index 64d5291..e8c9165 100644
--- a/include/linux/iocontext.h
+++ b/include/linux/iocontext.h
@@ -45,12 +45,6 @@ struct io_context {
unsigned short cgroup_changed;
#endif
- /*
- * For request batching
- */
- int nr_batch_requests; /* Number of requests left in the batch */
- unsigned long last_waited; /* Time last woken after wait for request */
-
struct radix_tree_root radix_root;
struct hlist_head cic_list;
void *ioc_data;
--
1.7.1.426.gb436
EOF
;;
76241c12f6a730241b9fa6a795dff55f826ce391)
cat <<EOF
index 1a9403e..a520cea 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -467,7 +467,7 @@ static int blk_init_free_list(struct request_queue *q)
{
struct request_list *rl = &q->rq;
- if (unlikely(rl->rq_pool))
+ if (unlikely(rl->rq_pool[0]))
return 0;
rl->count[BLK_RW_SYNC] = rl->count[BLK_RW_ASYNC] = 0;
@@ -476,11 +476,17 @@ static int blk_init_free_list(struct request_queue *q)
init_waitqueue_head(&rl->wait[BLK_RW_SYNC]);
init_waitqueue_head(&rl->wait[BLK_RW_ASYNC]);
- rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
+ rl->rq_pool[0] = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
mempool_free_slab, request_cachep, q->node);
+ if (!rl->rq_pool[0])
+ return -ENOMEM;
- if (!rl->rq_pool)
+ rl->rq_pool[1] = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
+ mempool_free_slab, request_cachep, q->node);
+ if (!rl->rq_pool[1]) {
+ mempool_destroy(rl->rq_pool[0]);
return -ENOMEM;
+ }
return 0;
}
@@ -644,16 +650,21 @@ int blk_get_queue(struct request_queue *q)
static inline void blk_free_request(struct request_queue *q, struct request *rq)
{
+ const bool is_sync = rq_is_sync(rq) != 0;
+
if (rq->cmd_flags & REQ_ELVPRIV)
elv_put_request(q, rq);
- mempool_free(rq, q->rq.rq_pool);
+
+ mempool_free(rq, q->rq.rq_pool[is_sync]);
}
static struct request *
blk_alloc_request(struct request_queue *q, int flags, int priv, gfp_t gfp_mask)
{
- struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
+ const bool is_sync = rw_is_sync(flags) != 0;
+ struct request *rq;
+ rq = mempool_alloc(q->rq.rq_pool[is_sync], gfp_mask);
if (!rq)
return NULL;
@@ -663,7 +674,7 @@ blk_alloc_request(struct request_queue *q, int flags, int priv, gfp_t gfp_mask)
if (priv) {
if (unlikely(elv_set_request(q, rq, gfp_mask))) {
- mempool_free(rq, q->rq.rq_pool);
+ mempool_free(rq, q->rq.rq_pool[is_sync]);
return NULL;
}
rq->cmd_flags |= REQ_ELVPRIV;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 0749b89..ee44ce5 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -460,8 +460,10 @@ static void blk_release_queue(struct kobject *kobj)
blk_sync_queue(q);
- if (rl->rq_pool)
- mempool_destroy(rl->rq_pool);
+ if (rl->rq_pool[0])
+ mempool_destroy(rl->rq_pool[0]);
+ if (rl->rq_pool[1])
+ mempool_destroy(rl->rq_pool[1]);
if (q->queue_tags)
__blk_queue_free_tags(q);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 2fc7917..858235d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -45,7 +45,7 @@ struct request_list {
int count[2];
int starved[2];
int elvpriv;
- mempool_t *rq_pool;
+ mempool_t *rq_pool[2];
wait_queue_head_t wait[2];
};
--
1.7.1.426.gb436
EOF
;;
35f2046ac858ca165a8aba477c9236e53a8dbffa)
cat <<EOF
index a520cea..91bc13d 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -471,7 +471,6 @@ static int blk_init_free_list(struct request_queue *q)
return 0;
rl->count[BLK_RW_SYNC] = rl->count[BLK_RW_ASYNC] = 0;
- rl->starved[BLK_RW_SYNC] = rl->starved[BLK_RW_ASYNC] = 0;
rl->elvpriv = 0;
init_waitqueue_head(&rl->wait[BLK_RW_SYNC]);
init_waitqueue_head(&rl->wait[BLK_RW_ASYNC]);
@@ -711,9 +710,6 @@ static void freed_request(struct request_queue *q, int sync, int priv)
rl->elvpriv--;
__freed_request(q, sync);
-
- if (unlikely(rl->starved[sync ^ 1]))
- __freed_request(q, sync ^ 1);
}
/*
@@ -731,10 +727,9 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
may_queue = elv_may_queue(q, rw_flags);
if (may_queue == ELV_MQUEUE_NO)
- goto rq_starved;
+ goto out;
rl->count[is_sync]++;
- rl->starved[is_sync] = 0;
priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
if (priv)
@@ -755,18 +750,6 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
*/
spin_lock_irq(q->queue_lock);
freed_request(q, is_sync, priv);
-
- /*
- * in the very unlikely event that allocation failed and no
- * requests for this direction was pending, mark us starved
- * so that freeing of a request in the other direction will
- * notice us. another possible fix would be to split the
- * rq mempool into READ and WRITE
- */
-rq_starved:
- if (unlikely(rl->count[is_sync] == 0))
- rl->starved[is_sync] = 1;
-
goto out;
}
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 858235d..089b8a2 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -39,11 +39,10 @@ typedef void (rq_end_io_fn)(struct request *, int);
struct request_list {
/*
- * count[], starved[], and wait[] are indexed by
+ * count[], and wait[] are indexed by
* BLK_RW_SYNC/BLK_RW_ASYNC
*/
int count[2];
- int starved[2];
int elvpriv;
mempool_t *rq_pool[2];
wait_queue_head_t wait[2];
--
1.7.1.426.gb436
EOF
;;
38bb177765247024dad4b70a2abe0044d0574998)
cat <<EOF
index 91bc13d..aa94ba3 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -714,8 +714,6 @@ static void freed_request(struct request_queue *q, int sync, int priv)
/*
* Get a free request, queue_lock must be held.
- * Returns NULL on failure, with queue_lock held.
- * Returns !NULL on success, with queue_lock *not held*.
*/
static struct request *get_request(struct request_queue *q, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -723,6 +721,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
struct request *rq = NULL;
struct request_list *rl = &q->rq;
const bool is_sync = rw_is_sync(rw_flags) != 0;
+ const bool drop_lock = (gfp_mask & __GFP_WAIT) != 0;
int may_queue, priv;
may_queue = elv_may_queue(q, rw_flags);
@@ -737,7 +736,9 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
if (blk_queue_io_stat(q))
rw_flags |= REQ_IO_STAT;
- spin_unlock_irq(q->queue_lock);
+
+ if (drop_lock)
+ spin_unlock_irq(q->queue_lock);
rq = blk_alloc_request(q, rw_flags, priv, gfp_mask);
if (unlikely(!rq)) {
@@ -748,12 +749,17 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
* Allocating task should really be put onto the front of the
* wait queue, but this is pretty rare.
*/
- spin_lock_irq(q->queue_lock);
+ if (drop_lock)
+ spin_lock_irq(q->queue_lock);
+
freed_request(q, is_sync, priv);
goto out;
}
trace_block_getrq(q, bio, rw_flags & 1);
+
+ if (drop_lock)
+ spin_lock_irq(q->queue_lock);
out:
return rq;
}
@@ -762,7 +768,7 @@ out:
* No available requests for this queue, unplug the device and wait for some
* requests to become available.
*
- * Called with q->queue_lock held, and returns with it unlocked.
+ * Called with q->queue_lock held.
*/
static struct request *get_request_wait(struct request_queue *q, int rw_flags,
struct bio *bio)
@@ -770,7 +776,7 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags,
const bool is_sync = rw_is_sync(rw_flags) != 0;
struct request *rq;
- rq = get_request(q, rw_flags, bio, GFP_NOIO);
+ rq = get_request(q, rw_flags, bio, GFP_ATOMIC);
while (!rq) {
DEFINE_WAIT(wait);
struct request_list *rl = &q->rq;
@@ -800,15 +806,13 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
BUG_ON(rw != READ && rw != WRITE);
spin_lock_irq(q->queue_lock);
- if (gfp_mask & __GFP_WAIT) {
+
+ if (gfp_mask & __GFP_WAIT)
rq = get_request_wait(q, rw, NULL);
- } else {
+ else
rq = get_request(q, rw, NULL, gfp_mask);
- if (!rq)
- spin_unlock_irq(q->queue_lock);
- }
- /* q->queue_lock is unlocked at this point */
+ spin_unlock_irq(q->queue_lock);
return rq;
}
EXPORT_SYMBOL(blk_get_request);
@@ -1200,8 +1204,7 @@ get_rq:
rw_flags |= REQ_SYNC;
/*
- * Grab a free request. This is might sleep but can not fail.
- * Returns with the queue unlocked.
+ * Grab a free request.
*/
req = get_request_wait(q, rw_flags, bio);
@@ -1213,7 +1216,6 @@ get_rq:
*/
init_request_from_bio(req, bio);
- spin_lock_irq(q->queue_lock);
if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) ||
bio_flagged(bio, BIO_CPU_AFFINE))
req->cpu = blk_cpu_to_group(smp_processor_id());
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index f65c6f0..3d8635d 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -2543,12 +2543,12 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
cfq_put_cfqg(orig_cfqg);
}
+typedef void (cic_call_fn)(struct io_context *, struct cfq_io_context *);
+
/*
* Must always be called with the rcu_read_lock() held
*/
-static void
-__call_for_each_cic(struct io_context *ioc,
- void (*func)(struct io_context *, struct cfq_io_context *))
+static void __call_for_each_cic(struct io_context *ioc, cic_call_fn *func)
{
struct cfq_io_context *cic;
struct hlist_node *n;
@@ -2560,9 +2560,7 @@ __call_for_each_cic(struct io_context *ioc,
/*
* Call func for each cic attached to this ioc.
*/
-static void
-call_for_each_cic(struct io_context *ioc,
- void (*func)(struct io_context *, struct cfq_io_context *))
+static void call_for_each_cic(struct io_context *ioc, cic_call_fn *func)
{
rcu_read_lock();
__call_for_each_cic(ioc, func);
@@ -2787,13 +2785,10 @@ static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic)
{
struct cfq_data *cfqd = cic_to_cfqd(cic);
struct cfq_queue *cfqq;
- unsigned long flags;
if (unlikely(!cfqd))
return;
- spin_lock_irqsave(cfqd->queue->queue_lock, flags);
-
cfqq = cic->cfqq[BLK_RW_ASYNC];
if (cfqq) {
struct cfq_queue *new_cfqq;
@@ -2808,8 +2803,6 @@ static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic)
cfqq = cic->cfqq[BLK_RW_SYNC];
if (cfqq)
cfq_mark_cfqq_prio_changed(cfqq);
-
- spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
}
static void cfq_ioc_set_ioprio(struct io_context *ioc)
@@ -3057,11 +3050,8 @@ static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
radix_tree_preload_end();
- if (!ret) {
- spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+ if (!ret)
list_add(&cic->queue_list, &cfqd->cic_list);
- spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
- }
}
if (ret)
@@ -3081,8 +3071,6 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
struct io_context *ioc = NULL;
struct cfq_io_context *cic;
- might_sleep_if(gfp_mask & __GFP_WAIT);
-
ioc = get_io_context(gfp_mask, cfqd->queue->node);
if (!ioc)
return NULL;
@@ -3633,14 +3621,10 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
const int rw = rq_data_dir(rq);
const bool is_sync = rq_is_sync(rq);
struct cfq_queue *cfqq;
- unsigned long flags;
might_sleep_if(gfp_mask & __GFP_WAIT);
cic = cfq_get_io_context(cfqd, gfp_mask);
-
- spin_lock_irqsave(q->queue_lock, flags);
-
if (!cic)
goto queue_fail;
@@ -3673,8 +3657,6 @@ new_queue:
cfqq->allocated[rw]++;
atomic_inc(&cfqq->ref);
- spin_unlock_irqrestore(q->queue_lock, flags);
-
rq->elevator_private = cic;
rq->elevator_private2 = cfqq;
rq->elevator_private3 = cfq_ref_get_cfqg(cfqq->cfqg);
@@ -3685,7 +3667,6 @@ queue_fail:
put_io_context(cic->ioc);
cfq_schedule_dispatch(cfqd);
- spin_unlock_irqrestore(q->queue_lock, flags);
cfq_log(cfqd, "set_request fail");
return 1;
}
--
1.7.1.426.gb436
EOF
;;
*)
echo ERROR
;;
esac
}
# Argument processing
if [ $# != 1 ]; then
usage
exit 1
fi
if [ "${1#[0-9]*.[0-9]*.[0-9]*.[0-9]*}" != "$1" ]; then
kernel_version="${1%.[0-9]*}"
patch_level="${1#${kernel_version}.}"
else
kernel_version="$1"
fi
# Actual kernel source generation
if [ -e linux-${kernel_version} -o -e linux-$1 ]; then
echo "Error: directoy not clean."
exit 1
fi
echo "Extracting kernel sources ..."
tar xaf $TARBALLDIR/linux-${kernel_version}.tar.bz2 || exit $?
if [ "${patch_level}" != "" ]; then
mv -i linux-${kernel_version} linux-$1 || exit $?
fi
cd linux-$1 || exit $?
if [ "${patch_level}" != "" ]; then
patchfile="patch-${kernel_version}.${patch_level}"
echo "Applying ${patchfile} ..."
bzip2 -cd <${TARBALLDIR}/${patchfile}.bz2 | \
patch -p1 -s
fi
if [ "${kernel_version}" "<" "2.6.36" ]; then
# IB/srp: Use print_hex_dump()
# IB/srp: Make receive buffer handling more robust
# IB/srp: Export req_lim via sysfs
for commit in \
7a7008110b94dfaa90db4b0cc5b0c3f964c80506 \
c996bb47bb419b7c2f75499e11750142775e5da9 \
89de74866b846cc48780fda3de7fd223296aaca9
do
echo "Applying patch $commit ..."
get_2_6_36_patch $commit | patch -p1 -s
done
fi
# IB/srp: Preparation for transmit ring response allocation
# IB/srp: Implement SRP_CRED_REQ and SRP_AER_REQ
# IB/srp: Eliminate two forward declarations
# IB/srp: Reduce number of BUSY conditions
# IB/srp: Introduce list_first_entry()
for p in \
143381 \
143391 \
143401 \
143411 \
143421
do
echo "Applying patch $p ..."
get_2_6_37_patch $p | patch -p1 -s
done
echo "Applying locking-per-lun patch ..."
get_locking_per_lun_patch | patch -p1 -s
echo "Applying Jens' block layer optimization patches ..."
if [ "${kernel_version}" "<" "2.6.38" ]; then
# block: kill request batching
# block: add separate sync/async rq allocation mempools
# block: get rid of request_list->starved[]
# block: optimize rq allocation path for less queue locking
for commit in \
5a00f237eb167a5e98d5f3bb56e11e4da406a5bc \
76241c12f6a730241b9fa6a795dff55f826ce391 \
35f2046ac858ca165a8aba477c9236e53a8dbffa \
38bb177765247024dad4b70a2abe0044d0574998
do
echo "Applying patch $commit ..."
get_block_layer_patch $commit | patch -p1 -s
done
fi