diff mbox

ALSA: control: Simplify snd_ctl_elem_list() implementation

Message ID 20170522155224.4810-1-tiwai@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

Takashi Iwai May 22, 2017, 3:52 p.m. UTC
This patch simplifies the code of snd_ctl_elem_list() in the following
ways:

- Avoid a vmalloc() temporary buffer but do copy in each iteration;
  the vmalloc buffer was introduced at the time we took the spinlock
  for the ctl element management.

- Use the standard list_for_each_entry() macro

- Merge two loops into one;
  it used to be a loop for skipping until offset becomes zero and
  another loop to copy the data.  They can be folded into a single
  loop easily.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/core/control.c | 66 +++++++++++++++++++---------------------------------
 1 file changed, 24 insertions(+), 42 deletions(-)

Comments

Takashi Sakamoto May 22, 2017, 7:55 p.m. UTC | #1
Hi,

On May 23 2017 00:52, Takashi Iwai wrote:
> This patch simplifies the code of snd_ctl_elem_list() in the following
> ways:
> 
> - Avoid a vmalloc() temporary buffer but do copy in each iteration;
>    the vmalloc buffer was introduced at the time we took the spinlock
>    for the ctl element management.
> 
> - Use the standard list_for_each_entry() macro
> 
> - Merge two loops into one;
>    it used to be a loop for skipping until offset becomes zero and
>    another loop to copy the data.  They can be folded into a single
>    loop easily.
> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>

Reviewed-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Tested-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>

I have one comment.

> ---
>   sound/core/control.c | 66 +++++++++++++++++++---------------------------------
>   1 file changed, 24 insertions(+), 42 deletions(-)
> 
> diff --git a/sound/core/control.c b/sound/core/control.c
> index c109b82eef4b..47080da8451a 100644
> --- a/sound/core/control.c
> +++ b/sound/core/control.c
> @@ -747,11 +747,11 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
>   static int snd_ctl_elem_list(struct snd_card *card,
>   			     struct snd_ctl_elem_list __user *_list)
>   {
> -	struct list_head *plist;
>   	struct snd_ctl_elem_list list;
>   	struct snd_kcontrol *kctl;
> -	struct snd_ctl_elem_id *dst, *id;
> +	struct snd_ctl_elem_id id;
>   	unsigned int offset, space, jidx;
> +	int err = 0;
>   	
>   	if (copy_from_user(&list, _list, sizeof(list)))
>   		return -EFAULT;
> @@ -760,52 +760,34 @@ static int snd_ctl_elem_list(struct snd_card *card,
>   	/* try limit maximum space */
>   	if (space > 16384)
>   		return -ENOMEM;

We can get rid of this limitation because allocation in kernel space is 
not performed anymore.


Regards

Takashi Sakamoto
Takashi Iwai May 22, 2017, 8:04 p.m. UTC | #2
On Mon, 22 May 2017 21:55:02 +0200,
Takashi Sakamoto wrote:
> 
> Hi,
> 
> On May 23 2017 00:52, Takashi Iwai wrote:
> > This patch simplifies the code of snd_ctl_elem_list() in the following
> > ways:
> >
> > - Avoid a vmalloc() temporary buffer but do copy in each iteration;
> >    the vmalloc buffer was introduced at the time we took the spinlock
> >    for the ctl element management.
> >
> > - Use the standard list_for_each_entry() macro
> >
> > - Merge two loops into one;
> >    it used to be a loop for skipping until offset becomes zero and
> >    another loop to copy the data.  They can be folded into a single
> >    loop easily.
> >
> > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> 
> Reviewed-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
> Tested-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
> 
> I have one comment.
> 
> > ---
> >   sound/core/control.c | 66 +++++++++++++++++++---------------------------------
> >   1 file changed, 24 insertions(+), 42 deletions(-)
> >
> > diff --git a/sound/core/control.c b/sound/core/control.c
> > index c109b82eef4b..47080da8451a 100644
> > --- a/sound/core/control.c
> > +++ b/sound/core/control.c
> > @@ -747,11 +747,11 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
> >   static int snd_ctl_elem_list(struct snd_card *card,
> >   			     struct snd_ctl_elem_list __user *_list)
> >   {
> > -	struct list_head *plist;
> >   	struct snd_ctl_elem_list list;
> >   	struct snd_kcontrol *kctl;
> > -	struct snd_ctl_elem_id *dst, *id;
> > +	struct snd_ctl_elem_id id;
> >   	unsigned int offset, space, jidx;
> > +	int err = 0;
> >   	
> >   	if (copy_from_user(&list, _list, sizeof(list)))
> >   		return -EFAULT;
> > @@ -760,52 +760,34 @@ static int snd_ctl_elem_list(struct snd_card *card,
> >   	/* try limit maximum space */
> >   	if (space > 16384)
> >   		return -ENOMEM;
> 
> We can get rid of this limitation because allocation in kernel space
> is not performed anymore.

Yes, likely.


thanks,

Takashi
diff mbox

Patch

diff --git a/sound/core/control.c b/sound/core/control.c
index c109b82eef4b..47080da8451a 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -747,11 +747,11 @@  static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
 static int snd_ctl_elem_list(struct snd_card *card,
 			     struct snd_ctl_elem_list __user *_list)
 {
-	struct list_head *plist;
 	struct snd_ctl_elem_list list;
 	struct snd_kcontrol *kctl;
-	struct snd_ctl_elem_id *dst, *id;
+	struct snd_ctl_elem_id id;
 	unsigned int offset, space, jidx;
+	int err = 0;
 	
 	if (copy_from_user(&list, _list, sizeof(list)))
 		return -EFAULT;
@@ -760,52 +760,34 @@  static int snd_ctl_elem_list(struct snd_card *card,
 	/* try limit maximum space */
 	if (space > 16384)
 		return -ENOMEM;
+	down_read(&card->controls_rwsem);
+	list.count = card->controls_count;
+	list.used = 0;
 	if (space > 0) {
-		/* allocate temporary buffer for atomic operation */
-		dst = vmalloc(space * sizeof(struct snd_ctl_elem_id));
-		if (dst == NULL)
-			return -ENOMEM;
-		down_read(&card->controls_rwsem);
-		list.count = card->controls_count;
-		plist = card->controls.next;
-		while (plist != &card->controls) {
-			if (offset == 0)
-				break;
-			kctl = snd_kcontrol(plist);
-			if (offset < kctl->count)
-				break;
-			offset -= kctl->count;
-			plist = plist->next;
-		}
-		list.used = 0;
-		id = dst;
-		while (space > 0 && plist != &card->controls) {
-			kctl = snd_kcontrol(plist);
-			for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
-				snd_ctl_build_ioff(id, kctl, jidx);
-				id++;
-				space--;
+		list_for_each_entry(kctl, &card->controls, list) {
+			if (offset >= kctl->count) {
+				offset -= kctl->count;
+				continue;
+			}
+			for (jidx = offset; jidx < kctl->count; jidx++) {
+				snd_ctl_build_ioff(&id, kctl, jidx);
+				if (copy_to_user(list.pids + list.used, &id,
+						 sizeof(id))) {
+					err = -EFAULT;
+					goto out;
+				}
 				list.used++;
+				if (!--space)
+					goto out;
 			}
-			plist = plist->next;
 			offset = 0;
 		}
-		up_read(&card->controls_rwsem);
-		if (list.used > 0 &&
-		    copy_to_user(list.pids, dst,
-				 list.used * sizeof(struct snd_ctl_elem_id))) {
-			vfree(dst);
-			return -EFAULT;
-		}
-		vfree(dst);
-	} else {
-		down_read(&card->controls_rwsem);
-		list.count = card->controls_count;
-		up_read(&card->controls_rwsem);
 	}
-	if (copy_to_user(_list, &list, sizeof(list)))
-		return -EFAULT;
-	return 0;
+ out:
+	up_read(&card->controls_rwsem);
+	if (!err && copy_to_user(_list, &list, sizeof(list)))
+		err = -EFAULT;
+	return err;
 }
 
 static bool validate_element_member_dimension(struct snd_ctl_elem_info *info)