]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | Subject: [SCSI] Fix hang in starved list processing |
2 | From: Mike Christie <michaelc@cs.wisc.edu> | |
3 | Date: Sun Nov 16 08:13:58 2008 -0600: | |
4 | Git: 2a3a59e5c977654d3aad5bc11cc0aca2303a7f44 | |
5 | References: bnc#464155 | |
6 | ||
7 | Close possible infinite loop with interrupts off when devices are | |
8 | added back to the starved list. | |
9 | ||
10 | Fixes: http://bugzilla.kernel.org/show_bug.cgi?id=11898 | |
11 | ||
12 | Reported-by: <alex.shi@intel.com> | |
13 | Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> | |
14 | Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> | |
15 | Signed-off-by: Hannes Reinecke <hare@suse.de> | |
16 | ||
17 | diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c | |
18 | index f5d3b96..fa45a1a 100644 | |
19 | --- a/drivers/scsi/scsi_lib.c | |
20 | +++ b/drivers/scsi/scsi_lib.c | |
21 | @@ -567,15 +567,18 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost) | |
22 | */ | |
23 | static void scsi_run_queue(struct request_queue *q) | |
24 | { | |
25 | - struct scsi_device *starved_head = NULL, *sdev = q->queuedata; | |
26 | + struct scsi_device *sdev = q->queuedata; | |
27 | struct Scsi_Host *shost = sdev->host; | |
28 | + LIST_HEAD(starved_list); | |
29 | unsigned long flags; | |
30 | ||
31 | if (scsi_target(sdev)->single_lun) | |
32 | scsi_single_lun_run(sdev); | |
33 | ||
34 | spin_lock_irqsave(shost->host_lock, flags); | |
35 | - while (!list_empty(&shost->starved_list) && !scsi_host_is_busy(shost)) { | |
36 | + list_splice_init(&shost->starved_list, &starved_list); | |
37 | + | |
38 | + while (!list_empty(&starved_list)) { | |
39 | int flagset; | |
40 | ||
41 | /* | |
42 | @@ -588,24 +591,18 @@ static void scsi_run_queue(struct request_queue *q) | |
43 | * scsi_request_fn must get the host_lock before checking | |
44 | * or modifying starved_list or starved_entry. | |
45 | */ | |
46 | - sdev = list_entry(shost->starved_list.next, | |
47 | - struct scsi_device, starved_entry); | |
48 | - /* | |
49 | - * The *queue_ready functions can add a device back onto the | |
50 | - * starved list's tail, so we must check for a infinite loop. | |
51 | - */ | |
52 | - if (sdev == starved_head) | |
53 | + if (scsi_host_is_busy(shost)) | |
54 | break; | |
55 | - if (!starved_head) | |
56 | - starved_head = sdev; | |
57 | ||
58 | + sdev = list_entry(starved_list.next, | |
59 | + struct scsi_device, starved_entry); | |
60 | + list_del_init(&sdev->starved_entry); | |
61 | if (scsi_target_is_busy(scsi_target(sdev))) { | |
62 | list_move_tail(&sdev->starved_entry, | |
63 | &shost->starved_list); | |
64 | continue; | |
65 | } | |
66 | ||
67 | - list_del_init(&sdev->starved_entry); | |
68 | spin_unlock(shost->host_lock); | |
69 | ||
70 | spin_lock(sdev->request_queue->queue_lock); | |
71 | @@ -621,6 +618,8 @@ static void scsi_run_queue(struct request_queue *q) | |
72 | ||
73 | spin_lock(shost->host_lock); | |
74 | } | |
75 | + /* put any unprocessed entries back */ | |
76 | + list_splice(&starved_list, &shost->starved_list); | |
77 | spin_unlock_irqrestore(shost->host_lock, flags); | |
78 | ||
79 | blk_run_queue(q); |