sound: oss: dmasound: kill SLEEP() macro to avoid race
authorArnd Bergmann <arnd@arndb.de>
Thu, 2 Jan 2014 12:07:50 +0000 (13:07 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 14 Jan 2014 15:12:07 +0000 (16:12 +0100)
The use of interruptible_sleep_on_timeout in the dmasound driver
is questionable and we want to kill off all sleep_on variants.
This replaces the calls with wait_event_interruptible_timeout
where possible, to wait for a particular event instead of blocking
in a racy way. In the sq_write function, the easiest solution is
an open-coded prepare_to_wait loop.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/oss/dmasound/dmasound.h
sound/oss/dmasound/dmasound_core.c

index 1308d8d..01019f0 100644 (file)
@@ -239,7 +239,6 @@ struct sound_queue {
     int busy, syncing, xruns, died;
 };
 
-#define SLEEP(queue)           interruptible_sleep_on_timeout(&queue, HZ)
 #define WAKE_UP(queue)         (wake_up_interruptible(&queue))
 
 extern struct sound_queue dmasound_write_sq;
index bac43b5..f4ee85a 100644 (file)
@@ -619,15 +619,27 @@ static ssize_t sq_write(struct file *file, const char __user *src, size_t uLeft,
        }
 
        while (uLeft) {
+               DEFINE_WAIT(wait);
+
                while (write_sq.count >= write_sq.max_active) {
+                       prepare_to_wait(&write_sq.action_queue, &wait, TASK_INTERRUPTIBLE);
                        sq_play();
-                       if (write_sq.non_blocking)
+                       if (write_sq.non_blocking) {
+                               finish_wait(&write_sq.action_queue, &wait);
                                return uWritten > 0 ? uWritten : -EAGAIN;
-                       SLEEP(write_sq.action_queue);
-                       if (signal_pending(current))
+                       }
+                       if (write_sq.count < write_sq.max_active)
+                               break;
+
+                       schedule_timeout(HZ);
+                       if (signal_pending(current)) {
+                               finish_wait(&write_sq.action_queue, &wait);
                                return uWritten > 0 ? uWritten : -EINTR;
+                       }
                }
 
+               finish_wait(&write_sq.action_queue, &wait);
+
                /* Here, we can avoid disabling the interrupt by first
                 * copying and translating the data, and then updating
                 * the write_sq variables. Until this is done, the interrupt
@@ -707,11 +719,8 @@ static int sq_open2(struct sound_queue *sq, struct file *file, fmode_t mode,
                        if (file->f_flags & O_NONBLOCK)
                                return rc;
                        rc = -EINTR;
-                       while (sq->busy) {
-                               SLEEP(sq->open_queue);
-                               if (signal_pending(current))
-                                       return rc;
-                       }
+                       if (wait_event_interruptible(sq->open_queue, !sq->busy))
+                               return rc;
                        rc = 0;
 #else
                        /* OSS manual says we will return EBUSY regardless
@@ -844,7 +853,8 @@ static int sq_fsync(void)
        sq_play();      /* there may be an incomplete frame waiting */
 
        while (write_sq.active) {
-               SLEEP(write_sq.sync_queue);
+               wait_event_interruptible_timeout(write_sq.sync_queue,
+                                                !write_sq.active, HZ);
                if (signal_pending(current)) {
                        /* While waiting for audio output to drain, an
                         * interrupt occurred.  Stop audio output immediately