Fix for double scst_check_local_events() call crash on commands processing path

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3458 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2011-05-18 00:46:37 +00:00
parent 6b3ad5d0fe
commit 988cd9fe3b
3 changed files with 63 additions and 33 deletions

View File

@@ -174,32 +174,26 @@ static inline unsigned int queue_max_hw_sectors(struct request_queue *q)
/* Cmd is going to be sent for execution */
#define SCST_CMD_STATE_SEND_FOR_EXEC 5
/* Cmd is being checked if it should be executed locally */
#define SCST_CMD_STATE_LOCAL_EXEC 6
/* Cmd is ready for execution */
#define SCST_CMD_STATE_REAL_EXEC 7
/* Internal post-exec checks */
#define SCST_CMD_STATE_PRE_DEV_DONE 8
#define SCST_CMD_STATE_PRE_DEV_DONE 6
/* Internal MODE SELECT pages related checks */
#define SCST_CMD_STATE_MODE_SELECT_CHECKS 9
#define SCST_CMD_STATE_MODE_SELECT_CHECKS 7
/* Dev handler's dev_done() is going to be called */
#define SCST_CMD_STATE_DEV_DONE 10
#define SCST_CMD_STATE_DEV_DONE 8
/* Checks before target driver's xmit_response() is called */
#define SCST_CMD_STATE_PRE_XMIT_RESP 11
#define SCST_CMD_STATE_PRE_XMIT_RESP 9
/* Target driver's xmit_response() is going to be called */
#define SCST_CMD_STATE_XMIT_RESP 12
#define SCST_CMD_STATE_XMIT_RESP 10
/* Cmd finished */
#define SCST_CMD_STATE_FINISHED 13
#define SCST_CMD_STATE_FINISHED 11
/* Internal cmd finished */
#define SCST_CMD_STATE_FINISHED_INTERNAL 14
#define SCST_CMD_STATE_FINISHED_INTERNAL 12
#define SCST_CMD_STATE_LAST_ACTIVE (SCST_CMD_STATE_FINISHED_INTERNAL+100)
@@ -215,11 +209,17 @@ static inline unsigned int queue_max_hw_sectors(struct request_queue *q)
/* Waiting for data from the initiator (until scst_rx_data() called) */
#define SCST_CMD_STATE_DATA_WAIT (SCST_CMD_STATE_LAST_ACTIVE+4)
/* Cmd is being checked if it should be executed locally */
#define SCST_CMD_STATE_LOCAL_EXEC (SCST_CMD_STATE_LAST_ACTIVE+5)
/* Cmd is ready for execution */
#define SCST_CMD_STATE_REAL_EXEC (SCST_CMD_STATE_LAST_ACTIVE+6)
/* Waiting for CDB's execution finish */
#define SCST_CMD_STATE_REAL_EXECUTING (SCST_CMD_STATE_LAST_ACTIVE+5)
#define SCST_CMD_STATE_REAL_EXECUTING (SCST_CMD_STATE_LAST_ACTIVE+7)
/* Waiting for response's transmission finish */
#define SCST_CMD_STATE_XMIT_WAIT (SCST_CMD_STATE_LAST_ACTIVE+6)
#define SCST_CMD_STATE_XMIT_WAIT (SCST_CMD_STATE_LAST_ACTIVE+8)
/*************************************************************
* Can be returned instead of cmd's state by dev handlers'
@@ -1884,6 +1884,12 @@ struct scst_cmd {
*/
unsigned int finished:1;
/*
* Set if scst_check_local_events() can be called more than once. Set by
* scst_pre_check_local_events().
*/
unsigned int check_local_events_once_done:1;
#ifdef CONFIG_SCST_DEBUG_TM
/* Set if the cmd was delayed by task management debugging code */
unsigned int tm_dbg_delayed:1;
@@ -3863,6 +3869,13 @@ void scst_post_alloc_data_buf(struct scst_cmd *cmd);
int scst_check_local_events(struct scst_cmd *cmd);
static inline int scst_pre_check_local_events(struct scst_cmd *cmd)
{
int res = scst_check_local_events(cmd);
cmd->check_local_events_once_done = 1;
return res;
}
int scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd);
struct scst_trace_log {

View File

@@ -72,11 +72,14 @@ static inline void scst_dec_pr_readers_count(struct scst_cmd *cmd,
{
struct scst_device *dev = cmd->dev;
/*
* scst_check_local_events() should not be called twice for the
* same cmd
*/
WARN_ON(!cmd->dec_pr_readers_count_needed);
if (unlikely(!cmd->dec_pr_readers_count_needed)) {
PRINT_ERROR("scst_check_local_events() should not be called "
"twice (cmd %p, op %x)! Use "
"scst_pre_check_local_events() instead.", cmd,
cmd->cdb[0]);
WARN_ON(1);
goto out;
}
if (!locked)
spin_lock_bh(&dev->dev_lock);
@@ -91,10 +94,19 @@ static inline void scst_dec_pr_readers_count(struct scst_cmd *cmd,
if (!locked)
spin_unlock_bh(&dev->dev_lock);
out:
EXTRACHECKS_BUG_ON(dev->pr_readers_count < 0);
return;
}
static inline void scst_reset_requeued_cmd(struct scst_cmd *cmd)
{
TRACE_DBG("Reset requeued cmd %p (op %x)", cmd, cmd->cdb[0]);
scst_inc_pr_readers_count(cmd, false);
cmd->check_local_events_once_done = 0;
return;
}
static inline bool scst_pr_type_valid(uint8_t type)
{
switch (type) {

View File

@@ -1950,7 +1950,7 @@ static int scst_reserve_local(struct scst_cmd *cmd)
* it, also there's no point to do any extra protection actions.
*/
rc = scst_check_local_events(cmd);
rc = scst_pre_check_local_events(cmd);
if (unlikely(rc != 0))
goto out_done;
@@ -2011,7 +2011,7 @@ static int scst_release_local(struct scst_cmd *cmd)
* other protection is needed here.
*/
rc = scst_check_local_events(cmd);
rc = scst_pre_check_local_events(cmd);
if (unlikely(rc != 0))
goto out_done;
@@ -2344,8 +2344,11 @@ out_done:
* aborted, > 0 if there is an event and command should be immediately
* completed, or 0 otherwise.
*
* !! Dev handlers implementing exec() callback must call this function there
* !! just before the actual command's execution!
* !! 1.Dev handlers implementing exec() callback must call this function there
* !! just before the actual command's execution!
* !!
* !! 2. If this function can be called more than once on the processing path
* !! scst_pre_check_local_events() should be used for the first call!
*
* On call no locks, no IRQ or IRQ-disabled context allowed.
*/
@@ -2374,14 +2377,16 @@ int scst_check_local_events(struct scst_cmd *cmd)
}
}
if (dev->pr_is_set) {
if (unlikely(!scst_pr_is_cmd_allowed(cmd))) {
scst_set_cmd_error_status(cmd,
SAM_STAT_RESERVATION_CONFLICT);
goto out_complete;
}
} else
scst_dec_pr_readers_count(cmd, false);
if (likely(!cmd->check_local_events_once_done)) {
if (dev->pr_is_set) {
if (unlikely(!scst_pr_is_cmd_allowed(cmd))) {
scst_set_cmd_error_status(cmd,
SAM_STAT_RESERVATION_CONFLICT);
goto out_complete;
}
} else
scst_dec_pr_readers_count(cmd, false);
}
/*
* Let's check for ABORTED after scst_pr_is_cmd_allowed(), because
@@ -2939,7 +2944,7 @@ static int scst_check_sense(struct scst_cmd *cmd)
cmd->state = SCST_CMD_STATE_REAL_EXEC;
cmd->retry = 1;
scst_inc_pr_readers_count(cmd, false);
scst_reset_requeued_cmd(cmd);
res = 1;
goto out;
}