#!/bin/bash # Generates a 2.6.34.*, 2.6.35.* or 2.6.36* kernel tree with the SRP_CRED_REQ # 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 " } apply_locking_per_lun_patch() { patch -p1 <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 +553,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 +572,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 +604,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 +631,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 +816,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 +831,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 +843,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 +883,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 +903,28 @@ 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); - if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) - return NULL; + spin_lock_irqsave(&target->lock, flags); + + 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]; + 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 +938,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 +946,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 +1001,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 +1008,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 +1023,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 +1059,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 +1075,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 +1084,53 @@ 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 wc[16]; + 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(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) { struct srp_target_port *target = target_ptr; - struct ib_wc wc; + struct ib_wc wc[16]; + int i, n; + unsigned long flags; - 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; - } + while ((n = ib_poll_cq(cq, ARRAY_SIZE(wc), wc)) > 0) { + spin_lock_irqsave(&target->lock, flags); + 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; + spin_unlock_irqrestore(&target->lock, flags); + goto out; + } - ++target->tx_tail; + list_add_tail(&target->tx_ring[wc[i].wr_id]->list, + &target->tx_free); + } + spin_unlock_irqrestore(&target->lock, flags); } +out: + return; } static int srp_queuecommand(struct scsi_cmnd *scmnd, @@ -1138,6 +1142,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 +1162,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 +1188,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 +1196,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 +1226,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 +1400,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 +1471,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 +1497,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 +1504,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 +1534,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 +1543,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 +1563,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; } @@ -1981,6 +1989,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 +1997,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 +2210,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 +2228,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..f665cea 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -148,19 +148,19 @@ struct srp_target_port { struct ib_qp *qp; 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 +173,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..3819d66 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -749,11 +749,16 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) if (unlikely(host->shost_state == SHOST_DEL)) { cmd->result = (DID_NO_CONNECT << 16); scsi_done(cmd); + spin_unlock_irqrestore(host->host_lock, flags); } else { trace_scsi_dispatch_cmd_start(cmd); + if (host->unlocked_qcmds) + spin_unlock_irqrestore(host->host_lock, flags); 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 } # 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 ..." url="http://git.kernel.org/?p=linux/kernel/git/roland/infiniband.git;a=patch;h=$commit" wget -O- -q "$url" | \ awk 'BEGIN{h=1}h==0{print}/^diff /{h=0}' | \ 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: Reduce number of BUSY conditions # IB/srp: use multiple CPU cores more effectively for p in \ 143381 \ 143391 \ 143401 \ 143411 \ 143421 do echo "Applying patch $p ..." url="https://patchwork.kernel.org/patch/$p/raw/" wget -O- -q "$url" | patch -p1 -s done apply_locking_per_lun_patch