lkml.org 
[lkml]   [2010]   [May]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[16/39] [S390] dasd: fix race between tasklet and dasd_sleep_on

    2.6.33-stable review patch. If anyone has any objections, please let us know.

    ------------------
    From: Stefan Weinhuber <wein@de.ibm.com>

    commit 1c1e093cbf6d3a7576ba0bd10363362a1c5c74ee upstream.

    The various dasd_sleep_on functions use a global wait queue when
    waiting for a cqr. The wait condition checks the status and devlist
    fields of the cqr to determine if it is safe to continue. This
    evaluation may return true, although the tasklet has not finished
    processing of the cqr and the callback function has not been called
    yet. When the callback is finally called, the data in the cqr may
    already be invalid. The sleep_on wait condition needs a safe way to
    determine if the tasklet has finished processing. Use the
    callback_data field of the cqr to store a token, which is set by
    the callback function itself.

    Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    drivers/s390/block/dasd.c | 17 ++++++++++-------
    1 file changed, 10 insertions(+), 7 deletions(-)

    --- a/drivers/s390/block/dasd.c
    +++ b/drivers/s390/block/dasd.c
    @@ -35,6 +35,9 @@
    */
    #define DASD_CHANQ_MAX_SIZE 4

    +#define DASD_SLEEPON_START_TAG (void *) 1
    +#define DASD_SLEEPON_END_TAG (void *) 2
    +
    /*
    * SECTION: exported variables of dasd.c
    */
    @@ -1460,7 +1463,10 @@ void dasd_add_request_tail(struct dasd_c
    */
    static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
    {
    - wake_up((wait_queue_head_t *) data);
    + spin_lock_irq(get_ccwdev_lock(cqr->startdev->cdev));
    + cqr->callback_data = DASD_SLEEPON_END_TAG;
    + spin_unlock_irq(get_ccwdev_lock(cqr->startdev->cdev));
    + wake_up(&generic_waitq);
    }

    static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
    @@ -1470,10 +1476,7 @@ static inline int _wait_for_wakeup(struc

    device = cqr->startdev;
    spin_lock_irq(get_ccwdev_lock(device->cdev));
    - rc = ((cqr->status == DASD_CQR_DONE ||
    - cqr->status == DASD_CQR_NEED_ERP ||
    - cqr->status == DASD_CQR_TERMINATED) &&
    - list_empty(&cqr->devlist));
    + rc = (cqr->callback_data == DASD_SLEEPON_END_TAG);
    spin_unlock_irq(get_ccwdev_lock(device->cdev));
    return rc;
    }
    @@ -1561,7 +1564,7 @@ static int _dasd_sleep_on(struct dasd_cc
    wait_event(generic_waitq, !(device->stopped));

    cqr->callback = dasd_wakeup_cb;
    - cqr->callback_data = (void *) &generic_waitq;
    + cqr->callback_data = DASD_SLEEPON_START_TAG;
    dasd_add_request_tail(cqr);
    if (interruptible) {
    rc = wait_event_interruptible(
    @@ -1640,7 +1643,7 @@ int dasd_sleep_on_immediatly(struct dasd
    }

    cqr->callback = dasd_wakeup_cb;
    - cqr->callback_data = (void *) &generic_waitq;
    + cqr->callback_data = DASD_SLEEPON_START_TAG;
    cqr->status = DASD_CQR_QUEUED;
    list_add(&cqr->devlist, &device->ccw_queue);




    \
     
     \ /
      Last update: 2010-05-25 01:33    [W:0.023 / U:0.636 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site