Commit 9c323fcb authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela

[ALSA] Fix mmap_count with O_APPEND opened streams

Move mmap_count to snd_pcm_substream instead of runtime struct
so that multiplly opened substreams via O_APPEND can be handled
correctly.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 0df63e44
...@@ -300,7 +300,6 @@ struct snd_pcm_runtime { ...@@ -300,7 +300,6 @@ struct snd_pcm_runtime {
/* -- mmap -- */ /* -- mmap -- */
volatile struct snd_pcm_mmap_status *status; volatile struct snd_pcm_mmap_status *status;
volatile struct snd_pcm_mmap_control *control; volatile struct snd_pcm_mmap_control *control;
atomic_t mmap_count;
/* -- locking / scheduling -- */ /* -- locking / scheduling -- */
wait_queue_head_t sleep; wait_queue_head_t sleep;
...@@ -369,6 +368,7 @@ struct snd_pcm_substream { ...@@ -369,6 +368,7 @@ struct snd_pcm_substream {
/* -- assigned files -- */ /* -- assigned files -- */
void *file; void *file;
int ref_count; int ref_count;
atomic_t mmap_count;
unsigned int f_flags; unsigned int f_flags;
void (*pcm_release)(struct snd_pcm_substream *); void (*pcm_release)(struct snd_pcm_substream *);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
...@@ -972,13 +972,13 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne ...@@ -972,13 +972,13 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
{ {
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
atomic_inc(&substream->runtime->mmap_count); atomic_inc(&substream->mmap_count);
} }
static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area) static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
{ {
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
atomic_dec(&substream->runtime->mmap_count); atomic_dec(&substream->mmap_count);
} }
/* mmap for io-memory area */ /* mmap for io-memory area */
......
...@@ -684,7 +684,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, ...@@ -684,7 +684,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
oss_buffer_size = snd_pcm_plug_client_size(substream, oss_buffer_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size; snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
oss_buffer_size = 1 << ld2(oss_buffer_size); oss_buffer_size = 1 << ld2(oss_buffer_size);
if (atomic_read(&runtime->mmap_count)) { if (atomic_read(&substream->mmap_count)) {
if (oss_buffer_size > runtime->oss.mmap_bytes) if (oss_buffer_size > runtime->oss.mmap_bytes)
oss_buffer_size = runtime->oss.mmap_bytes; oss_buffer_size = runtime->oss.mmap_bytes;
} }
...@@ -819,7 +819,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) ...@@ -819,7 +819,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
goto failure; goto failure;
} }
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
direct = 1; direct = 1;
else else
direct = substream->oss.setup.direct; direct = substream->oss.setup.direct;
...@@ -828,7 +828,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) ...@@ -828,7 +828,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
_snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS); _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
_snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0); _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
snd_mask_none(&mask); snd_mask_none(&mask);
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
else { else {
snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED); snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
...@@ -947,7 +947,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) ...@@ -947,7 +947,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
} else { } else {
sw_params->start_threshold = runtime->boundary; sw_params->start_threshold = runtime->boundary;
} }
if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE) if (atomic_read(&substream->mmap_count) ||
substream->stream == SNDRV_PCM_STREAM_CAPTURE)
sw_params->stop_threshold = runtime->boundary; sw_params->stop_threshold = runtime->boundary;
else else
sw_params->stop_threshold = runtime->buffer_size; sw_params->stop_threshold = runtime->buffer_size;
...@@ -957,7 +958,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) ...@@ -957,7 +958,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
1 : runtime->period_size; 1 : runtime->period_size;
sw_params->xfer_align = 1; sw_params->xfer_align = 1;
if (atomic_read(&runtime->mmap_count) || if (atomic_read(&substream->mmap_count) ||
substream->oss.setup.nosilence) { substream->oss.setup.nosilence) {
sw_params->silence_threshold = 0; sw_params->silence_threshold = 0;
sw_params->silence_size = 0; sw_params->silence_size = 0;
...@@ -1301,7 +1302,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha ...@@ -1301,7 +1302,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
ssize_t tmp; ssize_t tmp;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
return -ENXIO; return -ENXIO;
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
...@@ -1391,7 +1392,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use ...@@ -1391,7 +1392,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
ssize_t tmp; ssize_t tmp;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
return -ENXIO; return -ENXIO;
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
...@@ -1521,7 +1522,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) ...@@ -1521,7 +1522,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream != NULL) { if (substream != NULL) {
runtime = substream->runtime; runtime = substream->runtime;
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
goto __direct; goto __direct;
if ((err = snd_pcm_oss_make_ready(substream)) < 0) if ((err = snd_pcm_oss_make_ready(substream)) < 0)
return err; return err;
...@@ -1690,7 +1691,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) ...@@ -1690,7 +1691,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
return err; return err;
if (atomic_read(&substream->runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
direct = 1; direct = 1;
else else
direct = substream->oss.setup.direct; direct = substream->oss.setup.direct;
...@@ -1900,7 +1901,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr ...@@ -1900,7 +1901,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
if (trigger & PCM_ENABLE_OUTPUT) { if (trigger & PCM_ENABLE_OUTPUT) {
if (runtime->oss.trigger) if (runtime->oss.trigger)
goto _skip1; goto _skip1;
if (atomic_read(&psubstream->runtime->mmap_count)) if (atomic_read(&psubstream->mmap_count))
snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
runtime->oss.trigger = 1; runtime->oss.trigger = 1;
runtime->start_threshold = 1; runtime->start_threshold = 1;
...@@ -2018,7 +2019,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream ...@@ -2018,7 +2019,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
if (err < 0) if (err < 0)
return err; return err;
info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
if (atomic_read(&runtime->mmap_count)) { if (atomic_read(&substream->mmap_count)) {
snd_pcm_sframes_t n; snd_pcm_sframes_t n;
n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
if (n < 0) if (n < 0)
...@@ -2574,7 +2575,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size ...@@ -2574,7 +2575,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
else else
return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
...@@ -2583,7 +2584,7 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) ...@@ -2583,7 +2584,7 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
else else
return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
......
...@@ -662,6 +662,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) ...@@ -662,6 +662,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
INIT_LIST_HEAD(&substream->self_group.substreams); INIT_LIST_HEAD(&substream->self_group.substreams);
list_add_tail(&substream->link_list, &substream->self_group.substreams); list_add_tail(&substream->link_list, &substream->self_group.substreams);
spin_lock_init(&substream->timer_lock); spin_lock_init(&substream->timer_lock);
atomic_set(&substream->mmap_count, 0);
prev = substream; prev = substream;
} }
return 0; return 0;
...@@ -884,7 +885,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, ...@@ -884,7 +885,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
memset((void*)runtime->control, 0, size); memset((void*)runtime->control, 0, size);
init_waitqueue_head(&runtime->sleep); init_waitqueue_head(&runtime->sleep);
atomic_set(&runtime->mmap_count, 0);
init_timer(&runtime->tick_timer); init_timer(&runtime->tick_timer);
runtime->tick_timer.function = snd_pcm_tick_timer_func; runtime->tick_timer.function = snd_pcm_tick_timer_func;
runtime->tick_timer.data = (unsigned long) substream; runtime->tick_timer.data = (unsigned long) substream;
......
...@@ -372,7 +372,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -372,7 +372,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
if (!substream->oss.oss) if (!substream->oss.oss)
#endif #endif
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
return -EBADFD; return -EBADFD;
params->rmask = ~0U; params->rmask = ~0U;
...@@ -485,7 +485,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) ...@@ -485,7 +485,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
return -EBADFD; return -EBADFD;
} }
snd_pcm_stream_unlock_irq(substream); snd_pcm_stream_unlock_irq(substream);
if (atomic_read(&runtime->mmap_count)) if (atomic_read(&substream->mmap_count))
return -EBADFD; return -EBADFD;
if (substream->ops->hw_free) if (substream->ops->hw_free)
result = substream->ops->hw_free(substream); result = substream->ops->hw_free(substream);
...@@ -2207,7 +2207,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file) ...@@ -2207,7 +2207,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
pcm_file = file->private_data; pcm_file = file->private_data;
substream = pcm_file->substream; substream = pcm_file->substream;
snd_assert(substream != NULL, return -ENXIO); snd_assert(substream != NULL, return -ENXIO);
snd_assert(!atomic_read(&substream->runtime->mmap_count), ); snd_assert(!atomic_read(&substream->mmap_count), );
pcm = substream->pcm; pcm = substream->pcm;
fasync_helper(-1, file, 0, &substream->runtime->fasync); fasync_helper(-1, file, 0, &substream->runtime->fasync);
mutex_lock(&pcm->open_mutex); mutex_lock(&pcm->open_mutex);
...@@ -3178,7 +3178,7 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, ...@@ -3178,7 +3178,7 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
area->vm_ops = &snd_pcm_vm_ops_data; area->vm_ops = &snd_pcm_vm_ops_data;
area->vm_private_data = substream; area->vm_private_data = substream;
area->vm_flags |= VM_RESERVED; area->vm_flags |= VM_RESERVED;
atomic_inc(&substream->runtime->mmap_count); atomic_inc(&substream->mmap_count);
return 0; return 0;
} }
...@@ -3210,7 +3210,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, ...@@ -3210,7 +3210,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
(substream->runtime->dma_addr + offset) >> PAGE_SHIFT, (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
size, area->vm_page_prot)) size, area->vm_page_prot))
return -EAGAIN; return -EAGAIN;
atomic_inc(&substream->runtime->mmap_count); atomic_inc(&substream->mmap_count);
return 0; return 0;
} }
......
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