ALSA: pcm - Avoid GFP_ATOMIC in snd_pcm_link()
Takashi Iwai [Tue, 13 Mar 2012 14:55:43 +0000 (15:55 +0100)]
GFP_ATOMIC is used in snd_pcm_link() just because the kmalloc is
called inside a lock.  Since this function isn't too critical for
speed and is rarely called in practice, better to allocate the chunk
at first before spinlock and free it in error paths, so that
GFP_KERNEL can be used.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

sound/core/pcm_native.c

index 25ed9fe..3fe99e6 100644 (file)
@@ -1586,12 +1586,18 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
        struct file *file;
        struct snd_pcm_file *pcm_file;
        struct snd_pcm_substream *substream1;
+       struct snd_pcm_group *group;
 
        file = snd_pcm_file_fd(fd);
        if (!file)
                return -EBADFD;
        pcm_file = file->private_data;
        substream1 = pcm_file->substream;
+       group = kmalloc(sizeof(*group), GFP_KERNEL);
+       if (!group) {
+               res = -ENOMEM;
+               goto _nolock;
+       }
        down_write(&snd_pcm_link_rwsem);
        write_lock_irq(&snd_pcm_link_rwlock);
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
@@ -1604,11 +1610,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
                goto _end;
        }
        if (!snd_pcm_stream_linked(substream)) {
-               substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC);
-               if (substream->group == NULL) {
-                       res = -ENOMEM;
-                       goto _end;
-               }
+               substream->group = group;
                spin_lock_init(&substream->group->lock);
                INIT_LIST_HEAD(&substream->group->substreams);
                list_add_tail(&substream->link_list, &substream->group->substreams);
@@ -1620,7 +1622,10 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
  _end:
        write_unlock_irq(&snd_pcm_link_rwlock);
        up_write(&snd_pcm_link_rwsem);
+ _nolock:
        fput(file);
+       if (res < 0)
+               kfree(group);
        return res;
 }