[ALSA] Fix control/status mmap with shared PCM substream
The flag to avoid 32bit-incompatible mmap for control/status records should be outside the pcm substream instance since a substream can be shared among multiple opens. Now it's flagged in pcm_file list that is directly assigned to file->private_data. Also, removed snd_pcm_add_file() and remove_file() functions and substream.files field that are not really used in the code. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
This commit is contained in:
committed by
Jaroslav Kysela
parent
1c39855804
commit
548a648b98
@@ -190,7 +190,7 @@ struct snd_pcm_ops {
|
|||||||
|
|
||||||
struct snd_pcm_file {
|
struct snd_pcm_file {
|
||||||
struct snd_pcm_substream *substream;
|
struct snd_pcm_substream *substream;
|
||||||
struct snd_pcm_file *next;
|
int no_compat_mmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct snd_pcm_hw_rule;
|
struct snd_pcm_hw_rule;
|
||||||
@@ -384,7 +384,6 @@ struct snd_pcm_substream {
|
|||||||
struct snd_info_entry *proc_prealloc_entry;
|
struct snd_info_entry *proc_prealloc_entry;
|
||||||
#endif
|
#endif
|
||||||
/* misc flags */
|
/* misc flags */
|
||||||
unsigned int no_mmap_ctrl: 1;
|
|
||||||
unsigned int hw_opened: 1;
|
unsigned int hw_opened: 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -402,7 +401,6 @@ struct snd_pcm_str {
|
|||||||
/* -- OSS things -- */
|
/* -- OSS things -- */
|
||||||
struct snd_pcm_oss_stream oss;
|
struct snd_pcm_oss_stream oss;
|
||||||
#endif
|
#endif
|
||||||
struct snd_pcm_file *files;
|
|
||||||
#ifdef CONFIG_SND_VERBOSE_PROCFS
|
#ifdef CONFIG_SND_VERBOSE_PROCFS
|
||||||
struct snd_info_entry *proc_root;
|
struct snd_info_entry *proc_root;
|
||||||
struct snd_info_entry *proc_info_entry;
|
struct snd_info_entry *proc_info_entry;
|
||||||
|
@@ -478,7 +478,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
|
|||||||
* mmap of PCM status/control records because of the size
|
* mmap of PCM status/control records because of the size
|
||||||
* incompatibility.
|
* incompatibility.
|
||||||
*/
|
*/
|
||||||
substream->no_mmap_ctrl = 1;
|
pcm_file->no_compat_mmap = 1;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_IOCTL_PVERSION:
|
case SNDRV_PCM_IOCTL_PVERSION:
|
||||||
|
@@ -1992,35 +1992,9 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_pcm_add_file(struct snd_pcm_str *str,
|
|
||||||
struct snd_pcm_file *pcm_file)
|
|
||||||
{
|
|
||||||
pcm_file->next = str->files;
|
|
||||||
str->files = pcm_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void snd_pcm_remove_file(struct snd_pcm_str *str,
|
|
||||||
struct snd_pcm_file *pcm_file)
|
|
||||||
{
|
|
||||||
struct snd_pcm_file * pcm_file1;
|
|
||||||
if (str->files == pcm_file) {
|
|
||||||
str->files = pcm_file->next;
|
|
||||||
} else {
|
|
||||||
pcm_file1 = str->files;
|
|
||||||
while (pcm_file1 && pcm_file1->next != pcm_file)
|
|
||||||
pcm_file1 = pcm_file1->next;
|
|
||||||
if (pcm_file1 != NULL)
|
|
||||||
pcm_file1->next = pcm_file->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pcm_release_private(struct snd_pcm_substream *substream)
|
static void pcm_release_private(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_pcm_file *pcm_file = substream->file;
|
|
||||||
|
|
||||||
snd_pcm_unlink(substream);
|
snd_pcm_unlink(substream);
|
||||||
snd_pcm_remove_file(substream->pstr, pcm_file);
|
|
||||||
kfree(pcm_file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void snd_pcm_release_substream(struct snd_pcm_substream *substream)
|
void snd_pcm_release_substream(struct snd_pcm_substream *substream)
|
||||||
@@ -2060,7 +2034,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
substream->no_mmap_ctrl = 0;
|
|
||||||
err = snd_pcm_hw_constraints_init(substream);
|
err = snd_pcm_hw_constraints_init(substream);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
snd_printd("snd_pcm_hw_constraints_init failed\n");
|
snd_printd("snd_pcm_hw_constraints_init failed\n");
|
||||||
@@ -2105,19 +2078,16 @@ static int snd_pcm_open_file(struct file *file,
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (substream->ref_count > 1)
|
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
|
||||||
pcm_file = substream->file;
|
if (pcm_file == NULL) {
|
||||||
else {
|
snd_pcm_release_substream(substream);
|
||||||
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
|
return -ENOMEM;
|
||||||
if (pcm_file == NULL) {
|
}
|
||||||
snd_pcm_release_substream(substream);
|
pcm_file->substream = substream;
|
||||||
return -ENOMEM;
|
if (substream->ref_count == 1) {
|
||||||
}
|
|
||||||
str = substream->pstr;
|
str = substream->pstr;
|
||||||
substream->file = pcm_file;
|
substream->file = pcm_file;
|
||||||
substream->pcm_release = pcm_release_private;
|
substream->pcm_release = pcm_release_private;
|
||||||
pcm_file->substream = substream;
|
|
||||||
snd_pcm_add_file(str, pcm_file);
|
|
||||||
}
|
}
|
||||||
file->private_data = pcm_file;
|
file->private_data = pcm_file;
|
||||||
*rpcm_file = pcm_file;
|
*rpcm_file = pcm_file;
|
||||||
@@ -2209,6 +2179,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
|
|||||||
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);
|
||||||
snd_pcm_release_substream(substream);
|
snd_pcm_release_substream(substream);
|
||||||
|
kfree(pcm_file);
|
||||||
mutex_unlock(&pcm->open_mutex);
|
mutex_unlock(&pcm->open_mutex);
|
||||||
wake_up(&pcm->open_wait);
|
wake_up(&pcm->open_wait);
|
||||||
module_put(pcm->card->module);
|
module_put(pcm->card->module);
|
||||||
@@ -3270,11 +3241,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
|
|||||||
offset = area->vm_pgoff << PAGE_SHIFT;
|
offset = area->vm_pgoff << PAGE_SHIFT;
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case SNDRV_PCM_MMAP_OFFSET_STATUS:
|
case SNDRV_PCM_MMAP_OFFSET_STATUS:
|
||||||
if (substream->no_mmap_ctrl)
|
if (pcm_file->no_compat_mmap)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
return snd_pcm_mmap_status(substream, file, area);
|
return snd_pcm_mmap_status(substream, file, area);
|
||||||
case SNDRV_PCM_MMAP_OFFSET_CONTROL:
|
case SNDRV_PCM_MMAP_OFFSET_CONTROL:
|
||||||
if (substream->no_mmap_ctrl)
|
if (pcm_file->no_compat_mmap)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
return snd_pcm_mmap_control(substream, file, area);
|
return snd_pcm_mmap_control(substream, file, area);
|
||||||
default:
|
default:
|
||||||
|
Reference in New Issue
Block a user