[alsa-devel] [PATCH, RFC 00/30] sleep_on removal
The functions sleep_on, sleep_on_timeout, interruptible_sleep_on and interruptible_sleep_on_timeout have been deprecated for as long as I can remember, and a number of people have contributed patches in the past to remove them from various drivers.
This has recently popped up again and I decided to spend some of my time on tracking down the last users and kill it for good. The work is somewhat related to the BKL removal I did a couple of years ago, since most of these drivers were using the BKL in a way that actually made the sleep_on function safe to call. As the BKL was converted into mutexes, the semantics changed slightly and typically opened up a race between checking a condition and going to sleep.
I don't have any of the hardware that I'm sending the patches for, so it would be great if someone could test them before they get applied. Otherwise please review very carefully.
I'm definitely happy for any patches to go into maintainer trees right away. Obviously the final patch cannot go in until everything else gets merged first and I suspect there will be a series of patches for maintainerless drivers that will go along with it.
Arnd
Arnd Bergmann (30): ataflop: fix sleep_on races scsi: atari_scsi: fix sleep_on race DAC960: remove sleep_on usage swim3: fix interruptible_sleep_on race [media] omap_vout: avoid sleep_on race [media] usbvision: remove bogus sleep_on_timeout [media] radio-cadet: avoid interruptible_sleep_on race [media] arv: fix sleep_on race staging: serqt_usb2: don't use sleep_on staging: gdm72xx: fix interruptible_sleep_on race staging: panel: fix interruptible_sleep_on race parport: fix interruptible_sleep_on race cris: sync_serial: remove interruptible_sleep_on tty/amiserial: avoid interruptible_sleep_on usbserial: stop using interruptible_sleep_on tty: synclink: avoid sleep_on race atm: nicstar: remove interruptible_sleep_on_timeout atm: firestream: fix interruptible_sleep_on race isdn: pcbit: fix interruptible_sleep_on race isdn: hisax/elsa: fix sleep_on race in elsa FSM isdn: divert, hysdn: fix interruptible_sleep_on race isdn: fix multiple sleep_on races oss: msnd_pinnacle: avoid interruptible_sleep_on_timeout oss: midibuf: fix sleep_on races oss: vwsnd: avoid interruptible_sleep_on oss: dmasound: kill SLEEP() macro to avoid race oss: remove last sleep_on users sgi-xp: open-code interruptible_sleep_on_timeout char: nwbutton: open-code interruptible_sleep_on sched: remove sleep_on() and friends
Documentation/DocBook/kernel-hacking.tmpl | 10 ------ arch/cris/arch-v10/drivers/sync_serial.c | 4 ++- arch/cris/arch-v32/drivers/sync_serial.c | 4 ++- drivers/atm/firestream.c | 4 +-- drivers/atm/nicstar.c | 13 ++++---- drivers/block/DAC960.c | 34 +++++++++---------- drivers/block/ataflop.c | 16 ++++----- drivers/block/swim3.c | 18 ++++++---- drivers/char/nwbutton.c | 5 ++- drivers/char/pcmcia/synclink_cs.c | 4 +-- drivers/isdn/divert/divert_procfs.c | 7 ++-- drivers/isdn/hisax/elsa.c | 9 +++-- drivers/isdn/hisax/elsa_ser.c | 3 +- drivers/isdn/hysdn/hysdn_proclog.c | 7 ++-- drivers/isdn/i4l/isdn_common.c | 13 +++++--- drivers/isdn/pcbit/drv.c | 6 ++-- drivers/media/platform/arv.c | 4 +-- drivers/media/platform/omap/omap_vout_vrfb.c | 3 +- drivers/media/radio/radio-cadet.c | 12 +++++-- drivers/media/usb/usbvision/usbvision.h | 4 +-- drivers/misc/sgi-xp/xpc_channel.c | 5 ++- drivers/parport/share.c | 3 +- drivers/scsi/atari_scsi.c | 12 +++++-- drivers/staging/gdm72xx/gdm_usb.c | 5 +-- drivers/staging/panel/panel.c | 4 +-- drivers/staging/serqt_usb2/serqt_usb2.c | 17 ++++------ drivers/tty/amiserial.c | 26 ++++++++++----- drivers/tty/synclink.c | 4 +-- drivers/tty/synclink_gt.c | 4 +-- drivers/tty/synclinkmp.c | 4 +-- drivers/usb/serial/ch341.c | 29 +++++++++++----- drivers/usb/serial/cypress_m8.c | 49 ++++++++++++++++++---------- drivers/usb/serial/f81232.c | 29 +++++++++++----- drivers/usb/serial/pl2303.c | 29 +++++++++++----- include/linux/wait.h | 11 ------- kernel/sched/core.c | 46 -------------------------- sound/oss/dmabuf.c | 14 ++++---- sound/oss/dmasound/dmasound.h | 1 - sound/oss/dmasound/dmasound_core.c | 28 +++++++++++----- sound/oss/midibuf.c | 18 +++++----- sound/oss/msnd_pinnacle.c | 31 ++++++++++-------- sound/oss/sequencer.c | 16 ++++----- sound/oss/sleep.h | 18 ++++++++++ sound/oss/swarm_cs4297a.c | 14 ++++---- sound/oss/vwsnd.c | 14 +++++--- 45 files changed, 334 insertions(+), 277 deletions(-) create mode 100644 sound/oss/sleep.h
We want to remove all sleep_on variants from the kernel because they are racy. In case of the pinnacle driver, we can replace interruptible_sleep_on_timeout with wait_event_interruptible_timeout by changing the meaning of a few flags used in the driver so they are cleared at wakeup time, which is a somewhat more appropriate way to do the same, although probably still racy.
Signed-off-by: Arnd Bergmann arnd@arndb.de Cc: Andrew Veliath andrewtv@usa.net Cc: Jaroslav Kysela perex@perex.cz Cc: Takashi Iwai tiwai@suse.de Cc: alsa-devel@alsa-project.org --- sound/oss/msnd_pinnacle.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 11ff7c5..c23f9f9 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -664,12 +664,15 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static void dsp_write_flush(void) { + int timeout = get_play_delay_jiffies(dev.DAPF.len); + if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags)) return; set_bit(F_WRITEFLUSH, &dev.flags); - interruptible_sleep_on_timeout( - &dev.writeflush, - get_play_delay_jiffies(dev.DAPF.len)); + wait_event_interruptible_timeout( + dev.writeflush, + !test_bit(F_WRITEFLUSH, &dev.flags), + timeout); clear_bit(F_WRITEFLUSH, &dev.flags); if (!signal_pending(current)) { current->state = TASK_INTERRUPTIBLE; @@ -897,6 +900,7 @@ static int dsp_read(char __user *buf, size_t len) { int count = len; char *page = (char *)__get_free_page(GFP_KERNEL); + int timeout = get_rec_delay_jiffies(DAR_BUFF_SIZE);
if (!page) return -ENOMEM; @@ -936,11 +940,11 @@ static int dsp_read(char __user *buf, size_t len)
if (count > 0) { set_bit(F_READBLOCK, &dev.flags); - if (!interruptible_sleep_on_timeout( - &dev.readblock, - get_rec_delay_jiffies(DAR_BUFF_SIZE))) + if (wait_event_interruptible_timeout( + dev.readblock, + test_bit(F_READBLOCK, &dev.flags), + timeout) <= 0) clear_bit(F_READING, &dev.flags); - clear_bit(F_READBLOCK, &dev.flags); if (signal_pending(current)) { free_page((unsigned long)page); return -EINTR; @@ -955,6 +959,7 @@ static int dsp_write(const char __user *buf, size_t len) { int count = len; char *page = (char *)__get_free_page(GFP_KERNEL); + int timeout = get_play_delay_jiffies(DAP_BUFF_SIZE);
if (!page) return -ENOMEM; @@ -995,10 +1000,10 @@ static int dsp_write(const char __user *buf, size_t len)
if (count > 0) { set_bit(F_WRITEBLOCK, &dev.flags); - interruptible_sleep_on_timeout( - &dev.writeblock, - get_play_delay_jiffies(DAP_BUFF_SIZE)); - clear_bit(F_WRITEBLOCK, &dev.flags); + wait_event_interruptible_timeout( + dev.writeblock, + test_bit(F_WRITEBLOCK, &dev.flags), + timeout); if (signal_pending(current)) { free_page((unsigned long)page); return -EINTR; @@ -1044,7 +1049,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage) clear_bit(F_WRITING, &dev.flags); }
- if (test_bit(F_WRITEBLOCK, &dev.flags)) + if (test_and_clear_bit(F_WRITEBLOCK, &dev.flags)) wake_up_interruptible(&dev.writeblock); break;
@@ -1055,7 +1060,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage)
pack_DARQ_to_DARF(dev.last_recbank);
- if (test_bit(F_READBLOCK, &dev.flags)) + if (test_and_clear_bit(F_READBLOCK, &dev.flags)) wake_up_interruptible(&dev.readblock); break;
At Thu, 2 Jan 2014 13:07:47 +0100, Arnd Bergmann wrote:
We want to remove all sleep_on variants from the kernel because they are racy. In case of the pinnacle driver, we can replace interruptible_sleep_on_timeout with wait_event_interruptible_timeout by changing the meaning of a few flags used in the driver so they are cleared at wakeup time, which is a somewhat more appropriate way to do the same, although probably still racy.
Signed-off-by: Arnd Bergmann arnd@arndb.de Cc: Andrew Veliath andrewtv@usa.net Cc: Jaroslav Kysela perex@perex.cz Cc: Takashi Iwai tiwai@suse.de Cc: alsa-devel@alsa-project.org
I applied all 5 patches (23, 25, 24, 26, and 27) for sound/oss/*, some with trivial space fixes. Thanks!
Takashi
sleep_on is known to be racy and going away because of this. All instances of interruptible_sleep_on and interruptible_sleep_on_timeout in the midibuf driver can trivially be replaced with wait_event_interruptible and wait_event_interruptible_timeout.
Signed-off-by: Arnd Bergmann arnd@arndb.de Cc: Jaroslav Kysela perex@perex.cz Cc: Takashi Iwai tiwai@suse.de Cc: alsa-devel@alsa-project.org --- sound/oss/midibuf.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c index 8cdb2cf..79615cf 100644 --- a/sound/oss/midibuf.c +++ b/sound/oss/midibuf.c @@ -86,9 +86,8 @@ static void drain_midi_queue(int dev) */
if (midi_devs[dev]->buffer_status != NULL) - while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev)) - interruptible_sleep_on_timeout(&midi_sleeper[dev], - HZ/10); + wait_event_interruptible_timeout(midi_sleeper[dev], + !midi_devs[dev]->buffer_status(dev), HZ/10); }
static void midi_input_intr(int dev, unsigned char data) @@ -233,8 +232,8 @@ void MIDIbuf_release(int dev, struct file *file) * devices */
- while (!signal_pending(current) && DATA_AVAIL(midi_out_buf[dev])) - interruptible_sleep_on(&midi_sleeper[dev]); + wait_event_interruptible(midi_sleeper[dev], + !DATA_AVAIL(midi_out_buf[dev])); /* * Sync */ @@ -282,8 +281,8 @@ int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count) goto out; }
- interruptible_sleep_on(&midi_sleeper[dev]); - if (signal_pending(current)) + if (wait_event_interruptible(midi_sleeper[dev], + SPACE_AVAIL(midi_out_buf[dev]))) { c = -EINTR; goto out; @@ -325,8 +324,9 @@ int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count) c = -EAGAIN; goto out; } - interruptible_sleep_on_timeout(&input_sleeper[dev], - parms[dev].prech_timeout); + wait_event_interruptible_timeout(input_sleeper[dev], + DATA_AVAIL(midi_in_buf[dev]), + parms[dev].prech_timeout);
if (signal_pending(current)) c = -EINTR; /* The user is getting restless */
Interruptible_sleep_on is racy and we want to remove it. This replaces the use in the vwsnd driver with an open-coded prepare_to_wait loop that fixes the race between concurrent open() and close() calls, and also drops the global mutex while waiting here, which restores the original behavior that was changed during the BKL removal.
Signed-off-by: Arnd Bergmann arnd@arndb.de Cc: Jaroslav Kysela perex@perex.cz Cc: Takashi Iwai tiwai@suse.de Cc: alsa-devel@alsa-project.org --- sound/oss/vwsnd.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 4bbcc0f..a077e9c 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c @@ -2921,6 +2921,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) vwsnd_dev_t *devc; int minor = iminor(inode); int sw_samplefmt; + DEFINE_WAIT(wait);
DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
@@ -2937,21 +2938,26 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) }
mutex_lock(&devc->open_mutex); - while (devc->open_mode & file->f_mode) { + while (1) { + prepare_to_wait(&devc->open_wait, &wait, TASK_INTERRUPTIBLE); + if (!(devc->open_mode & file->f_mode)) + break; + mutex_unlock(&devc->open_mutex); + mutex_unlock(&vwsnd_mutex); if (file->f_flags & O_NONBLOCK) { DEC_USE_COUNT; - mutex_unlock(&vwsnd_mutex); return -EBUSY; } - interruptible_sleep_on(&devc->open_wait); + schedule(); if (signal_pending(current)) { DEC_USE_COUNT; - mutex_unlock(&vwsnd_mutex); return -ERESTARTSYS; } + mutex_lock(&vwsnd_mutex); mutex_lock(&devc->open_mutex); } + finish_wait(&devc->open_wait, &wait); devc->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); mutex_unlock(&devc->open_mutex);
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 Cc: Jaroslav Kysela perex@perex.cz Cc: Takashi Iwai tiwai@suse.de Cc: alsa-devel@alsa-project.org --- sound/oss/dmasound/dmasound.h | 1 - sound/oss/dmasound/dmasound_core.c | 28 +++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h index 1308d8d..01019f0 100644 --- a/sound/oss/dmasound/dmasound.h +++ b/sound/oss/dmasound/dmasound.h @@ -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; diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index bac43b5..f4ee85a 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -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
There are three files in oss for which I could not find an easy way to replace interruptible_sleep_on_timeout with a non-racy version. This patch instead just adds a private implementation of the function, now named oss_broken_sleep_on, and changes over the remaining users in sound/oss/ so we can remove the global interface.
Signed-off-by: Arnd Bergmann arnd@arndb.de Cc: Jaroslav Kysela perex@perex.cz Cc: Takashi Iwai tiwai@suse.de Cc: alsa-devel@alsa-project.org --- sound/oss/dmabuf.c | 14 ++++++-------- sound/oss/sequencer.c | 16 +++++++--------- sound/oss/sleep.h | 18 ++++++++++++++++++ sound/oss/swarm_cs4297a.c | 14 ++++++++------ 4 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 sound/oss/sleep.h
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c index 461d94c..e3f2913 100644 --- a/sound/oss/dmabuf.c +++ b/sound/oss/dmabuf.c @@ -28,6 +28,7 @@ #include <linux/mm.h> #include <linux/gfp.h> #include "sound_config.h" +#include "sleep.h"
#define DMAP_FREE_ON_CLOSE 0 #define DMAP_KEEP_ON_CLOSE 1 @@ -351,8 +352,7 @@ static void dma_reset_output(int dev) if (!signal_pending(current) && adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0){ spin_unlock_irqrestore(&dmap->lock,flags); - interruptible_sleep_on_timeout(&adev->out_sleeper, - dmabuf_timeout(dmap)); + oss_broken_sleep_on(&adev->out_sleeper, dmabuf_timeout(dmap)); spin_lock_irqsave(&dmap->lock,flags); } adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); @@ -446,7 +446,7 @@ int DMAbuf_sync(int dev) long t = dmabuf_timeout(dmap); spin_unlock_irqrestore(&dmap->lock,flags); /* FIXME: not safe may miss events */ - t = interruptible_sleep_on_timeout(&adev->out_sleeper, t); + t = oss_broken_sleep_on(&adev->out_sleeper, t); spin_lock_irqsave(&dmap->lock,flags); if (!t) { adev->dmap_out->flags &= ~DMA_SYNCING; @@ -466,7 +466,7 @@ int DMAbuf_sync(int dev) while (!signal_pending(current) && adev->d->local_qlen(dev)){ spin_unlock_irqrestore(&dmap->lock,flags); - interruptible_sleep_on_timeout(&adev->out_sleeper, + oss_broken_sleep_on(&adev->out_sleeper, dmabuf_timeout(dmap)); spin_lock_irqsave(&dmap->lock,flags); } @@ -587,8 +587,7 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) timeout = dmabuf_timeout(dmap);
spin_unlock_irqrestore(&dmap->lock,flags); - timeout = interruptible_sleep_on_timeout(&adev->in_sleeper, - timeout); + timeout = oss_broken_sleep_on(&adev->in_sleeper, timeout); if (!timeout) { /* FIXME: include device name */ err = -EIO; @@ -768,8 +767,7 @@ static int output_sleep(int dev, int dontblock) timeout_value = dmabuf_timeout(dmap); else timeout_value = MAX_SCHEDULE_TIMEOUT; - timeout_value = interruptible_sleep_on_timeout(&adev->out_sleeper, - timeout_value); + timeout_value = oss_broken_sleep_on(&adev->out_sleeper, timeout_value); if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) { printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); dma_reset_output(dev); diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index 4ff60a6..c855a75 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -19,6 +19,7 @@ #include "sound_config.h"
#include "midi_ctrl.h" +#include "sleep.h"
static int sequencer_ok; static struct sound_timer_operations *tmr; @@ -100,8 +101,7 @@ int sequencer_read(int dev, struct file *file, char __user *buf, int count) return -EAGAIN; }
- interruptible_sleep_on_timeout(&midi_sleeper, - pre_event_timeout); + oss_broken_sleep_on(&midi_sleeper, pre_event_timeout); spin_lock_irqsave(&lock,flags); if (!iqlen) { @@ -343,7 +343,7 @@ static int seq_queue(unsigned char *note, char nonblock) /* * Sleep until there is enough space on the queue */ - interruptible_sleep_on(&seq_sleeper); + oss_broken_sleep_on(&seq_sleeper, MAX_SCHEDULE_TIMEOUT); } if (qlen >= SEQ_MAX_QUEUE) { @@ -1122,8 +1122,7 @@ static void seq_drain_midi_queues(void) */
if (n) - interruptible_sleep_on_timeout(&seq_sleeper, - HZ/10); + oss_broken_sleep_on(&seq_sleeper, HZ/10); } }
@@ -1145,8 +1144,7 @@ void sequencer_release(int dev, struct file *file) while (!signal_pending(current) && qlen > 0) { seq_sync(); - interruptible_sleep_on_timeout(&seq_sleeper, - 3*HZ); + oss_broken_sleep_on(&seq_sleeper, 3*HZ); /* Extra delay */ } } @@ -1201,7 +1199,7 @@ static int seq_sync(void) seq_startplay();
if (qlen > 0) - interruptible_sleep_on_timeout(&seq_sleeper, HZ); + oss_broken_sleep_on(&seq_sleeper, HZ); return qlen; }
@@ -1224,7 +1222,7 @@ static void midi_outc(int dev, unsigned char data)
spin_lock_irqsave(&lock,flags); while (n && !midi_devs[dev]->outputc(dev, data)) { - interruptible_sleep_on_timeout(&seq_sleeper, HZ/25); + oss_broken_sleep_on(&seq_sleeper, HZ/25); n--; } spin_unlock_irqrestore(&lock,flags); diff --git a/sound/oss/sleep.h b/sound/oss/sleep.h new file mode 100644 index 0000000..a20fc92 --- /dev/null +++ b/sound/oss/sleep.h @@ -0,0 +1,18 @@ +#include <linux/wait.h> + +/* + * Do not use. This is a replacement for the old + * "interruptible_sleep_on_timeout" function that has been + * deprecated for ages. All users should instead try to use + * wait_event_interruptible_timeout. + */ + +static inline long +oss_broken_sleep_on(wait_queue_head_t *q, long timeout) +{ + DEFINE_WAIT(wait); + prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE); + timeout = schedule_timeout(timeout); + finish_wait(q, &wait); + return timeout; +} diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index 7d8803a..59defdc 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c @@ -90,6 +90,8 @@ #include <asm/sibyte/sb1250_mac.h> #include <asm/sibyte/sb1250.h>
+#include "sleep.h" + struct cs4297a_state;
static DEFINE_MUTEX(swarm_cs4297a_mutex); @@ -748,7 +750,7 @@ static int serdma_reg_access(struct cs4297a_state *s, u64 data) /* Since a writer has the DSP open, we have to mux the request in */ s->reg_request = data; - interruptible_sleep_on(&s->dma_dac.reg_wait); + oss_broken_sleep_on(&s->dma_dac.reg_wait, MAX_SCHEDULE_TIMEOUT); /* XXXKW how can I deal with the starvation case where the opener isn't writing? */ } else { @@ -790,7 +792,7 @@ static int cs4297a_read_ac97(struct cs4297a_state *s, u32 offset, if (serdma_reg_access(s, (0xCLL << 60) | (1LL << 47) | ((u64)(offset & 0x7F) << 40))) return -1;
- interruptible_sleep_on(&s->dma_adc.reg_wait); + oss_broken_sleep_on(&s->dma_adc.reg_wait, MAX_SCHEDULE_TIMEOUT); *value = s->read_value; CS_DBGOUT(CS_AC97, 2, printk(KERN_INFO "cs4297a: rdr reg %x -> %x\n", s->read_reg, s->read_value)); @@ -1740,7 +1742,7 @@ static ssize_t cs4297a_read(struct file *file, char *buffer, size_t count, start_adc(s); if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_adc.wait); + oss_broken_sleep_on(&s->dma_adc.wait, MAX_SCHEDULE_TIMEOUT); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; @@ -1836,7 +1838,7 @@ static ssize_t cs4297a_write(struct file *file, const char *buffer, start_dac(s); if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; - interruptible_sleep_on(&d->wait); + oss_broken_sleep_on(&d->wait, MAX_SCHEDULE_TIMEOUT); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; @@ -2452,7 +2454,7 @@ static int cs4297a_locked_open(struct inode *inode, struct file *file) return -EBUSY; } mutex_unlock(&s->open_sem_dac); - interruptible_sleep_on(&s->open_wait_dac); + oss_broken_sleep_on(&s->open_wait_dac, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current)) { printk("open - sig pending\n"); @@ -2469,7 +2471,7 @@ static int cs4297a_locked_open(struct inode *inode, struct file *file) return -EBUSY; } mutex_unlock(&s->open_sem_adc); - interruptible_sleep_on(&s->open_wait_adc); + oss_broken_sleep_on(&s->open_wait_adc, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current)) { printk("open - sig pending\n");
participants (2)
-
Arnd Bergmann
-
Takashi Iwai