aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorKiran Patil <kiran.patil@intel.com>2011-06-20 19:59:41 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-06-29 17:32:31 -0400
commitf2f7b09ccea1717026915a4401f0452f05c97364 (patch)
tree238d65acd5bc7771b2a7e96f4c8988c8fecc977e /drivers/target
parente3e65c69c3cfe8e407797c78fd11808aee1a8a81 (diff)
[SCSI] tcm_fc: Fixing reference counting problem which was causing ft_sess to be deleted.
Problem: After fixing the issue in TCM core w.r.t LUN Reset (Task Management request) , ran into issue where during the completing of this LUN Reset command, reference count of "ft_sess" drops to zero which caused "sess" to be deleted. Fix: As part of handling task management request (e.g. LUN Reset), TCM core function "transport_generic_do_tmr" ends up calling ft_free_cmd which in turn calls "ft_sess_put" (which drops session's reference count by 1) and then frees ft_cmd. Then function "transport_generic_do_tmr" calls "transport_cmd_check_stop" which in turn also calls ft_free_cmd (which calls ft_sess_put - which drops reference count of sess by 1, hence reference count of sess becomes zero and session gets deleted). Fix is to just send response in case of tmr from function "ft_queue_resp_code" and not delete "ft_cmd" (means don't call ft_free_cmd). Earlier code was to send the response code and also free ft_cmd. ft_free_cmd will be freed later after sending response code as a result of "transport_cmd_check_stop" (which calls ft_release_cmd -> ft_free_cmd) being called from "transport_generic_do_tmr" after sening TMR response code. Notes/Dependencies: This bug was found after fixing NULL pointer access issue in TCM core (in LUN Reset codepath) Signed-off-by: Kiran Patil <kiran.patil@intel.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index b9cea59d43b4..328ea2bccbdc 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -380,12 +380,23 @@ static void ft_send_resp_status(struct fc_lport *lport,
380 380
381/* 381/*
382 * Send error or task management response. 382 * Send error or task management response.
383 * Always frees the cmd and associated state.
384 */ 383 */
385static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) 384static void ft_send_resp_code(struct ft_cmd *cmd,
385 enum fcp_resp_rsp_codes code)
386{ 386{
387 ft_send_resp_status(cmd->sess->tport->lport, 387 ft_send_resp_status(cmd->sess->tport->lport,
388 cmd->req_frame, SAM_STAT_GOOD, code); 388 cmd->req_frame, SAM_STAT_GOOD, code);
389}
390
391
392/*
393 * Send error or task management response.
394 * Always frees the cmd and associated state.
395 */
396static void ft_send_resp_code_and_free(struct ft_cmd *cmd,
397 enum fcp_resp_rsp_codes code)
398{
399 ft_send_resp_code(cmd, code);
389 ft_free_cmd(cmd); 400 ft_free_cmd(cmd);
390} 401}
391 402
@@ -423,7 +434,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
423 * tm_flags set is invalid. 434 * tm_flags set is invalid.
424 */ 435 */
425 FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); 436 FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
426 ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); 437 ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
427 return; 438 return;
428 } 439 }
429 440
@@ -431,7 +442,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
431 tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); 442 tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func);
432 if (!tmr) { 443 if (!tmr) {
433 FT_TM_DBG("alloc failed\n"); 444 FT_TM_DBG("alloc failed\n");
434 ft_send_resp_code(cmd, FCP_TMF_FAILED); 445 ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
435 return; 446 return;
436 } 447 }
437 cmd->se_cmd.se_tmr_req = tmr; 448 cmd->se_cmd.se_tmr_req = tmr;
@@ -670,7 +681,7 @@ static void ft_send_cmd(struct ft_cmd *cmd)
670 return; 681 return;
671 682
672err: 683err:
673 ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); 684 ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
674 return; 685 return;
675} 686}
676 687