esp_scsi: Fix tag state corruption when autosensing.
Meelis Roos reports a crash in esp_free_lun_tag() in the presense of a disk which has died. The issue is that when we issue an autosense command, we do so by hijacking the original command that caused the check-condition. When we do so we clear out the ent->tag[] array when we issue it via find_and_prep_issuable_command(). This is so that the autosense command is forced to be issued non-tagged. That is problematic, because it is the value of ent->tag[] which determines whether we issued the original scsi command as tagged vs. non-tagged (see esp_alloc_lun_tag()). And that, in turn, is what trips up the sanity checks in esp_free_lun_tag(). That function needs the original ->tag[] values in order to free up the tag slot properly. Fix this by remembering the original command's tag values, and having esp_alloc_lun_tag() and esp_free_lun_tag() use them. Reported-by: Meelis Roos <mroos@linux.ee> Tested-by: Meelis Roos <mroos@linux.ee> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -530,7 +530,7 @@ static int esp_need_to_nego_sync(struct esp_target_data *tp)
|
|||||||
static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
|
static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
|
||||||
struct esp_lun_data *lp)
|
struct esp_lun_data *lp)
|
||||||
{
|
{
|
||||||
if (!ent->tag[0]) {
|
if (!ent->orig_tag[0]) {
|
||||||
/* Non-tagged, slot already taken? */
|
/* Non-tagged, slot already taken? */
|
||||||
if (lp->non_tagged_cmd)
|
if (lp->non_tagged_cmd)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
@@ -564,9 +564,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(lp->tagged_cmds[ent->tag[1]]);
|
BUG_ON(lp->tagged_cmds[ent->orig_tag[1]]);
|
||||||
|
|
||||||
lp->tagged_cmds[ent->tag[1]] = ent;
|
lp->tagged_cmds[ent->orig_tag[1]] = ent;
|
||||||
lp->num_tagged++;
|
lp->num_tagged++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -575,9 +575,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
|
|||||||
static void esp_free_lun_tag(struct esp_cmd_entry *ent,
|
static void esp_free_lun_tag(struct esp_cmd_entry *ent,
|
||||||
struct esp_lun_data *lp)
|
struct esp_lun_data *lp)
|
||||||
{
|
{
|
||||||
if (ent->tag[0]) {
|
if (ent->orig_tag[0]) {
|
||||||
BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent);
|
BUG_ON(lp->tagged_cmds[ent->orig_tag[1]] != ent);
|
||||||
lp->tagged_cmds[ent->tag[1]] = NULL;
|
lp->tagged_cmds[ent->orig_tag[1]] = NULL;
|
||||||
lp->num_tagged--;
|
lp->num_tagged--;
|
||||||
} else {
|
} else {
|
||||||
BUG_ON(lp->non_tagged_cmd != ent);
|
BUG_ON(lp->non_tagged_cmd != ent);
|
||||||
@@ -667,6 +667,8 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
|
|||||||
ent->tag[0] = 0;
|
ent->tag[0] = 0;
|
||||||
ent->tag[1] = 0;
|
ent->tag[1] = 0;
|
||||||
}
|
}
|
||||||
|
ent->orig_tag[0] = ent->tag[0];
|
||||||
|
ent->orig_tag[1] = ent->tag[1];
|
||||||
|
|
||||||
if (esp_alloc_lun_tag(ent, lp) < 0)
|
if (esp_alloc_lun_tag(ent, lp) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
@@ -271,6 +271,7 @@ struct esp_cmd_entry {
|
|||||||
#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
|
#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
|
||||||
|
|
||||||
u8 tag[2];
|
u8 tag[2];
|
||||||
|
u8 orig_tag[2];
|
||||||
|
|
||||||
u8 status;
|
u8 status;
|
||||||
u8 message;
|
u8 message;
|
||||||
|
Reference in New Issue
Block a user