summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-04-07 04:54:26 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2012-04-07 04:54:26 +0200
commita0421da44fc8dcb94aad8889dae285f7ee923f80 (patch)
tree27151ae945fef45b29bb406f512c757847cc229c /drivers
parentMerge branch 'stable' of git://git.kernel.org/pub/scm/linux/kernel/git/cmetca... (diff)
parenttcm_fc: Do not free tpg structure during wq allocation failure (diff)
downloadlinux-a0421da44fc8dcb94aad8889dae285f7ee923f80.tar.xz
linux-a0421da44fc8dcb94aad8889dae285f7ee923f80.zip
Merge branch '3.4-rc-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull target fixes from Nicholas Bellinger: "Pull two tcm_fc fabric related fixes for -rc2: Note that both have been CC'ed to stable, and patch #1 is the important one that addresses a memory corruption bug related to FC exchange timeouts + command abort. Thanks again to MDR for tracking down this issue!" * '3.4-rc-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: tcm_fc: Do not free tpg structure during wq allocation failure tcm_fc: Add abort flag for gracefully handling exchange timeout
Diffstat (limited to 'drivers')
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h1
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c10
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c13
-rw-r--r--drivers/target/tcm_fc/tfc_io.c2
4 files changed, 19 insertions, 7 deletions
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index 830657908db8..c5eb3c33c3db 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -122,6 +122,7 @@ struct ft_cmd {
/* Local sense buffer */
unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER];
u32 was_ddp_setup:1; /* Set only if ddp is setup */
+ u32 aborted:1; /* Set if aborted by reset or timeout */
struct scatterlist *sg; /* Set only if DDP is setup */
u32 sg_cnt; /* No. of item in scatterlist */
};
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index 62dec9715ce5..a375f257aabc 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -121,6 +121,8 @@ int ft_queue_status(struct se_cmd *se_cmd)
struct fc_exch *ep;
size_t len;
+ if (cmd->aborted)
+ return 0;
ft_dump_cmd(cmd, __func__);
ep = fc_seq_exch(cmd->seq);
lport = ep->lp;
@@ -187,6 +189,8 @@ int ft_write_pending(struct se_cmd *se_cmd)
ft_dump_cmd(cmd, __func__);
+ if (cmd->aborted)
+ return 0;
ep = fc_seq_exch(cmd->seq);
lport = ep->lp;
fp = fc_frame_alloc(lport, sizeof(*txrdy));
@@ -252,10 +256,10 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
struct ft_cmd *cmd = arg;
struct fc_frame_header *fh;
- if (IS_ERR(fp)) {
+ if (unlikely(IS_ERR(fp))) {
/* XXX need to find cmd if queued */
cmd->seq = NULL;
- transport_generic_free_cmd(&cmd->se_cmd, 0);
+ cmd->aborted = true;
return;
}
@@ -399,6 +403,8 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)
struct se_tmr_req *tmr = se_cmd->se_tmr_req;
enum fcp_resp_rsp_codes code;
+ if (cmd->aborted)
+ return 0;
switch (tmr->response) {
case TMR_FUNCTION_COMPLETE:
code = FCP_TMF_CMPL;
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index f357039349ba..2948dc944619 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -300,6 +300,7 @@ static struct se_portal_group *ft_add_tpg(
{
struct ft_lport_acl *lacl;
struct ft_tpg *tpg;
+ struct workqueue_struct *wq;
unsigned long index;
int ret;
@@ -321,18 +322,20 @@ static struct se_portal_group *ft_add_tpg(
tpg->lport_acl = lacl;
INIT_LIST_HEAD(&tpg->lun_list);
- ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg,
- tpg, TRANSPORT_TPG_TYPE_NORMAL);
- if (ret < 0) {
+ wq = alloc_workqueue("tcm_fc", 0, 1);
+ if (!wq) {
kfree(tpg);
return NULL;
}
- tpg->workqueue = alloc_workqueue("tcm_fc", 0, 1);
- if (!tpg->workqueue) {
+ ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg,
+ tpg, TRANSPORT_TPG_TYPE_NORMAL);
+ if (ret < 0) {
+ destroy_workqueue(wq);
kfree(tpg);
return NULL;
}
+ tpg->workqueue = wq;
mutex_lock(&ft_lport_lock);
list_add_tail(&tpg->list, &lacl->tpg_list);
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index 2b693eefac55..dc7c0db26e20 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -81,6 +81,8 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
void *from;
void *to = NULL;
+ if (cmd->aborted)
+ return 0;
ep = fc_seq_exch(cmd->seq);
lport = ep->lp;
cmd->seq = lport->tt.seq_start_next(cmd->seq);