| From stable-bounces@linux.kernel.org Sat Apr 1 12:00:59 2006 |
| Date: Sat, 1 Apr 2006 21:11:41 +0200 (CEST) |
| From: Stefan Richter <stefanr@s5r6.in-berlin.de> |
| To: Linus Torvalds <torvalds@osdl.org> |
| Message-ID: <tkrat.11bf8809a766b402@s5r6.in-berlin.de> |
| Content-Disposition: INLINE |
| Cc: Jody McIntyre <scjody@modernduck.com>, |
| linux1394-devel@lists.sourceforge.net, stable@kernel.org, |
| linux-kernel@vger.kernel.org |
| Subject: 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> |
| |
| --- |
| drivers/ieee1394/sbp2.c | 32 +++++++++++++++----------------- |
| 1 file changed, 15 insertions(+), 17 deletions(-) |
| |
| --- linux-2.6.16.1.orig/drivers/ieee1394/sbp2.c |
| +++ linux-2.6.16.1/drivers/ieee1394/sbp2.c |
| @@ -495,22 +495,17 @@ static struct sbp2_command_info *sbp2uti |
| /* |
| * 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(st |
| |
| /* |
| * 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(stru |
| * 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_cm |
| (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_cm |
| * 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_cm |
| command->Current_done(command->Current_SCpnt); |
| } |
| } |
| + spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); |
| |
| /* |
| * Initiate a fetch agent reset. |