Patch "target: Fix LUN_RESET active TMR descriptor handling" has been added to the 4.4-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
target: Fix LUN_RESET active TMR descriptor handling
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
target-fix-lun_reset-active-tmr-descriptor-handling.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
a6d9bb1c9605cd4f44e2d8290dc4d0e88f20292dMon Sep 17 00:00:00 2001
From: Nicholas Bellinger <[email protected]>
Date: Mon, 11 Jan 2016 21:53:05 -0800
Subject: target: Fix LUN_RESET active TMR descriptor handling
From: Nicholas Bellinger <[email protected]>
commit a6d9bb1c9605cd4f44e2d8290dc4d0e88f20292d upstream.
This patch fixes a NULL pointer se_cmd->cmd_kref < 0 refcount bug during TMR LUN_RESET with active TMRs, triggered during se_cmd + se_tmr_req descriptor shutdown + release via core_tmr_drain_tmr_list().
To address this bug, go ahead and obtain a local kref_get_unless_zero(&se_cmd->cmd_kref) for active I/O to set CMD_T_ABORTED, and transport_wait_for_tasks() followed by the final target_put_sess_cmd() to drop the local ->cmd_kref.
Also add two new checks within target_tmr_work() to avoid CMD_T_ABORTED -> TFO->queue_tm_rsp() callbacks ahead of invoking the backend -> fabric put in transport_cmd_check_stop_to_fabric().
For good measure, also change core_tmr_release_req() to use list_del_init() ahead of se_tmr_req memory free.
--- drivers/target/target_core_tmr.c | 22 +++++++++++++++++++++- drivers/target/target_core_transport.c | 17 +++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-)
drivers/target/target_core_tmr.c +21 -1
@@ -68,7 +68,7 @@ void core_tmr_release_req(struct se_tmr_if (dev) {spin_lock_irqsave (&dev->se_tmr_lock, flags); -list_del (&tmr->tmr_list); +list_del_init (&tmr->tmr_list);spin_unlock_irqrestore (&dev->se_tmr_lock, flags); }
@@ -194,9 +194,11 @@ static void core_tmr_drain_tmr_list( struct list_head *preempt_and_abort_list) {LIST_HEAD (drain_tmr_list); +struct se_session *sess;struct se_tmr_req *tmr_p, *tmr_pp;struct se_cmd *cmd;unsigned long flags; +bool rc;/* * Release all pending and outgoing TMRs aside from the received * LUN_RESET tmr..
@@ -222,17 +224,31 @@ static void core_tmr_drain_tmr_list(if (target_check_cdb_and_preempt (preempt_and_abort_list, cmd))continue ; + sess = cmd->se_sess; +if (WARN_ON_ONCE (!sess)) +continue ; + +spin_lock (&sess->sess_cmd_lock);spin_lock (&cmd->t_state_lock);if (!(cmd->transport_state &CMD_T_ACTIVE )) {spin_unlock (&cmd->t_state_lock); +spin_unlock (&sess->sess_cmd_lock);continue ; }if (cmd->t_state ==TRANSPORT_ISTATE_PROCESSING ) {spin_unlock (&cmd->t_state_lock); +spin_unlock (&sess->sess_cmd_lock);continue ; } + cmd->transport_state |=CMD_T_ABORTED ;spin_unlock (&cmd->t_state_lock); + rc =kref_get_unless_zero (&cmd->cmd_kref); +spin_unlock (&sess->sess_cmd_lock); +if (!rc) { +printk ("LUN_RESET TMR: non-zero kref_get_unless_zero\n" ); +continue ; + }list_move_tail (&tmr_p->tmr_list, &drain_tmr_list); }spin_unlock_irqrestore (&dev->se_tmr_lock, flags);
@@ -246,7 +262,11 @@ static void core_tmr_drain_tmr_list( (preempt_and_abort_list) ?"Preempt" :"" , tmr_p, tmr_p->function, tmr_p->response, cmd->t_state); +cancel_work_sync (&cmd->work); +transport_wait_for_tasks (cmd); +transport_cmd_finish_abort (cmd,1 ); +target_put_sess_cmd (cmd); } }
drivers/target/target_core_transport.c +17 -0
@@ -2891,8 +2891,17 @@ static void target_tmr_work(struct work_ struct se_cmd *cmd = container_of(work, struct se_cmd, work);struct se_device *dev = cmd->se_dev;struct se_tmr_req *tmr = cmd->se_tmr_req; +unsigned long flags;int ret; +spin_lock_irqsave (&cmd->t_state_lock, flags); +if (cmd->transport_state &CMD_T_ABORTED ) { + tmr->response =TMR_FUNCTION_REJECTED ; +spin_unlock_irqrestore (&cmd->t_state_lock, flags); + goto check_stop; + } +spin_unlock_irqrestore (&cmd->t_state_lock, flags); +switch (tmr->function) {case TMR_ABORT_TASK :core_tmr_abort_task (dev, tmr, cmd->se_sess);
@@ -2925,9 +2934,17 @@ static void target_tmr_work(struct work_break ; } +spin_lock_irqsave (&cmd->t_state_lock, flags); +if (cmd->transport_state &CMD_T_ABORTED ) { +spin_unlock_irqrestore (&cmd->t_state_lock, flags); + goto check_stop; + } cmd->t_state =TRANSPORT_ISTATE_PROCESSING ; +spin_unlock_irqrestore (&cmd->t_state_lock, flags); + cmd->se_tfo->queue_tm_rsp (cmd); +check_stop:transport_cmd_check_stop_to_fabric (cmd); }
Patches currently in stable-queue which might be from [email protected] are
queue-4.4/qla2xxx-fix-stale-pointer-access.patch queue-4.4/target-fix-remote-port-tmr-abort-se_cmd-fabric-stop.patch queue-4.4/target-fix-lun_reset-active-tmr-descriptor-handling.patch queue-4.4/target-fix-race-with-scf_send_delayed_tas-handling.patch queue-4.4/target-fix-lun_reset-active-i-o-handling-for-ack_kref.patch queue-4.4/target-fix-tas-handling-for-multi-session-se_node_acls.patch