[PATCH] sbp2: fix spinlock recursion
sbp2util_mark_command_completed takes a lock which was already taken by sbp2scsi_complete_all_commands. This is a regression in Linux 2.6.15. Reported by Kristian Harms at https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=187394 Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
91a4ee3e04
commit
366c3af0db
+15
-17
@@ -495,22 +495,17 @@ static struct sbp2_command_info *sbp2util_find_command_for_orb(
|
||||
/*
|
||||
* This function finds the sbp2_command for a given outstanding SCpnt.
|
||||
* Only looks at the inuse list.
|
||||
* Must be called with scsi_id->sbp2_command_orb_lock held.
|
||||
*/
|
||||
static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt)
|
||||
static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(
|
||||
struct scsi_id_instance_data *scsi_id, void *SCpnt)
|
||||
{
|
||||
struct sbp2_command_info *command;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
|
||||
list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {
|
||||
if (command->Current_SCpnt == SCpnt) {
|
||||
spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
if (!list_empty(&scsi_id->sbp2_command_orb_inuse))
|
||||
list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list)
|
||||
if (command->Current_SCpnt == SCpnt)
|
||||
return command;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -579,17 +574,15 @@ static void sbp2util_free_command_dma(struct sbp2_command_info *command)
|
||||
|
||||
/*
|
||||
* This function moves a command to the completed orb list.
|
||||
* Must be called with scsi_id->sbp2_command_orb_lock held.
|
||||
*/
|
||||
static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id,
|
||||
struct sbp2_command_info *command)
|
||||
static void sbp2util_mark_command_completed(
|
||||
struct scsi_id_instance_data *scsi_id,
|
||||
struct sbp2_command_info *command)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
list_del(&command->list);
|
||||
sbp2util_free_command_dma(command);
|
||||
list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
|
||||
spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2177,7 +2170,9 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
|
||||
* Matched status with command, now grab scsi command pointers and check status
|
||||
*/
|
||||
SCpnt = command->Current_SCpnt;
|
||||
spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
sbp2util_mark_command_completed(scsi_id, command);
|
||||
spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
|
||||
if (SCpnt) {
|
||||
|
||||
@@ -2513,6 +2508,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
|
||||
(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
|
||||
struct sbp2scsi_host_info *hi = scsi_id->hi;
|
||||
struct sbp2_command_info *command;
|
||||
unsigned long flags;
|
||||
|
||||
SBP2_ERR("aborting sbp2 command");
|
||||
scsi_print_command(SCpnt);
|
||||
@@ -2523,6 +2519,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
|
||||
* Right now, just return any matching command structures
|
||||
* to the free pool.
|
||||
*/
|
||||
spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
|
||||
if (command) {
|
||||
SBP2_DEBUG("Found command to abort");
|
||||
@@ -2540,6 +2537,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
|
||||
command->Current_done(command->Current_SCpnt);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
|
||||
|
||||
/*
|
||||
* Initiate a fetch agent reset.
|
||||
|
||||
Reference in New Issue
Block a user