Commit 8bcc2412 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by James Bottomley

[SCSI] Add missing completion to scsi_complete_async_scans()

If either scsi_complete_async_scans() is called a second time
before the first call has finished, or a host scan is started while
scsi_complete_async_scans() is still sleeping, it would fail to wake up
the other task, which would sleep forever.

I've changed the kernel-doc to make it clear that
scsi_complete_async_scans() only guarantees that scans which started
before it was called are guaranteed to have finished when it returns.
I considered making it wait until all scans are completed, but it can't
guarantee that no more scans will start before it returns anyway, and it
runs the risk of confusing other callers of scsi_complete_async_scans()
for hosts actually scanning.
Signed-off-by: default avatarMatthew Wilcox <matthew@wil.cx>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 23be331d
...@@ -133,12 +133,10 @@ struct async_scan_data { ...@@ -133,12 +133,10 @@ struct async_scan_data {
/** /**
* scsi_complete_async_scans - Wait for asynchronous scans to complete * scsi_complete_async_scans - Wait for asynchronous scans to complete
* *
* Asynchronous scans add themselves to the scanning_hosts list. Once * When this function returns, any host which started scanning before
* that list is empty, we know that the scans are complete. Rather than * this function was called will have finished its scan. Hosts which
* waking up periodically to check the state of the list, we pretend to be * started scanning after this function was called may or may not have
* a scanning task by adding ourselves at the end of the list and going to * finished.
* sleep. When the task before us wakes us up, we take ourselves off the
* list and return.
*/ */
int scsi_complete_async_scans(void) int scsi_complete_async_scans(void)
{ {
...@@ -171,6 +169,11 @@ int scsi_complete_async_scans(void) ...@@ -171,6 +169,11 @@ int scsi_complete_async_scans(void)
spin_lock(&async_scan_lock); spin_lock(&async_scan_lock);
list_del(&data->list); list_del(&data->list);
if (!list_empty(&scanning_hosts)) {
struct async_scan_data *next = list_entry(scanning_hosts.next,
struct async_scan_data, list);
complete(&next->prev_finished);
}
done: done:
spin_unlock(&async_scan_lock); spin_unlock(&async_scan_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment