Commit 4657fb8a authored by Martin Schwidefsky's avatar Martin Schwidefsky

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 54ad6412
...@@ -231,6 +231,9 @@ struct tape_device { ...@@ -231,6 +231,9 @@ struct tape_device {
/* Request queue. */ /* Request queue. */
struct list_head req_queue; struct list_head req_queue;
/* Request wait queue. */
wait_queue_head_t wait_queue;
/* Each tape device has (currently) two minor numbers. */ /* Each tape device has (currently) two minor numbers. */
int first_minor; int first_minor;
......
...@@ -449,6 +449,7 @@ tape_alloc_device(void) ...@@ -449,6 +449,7 @@ tape_alloc_device(void)
INIT_LIST_HEAD(&device->req_queue); INIT_LIST_HEAD(&device->req_queue);
INIT_LIST_HEAD(&device->node); INIT_LIST_HEAD(&device->node);
init_waitqueue_head(&device->state_change_wq); init_waitqueue_head(&device->state_change_wq);
init_waitqueue_head(&device->wait_queue);
device->tape_state = TS_INIT; device->tape_state = TS_INIT;
device->medium_state = MS_UNKNOWN; device->medium_state = MS_UNKNOWN;
*device->modeset_byte = 0; *device->modeset_byte = 0;
...@@ -954,21 +955,19 @@ __tape_wake_up(struct tape_request *request, void *data) ...@@ -954,21 +955,19 @@ __tape_wake_up(struct tape_request *request, void *data)
int int
tape_do_io(struct tape_device *device, struct tape_request *request) tape_do_io(struct tape_device *device, struct tape_request *request)
{ {
wait_queue_head_t wq;
int rc; int rc;
init_waitqueue_head(&wq);
spin_lock_irq(get_ccwdev_lock(device->cdev)); spin_lock_irq(get_ccwdev_lock(device->cdev));
/* Setup callback */ /* Setup callback */
request->callback = __tape_wake_up; 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. */ /* Add request to request queue and try to start it. */
rc = __tape_start_request(device, request); rc = __tape_start_request(device, request);
spin_unlock_irq(get_ccwdev_lock(device->cdev)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
if (rc) if (rc)
return rc; return rc;
/* Request added to the queue. Wait for its completion. */ /* 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 */ /* Get rc from request */
return request->rc; return request->rc;
} }
...@@ -989,20 +988,19 @@ int ...@@ -989,20 +988,19 @@ int
tape_do_io_interruptible(struct tape_device *device, tape_do_io_interruptible(struct tape_device *device,
struct tape_request *request) struct tape_request *request)
{ {
wait_queue_head_t wq;
int rc; int rc;
init_waitqueue_head(&wq);
spin_lock_irq(get_ccwdev_lock(device->cdev)); spin_lock_irq(get_ccwdev_lock(device->cdev));
/* Setup callback */ /* Setup callback */
request->callback = __tape_wake_up_interruptible; request->callback = __tape_wake_up_interruptible;
request->callback_data = &wq; request->callback_data = &device->wait_queue;
rc = __tape_start_request(device, request); rc = __tape_start_request(device, request);
spin_unlock_irq(get_ccwdev_lock(device->cdev)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
if (rc) if (rc)
return rc; return rc;
/* Request added to the queue. Wait for its completion. */ /* 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) if (rc != -ERESTARTSYS)
/* Request finished normally. */ /* Request finished normally. */
return request->rc; return request->rc;
...@@ -1015,7 +1013,7 @@ tape_do_io_interruptible(struct tape_device *device, ...@@ -1015,7 +1013,7 @@ tape_do_io_interruptible(struct tape_device *device,
/* Wait for the interrupt that acknowledges the halt. */ /* Wait for the interrupt that acknowledges the halt. */
do { do {
rc = wait_event_interruptible( rc = wait_event_interruptible(
wq, device->wait_queue,
(request->callback == NULL) (request->callback == NULL)
); );
} while (rc == -ERESTARTSYS); } while (rc == -ERESTARTSYS);
......
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