[S390] tape: fix race with stack local wait_queue_head_t.
A wait_event call with a stack local wait_queue_head_t structure that is used to do the wake up for the wait_event is inherently racy. After the wait_event finished the wake_up call might not have completed yet. Replace the stack local wait_queue_head_t in tape_do_io and tape_do_io_interruptible with a per device wait queue. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
54ad64129c
commit
4657fb8a98
|
@ -231,6 +231,9 @@ struct tape_device {
|
|||
/* Request queue. */
|
||||
struct list_head req_queue;
|
||||
|
||||
/* Request wait queue. */
|
||||
wait_queue_head_t wait_queue;
|
||||
|
||||
/* Each tape device has (currently) two minor numbers. */
|
||||
int first_minor;
|
||||
|
||||
|
|
|
@ -449,6 +449,7 @@ tape_alloc_device(void)
|
|||
INIT_LIST_HEAD(&device->req_queue);
|
||||
INIT_LIST_HEAD(&device->node);
|
||||
init_waitqueue_head(&device->state_change_wq);
|
||||
init_waitqueue_head(&device->wait_queue);
|
||||
device->tape_state = TS_INIT;
|
||||
device->medium_state = MS_UNKNOWN;
|
||||
*device->modeset_byte = 0;
|
||||
|
@ -954,21 +955,19 @@ __tape_wake_up(struct tape_request *request, void *data)
|
|||
int
|
||||
tape_do_io(struct tape_device *device, struct tape_request *request)
|
||||
{
|
||||
wait_queue_head_t wq;
|
||||
int rc;
|
||||
|
||||
init_waitqueue_head(&wq);
|
||||
spin_lock_irq(get_ccwdev_lock(device->cdev));
|
||||
/* Setup callback */
|
||||
request->callback = __tape_wake_up;
|
||||
request->callback_data = &wq;
|
||||
request->callback_data = &device->wait_queue;
|
||||
/* Add request to request queue and try to start it. */
|
||||
rc = __tape_start_request(device, request);
|
||||
spin_unlock_irq(get_ccwdev_lock(device->cdev));
|
||||
if (rc)
|
||||
return rc;
|
||||
/* Request added to the queue. Wait for its completion. */
|
||||
wait_event(wq, (request->callback == NULL));
|
||||
wait_event(device->wait_queue, (request->callback == NULL));
|
||||
/* Get rc from request */
|
||||
return request->rc;
|
||||
}
|
||||
|
@ -989,20 +988,19 @@ int
|
|||
tape_do_io_interruptible(struct tape_device *device,
|
||||
struct tape_request *request)
|
||||
{
|
||||
wait_queue_head_t wq;
|
||||
int rc;
|
||||
|
||||
init_waitqueue_head(&wq);
|
||||
spin_lock_irq(get_ccwdev_lock(device->cdev));
|
||||
/* Setup callback */
|
||||
request->callback = __tape_wake_up_interruptible;
|
||||
request->callback_data = &wq;
|
||||
request->callback_data = &device->wait_queue;
|
||||
rc = __tape_start_request(device, request);
|
||||
spin_unlock_irq(get_ccwdev_lock(device->cdev));
|
||||
if (rc)
|
||||
return rc;
|
||||
/* Request added to the queue. Wait for its completion. */
|
||||
rc = wait_event_interruptible(wq, (request->callback == NULL));
|
||||
rc = wait_event_interruptible(device->wait_queue,
|
||||
(request->callback == NULL));
|
||||
if (rc != -ERESTARTSYS)
|
||||
/* Request finished normally. */
|
||||
return request->rc;
|
||||
|
@ -1015,7 +1013,7 @@ tape_do_io_interruptible(struct tape_device *device,
|
|||
/* Wait for the interrupt that acknowledges the halt. */
|
||||
do {
|
||||
rc = wait_event_interruptible(
|
||||
wq,
|
||||
device->wait_queue,
|
||||
(request->callback == NULL)
|
||||
);
|
||||
} while (rc == -ERESTARTSYS);
|
||||
|
|
Loading…
Reference in New Issue