Commit f2f7b09c authored by Kiran Patil's avatar Kiran Patil Committed by James Bottomley

[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: default avatarKiran Patil <kiran.patil@intel.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent e3e65c69
...@@ -380,12 +380,23 @@ static void ft_send_resp_status(struct fc_lport *lport, ...@@ -380,12 +380,23 @@ static void ft_send_resp_status(struct fc_lport *lport,
/* /*
* Send error or task management response. * Send error or task management response.
* Always frees the cmd and associated state.
*/ */
static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) static void ft_send_resp_code(struct ft_cmd *cmd,
enum fcp_resp_rsp_codes code)
{ {
ft_send_resp_status(cmd->sess->tport->lport, ft_send_resp_status(cmd->sess->tport->lport,
cmd->req_frame, SAM_STAT_GOOD, code); cmd->req_frame, SAM_STAT_GOOD, code);
}
/*
* Send error or task management response.
* Always frees the cmd and associated state.
*/
static void ft_send_resp_code_and_free(struct ft_cmd *cmd,
enum fcp_resp_rsp_codes code)
{
ft_send_resp_code(cmd, code);
ft_free_cmd(cmd); ft_free_cmd(cmd);
} }
...@@ -423,7 +434,7 @@ static void ft_send_tm(struct ft_cmd *cmd) ...@@ -423,7 +434,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
* tm_flags set is invalid. * tm_flags set is invalid.
*/ */
FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
return; return;
} }
...@@ -431,7 +442,7 @@ static void ft_send_tm(struct ft_cmd *cmd) ...@@ -431,7 +442,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func);
if (!tmr) { if (!tmr) {
FT_TM_DBG("alloc failed\n"); FT_TM_DBG("alloc failed\n");
ft_send_resp_code(cmd, FCP_TMF_FAILED); ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
return; return;
} }
cmd->se_cmd.se_tmr_req = tmr; cmd->se_cmd.se_tmr_req = tmr;
...@@ -670,7 +681,7 @@ static void ft_send_cmd(struct ft_cmd *cmd) ...@@ -670,7 +681,7 @@ static void ft_send_cmd(struct ft_cmd *cmd)
return; return;
err: err:
ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment