> s390irq_spin_lock_irqsave (...);
> dasd_chanq_enq (...);
> dasd_schedule_bh (...);
> do {
> s390irq_spin_unlock_irqrestore (...);
> wait_event ( device->wait_q,
> (((cs = req->status) == CQR_STATUS_DONE) ...);
> s390irq_spin_lock_irqsave (...);
> } while (cs != CQR_STATUS_DONE ...);
> For example, immediately after the `SSM' instruction in the unlock
> is executed an external interrupt could occur. The first bottom
> half routine is then dispatched scheduling the i/o (dasd_run_bh ->
> dasd_start_IO -> do_IO -> SSCH). before the instruction after the SSM
> instruction can be executed, the i/o interrupt could occur.
> `dasd_int_handler' sets the cqr status to DONE and schedules the
> second bottom half routine. Now `dasd_sleep_on_req' doesn't
> wait at all because `wait_event' doesn't wait if the specified
> condition is true. Control returns back to `dasd_format',
> which calls `dasd_free_request', then `dasd_eckd_format_device' which
> zeroes the cqr (effectively setting the status to EMPTY). If an
> external interrupt now occurs then the second bottom half routine
> runs and the bug occurs because it doesn't expect an EMPTY status.
I see a great deal of similarity between the above and a bug
in USB that I fixed. Basically, the waiter must not check the
status of the request (in USB case it was URB), but instead,
poll a flag set by the last callback (in our case the second
bottom half).
-- Pete