* [PATCH 0/2 RFC] control core refactoring @ 2015-04-08 16:55 Takashi Sakamoto 2015-04-08 16:55 ` [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value Takashi Sakamoto ` (2 more replies) 0 siblings, 3 replies; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-08 16:55 UTC (permalink / raw) To: clemens, tiwai; +Cc: alsa-devel This patchset is for refactoring control core code. The first patch is re-send http://mailman.alsa-project.org/pipermail/alsa-devel/2015-February/087700.html The second patch is new. As long as I investigated, the changed code was written in 1999 and its basic design have never been changed. In my opinion, the design is a bit complicated and refactoring it is better to decrease maintaining cost. Takashi Sakamoto (2): ALSA: ctl: evaluate macro instead of numerical value ALSA: ctl: refactoring for read operation sound/core/control.c | 87 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 33 deletions(-) -- 2.1.0 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value 2015-04-08 16:55 [PATCH 0/2 RFC] control core refactoring Takashi Sakamoto @ 2015-04-08 16:55 ` Takashi Sakamoto 2015-04-08 16:55 ` [PATCH 2/2] ALSA: ctl: refactoring for read operation Takashi Sakamoto 2015-04-09 23:42 ` [PATCH 0/2] control core refactoring Takashi Sakamoto 2 siblings, 0 replies; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-08 16:55 UTC (permalink / raw) To: clemens, tiwai; +Cc: alsa-devel SNDRV_CTL_TLV_OP_XXX is defined but not used in core code. Instead, raw numerical value is evaluated. This commit replaces these values to these macros for better looking. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> --- sound/core/control.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 2ab7ee5..de19d56 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1114,7 +1114,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, int change = 0; void *new_data; - if (op_flag > 0) { + if (op_flag == SNDRV_CTL_TLV_OP_WRITE) { if (size > 1024 * 128) /* sane value */ return -EINVAL; @@ -1411,9 +1411,12 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, goto __kctl_end; } vd = &kctl->vd[tlv.numid - kctl->id.numid]; - if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || - (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || - (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { + if ((op_flag == SNDRV_CTL_TLV_OP_READ && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || + (op_flag == SNDRV_CTL_TLV_OP_WRITE && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || + (op_flag == SNDRV_CTL_TLV_OP_CMD && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { err = -ENXIO; goto __kctl_end; } @@ -1430,7 +1433,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, return 0; } } else { - if (op_flag) { + if (op_flag != SNDRV_CTL_ELEM_ACCESS_TLV_READ) { err = -ENXIO; goto __kctl_end; } -- 2.1.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-08 16:55 [PATCH 0/2 RFC] control core refactoring Takashi Sakamoto 2015-04-08 16:55 ` [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value Takashi Sakamoto @ 2015-04-08 16:55 ` Takashi Sakamoto 2015-04-09 5:33 ` Takashi Iwai 2015-04-09 23:42 ` [PATCH 0/2] control core refactoring Takashi Sakamoto 2 siblings, 1 reply; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-08 16:55 UTC (permalink / raw) To: clemens, tiwai; +Cc: alsa-devel snd_ctl_read() has nested loop and complicated condition for return status. This is not better for reading. This commit applies refactoring with two loops. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> --- sound/core/control.c | 74 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index de19d56..6870baf 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1520,58 +1520,76 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset) { struct snd_ctl_file *ctl; - int err = 0; - ssize_t result = 0; + struct snd_ctl_event ev; + struct snd_kctl_event *kev; + wait_queue_t wait; + size_t result; + int err; ctl = file->private_data; if (snd_BUG_ON(!ctl || !ctl->card)) return -ENXIO; if (!ctl->subscribed) return -EBADFD; + + /* The size of given buffer should be larger than at least one event. */ if (count < sizeof(struct snd_ctl_event)) return -EINVAL; + + /* Block till any events were queued. */ spin_lock_irq(&ctl->read_lock); - while (count >= sizeof(struct snd_ctl_event)) { - struct snd_ctl_event ev; - struct snd_kctl_event *kev; - while (list_empty(&ctl->events)) { - wait_queue_t wait; - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { - err = -EAGAIN; - goto __end_lock; - } - init_waitqueue_entry(&wait, current); - add_wait_queue(&ctl->change_sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); + while (list_empty(&ctl->events)) { + if (file->f_flags & O_NONBLOCK) { + spin_unlock_irq(&ctl->read_lock); + return -EAGAIN; + } + + /* The card was disconnected. The queued events are dropped. */ + if (ctl->card->shutdown) { spin_unlock_irq(&ctl->read_lock); - schedule(); - remove_wait_queue(&ctl->change_sleep, &wait); - if (ctl->card->shutdown) - return -ENODEV; - if (signal_pending(current)) - return -ERESTARTSYS; - spin_lock_irq(&ctl->read_lock); + return -ENODEV; } + + + init_waitqueue_entry(&wait, current); + add_wait_queue(&ctl->change_sleep, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&ctl->read_lock); + + schedule(); + + remove_wait_queue(&ctl->change_sleep, &wait); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irq(&ctl->read_lock); + } + + /* Copy events till the buffer filled, or no events are remained. */ + result = 0; + while (count >= sizeof(struct snd_ctl_event)) { + if (list_empty(&ctl->events)) + break; kev = snd_kctl_event(ctl->events.next); + list_del(&kev->list); + ev.type = SNDRV_CTL_EVENT_ELEM; ev.data.elem.mask = kev->mask; ev.data.elem.id = kev->id; - list_del(&kev->list); - spin_unlock_irq(&ctl->read_lock); kfree(kev); if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { err = -EFAULT; - goto __end; + break; } - spin_lock_irq(&ctl->read_lock); + buffer += sizeof(struct snd_ctl_event); count -= sizeof(struct snd_ctl_event); result += sizeof(struct snd_ctl_event); } - __end_lock: + spin_unlock_irq(&ctl->read_lock); - __end: - return result > 0 ? result : err; + return result; } static unsigned int snd_ctl_poll(struct file *file, poll_table * wait) -- 2.1.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-08 16:55 ` [PATCH 2/2] ALSA: ctl: refactoring for read operation Takashi Sakamoto @ 2015-04-09 5:33 ` Takashi Iwai 2015-04-09 7:35 ` Takashi Sakamoto 0 siblings, 1 reply; 15+ messages in thread From: Takashi Iwai @ 2015-04-09 5:33 UTC (permalink / raw) To: Takashi Sakamoto; +Cc: alsa-devel, clemens At Thu, 9 Apr 2015 01:55:08 +0900, Takashi Sakamoto wrote: > > snd_ctl_read() has nested loop and complicated condition for return > status. This is not better for reading. > > This commit applies refactoring with two loops. > > Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> > --- > sound/core/control.c | 74 ++++++++++++++++++++++++++++++++-------------------- > 1 file changed, 46 insertions(+), 28 deletions(-) > > diff --git a/sound/core/control.c b/sound/core/control.c > index de19d56..6870baf 100644 > --- a/sound/core/control.c > +++ b/sound/core/control.c > @@ -1520,58 +1520,76 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, > size_t count, loff_t * offset) > { > struct snd_ctl_file *ctl; > - int err = 0; > - ssize_t result = 0; > + struct snd_ctl_event ev; > + struct snd_kctl_event *kev; > + wait_queue_t wait; > + size_t result; > + int err; > > ctl = file->private_data; > if (snd_BUG_ON(!ctl || !ctl->card)) > return -ENXIO; > if (!ctl->subscribed) > return -EBADFD; > + > + /* The size of given buffer should be larger than at least one event. */ > if (count < sizeof(struct snd_ctl_event)) > return -EINVAL; > + > + /* Block till any events were queued. */ > spin_lock_irq(&ctl->read_lock); > - while (count >= sizeof(struct snd_ctl_event)) { > - struct snd_ctl_event ev; > - struct snd_kctl_event *kev; > - while (list_empty(&ctl->events)) { > - wait_queue_t wait; > - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { > - err = -EAGAIN; > - goto __end_lock; > - } > - init_waitqueue_entry(&wait, current); > - add_wait_queue(&ctl->change_sleep, &wait); > - set_current_state(TASK_INTERRUPTIBLE); > + while (list_empty(&ctl->events)) { > + if (file->f_flags & O_NONBLOCK) { > + spin_unlock_irq(&ctl->read_lock); > + return -EAGAIN; It's better not to spread the unlock call allover the places but just "goto unlock". > + } > + > + /* The card was disconnected. The queued events are dropped. */ > + if (ctl->card->shutdown) { > spin_unlock_irq(&ctl->read_lock); > - schedule(); > - remove_wait_queue(&ctl->change_sleep, &wait); > - if (ctl->card->shutdown) > - return -ENODEV; > - if (signal_pending(current)) > - return -ERESTARTSYS; > - spin_lock_irq(&ctl->read_lock); > + return -ENODEV; > } > + > + > + init_waitqueue_entry(&wait, current); > + add_wait_queue(&ctl->change_sleep, &wait); > + set_current_state(TASK_INTERRUPTIBLE); > + spin_unlock_irq(&ctl->read_lock); > + > + schedule(); > + > + remove_wait_queue(&ctl->change_sleep, &wait); > + > + if (signal_pending(current)) > + return -ERESTARTSYS; > + > + spin_lock_irq(&ctl->read_lock); > + } > + > + /* Copy events till the buffer filled, or no events are remained. */ > + result = 0; > + while (count >= sizeof(struct snd_ctl_event)) { > + if (list_empty(&ctl->events)) > + break; > kev = snd_kctl_event(ctl->events.next); > + list_del(&kev->list); > + > ev.type = SNDRV_CTL_EVENT_ELEM; > ev.data.elem.mask = kev->mask; > ev.data.elem.id = kev->id; > - list_del(&kev->list); > - spin_unlock_irq(&ctl->read_lock); > kfree(kev); > if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { > err = -EFAULT; > - goto __end; > + break; > } > - spin_lock_irq(&ctl->read_lock); > + > buffer += sizeof(struct snd_ctl_event); > count -= sizeof(struct snd_ctl_event); > result += sizeof(struct snd_ctl_event); > } > - __end_lock: > + > spin_unlock_irq(&ctl->read_lock); > - __end: > - return result > 0 ? result : err; > + return result; You can't ignore the error. -EFAULT should be still returned when it happens at the first read. Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-09 5:33 ` Takashi Iwai @ 2015-04-09 7:35 ` Takashi Sakamoto 2015-04-09 8:17 ` Takashi Iwai 0 siblings, 1 reply; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-09 7:35 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, clemens On Apr 09 2015 14:33, Takashi Iwai wrote: > At Thu, 9 Apr 2015 01:55:08 +0900, > Takashi Sakamoto wrote: >> >> snd_ctl_read() has nested loop and complicated condition for return >> status. This is not better for reading. >> >> This commit applies refactoring with two loops. >> >> Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> >> --- >> sound/core/control.c | 74 ++++++++++++++++++++++++++++++++-------------------- >> 1 file changed, 46 insertions(+), 28 deletions(-) >> >> diff --git a/sound/core/control.c b/sound/core/control.c >> index de19d56..6870baf 100644 >> --- a/sound/core/control.c >> +++ b/sound/core/control.c >> @@ -1520,58 +1520,76 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, >> size_t count, loff_t * offset) >> { >> struct snd_ctl_file *ctl; >> - int err = 0; >> - ssize_t result = 0; >> + struct snd_ctl_event ev; >> + struct snd_kctl_event *kev; >> + wait_queue_t wait; >> + size_t result; >> + int err; >> >> ctl = file->private_data; >> if (snd_BUG_ON(!ctl || !ctl->card)) >> return -ENXIO; >> if (!ctl->subscribed) >> return -EBADFD; >> + >> + /* The size of given buffer should be larger than at least one event. */ >> if (count < sizeof(struct snd_ctl_event)) >> return -EINVAL; >> + >> + /* Block till any events were queued. */ >> spin_lock_irq(&ctl->read_lock); >> - while (count >= sizeof(struct snd_ctl_event)) { >> - struct snd_ctl_event ev; >> - struct snd_kctl_event *kev; >> - while (list_empty(&ctl->events)) { >> - wait_queue_t wait; >> - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { >> - err = -EAGAIN; >> - goto __end_lock; >> - } >> - init_waitqueue_entry(&wait, current); >> - add_wait_queue(&ctl->change_sleep, &wait); >> - set_current_state(TASK_INTERRUPTIBLE); >> + while (list_empty(&ctl->events)) { >> + if (file->f_flags & O_NONBLOCK) { >> + spin_unlock_irq(&ctl->read_lock); >> + return -EAGAIN; > > It's better not to spread the unlock call allover the places but just > "goto unlock". > >> + } >> + >> + /* The card was disconnected. The queued events are dropped. */ >> + if (ctl->card->shutdown) { >> spin_unlock_irq(&ctl->read_lock); >> - schedule(); >> - remove_wait_queue(&ctl->change_sleep, &wait); >> - if (ctl->card->shutdown) >> - return -ENODEV; >> - if (signal_pending(current)) >> - return -ERESTARTSYS; >> - spin_lock_irq(&ctl->read_lock); >> + return -ENODEV; >> } >> + >> + >> + init_waitqueue_entry(&wait, current); >> + add_wait_queue(&ctl->change_sleep, &wait); >> + set_current_state(TASK_INTERRUPTIBLE); >> + spin_unlock_irq(&ctl->read_lock); >> + >> + schedule(); >> + >> + remove_wait_queue(&ctl->change_sleep, &wait); >> + >> + if (signal_pending(current)) >> + return -ERESTARTSYS; >> + >> + spin_lock_irq(&ctl->read_lock); >> + } >> + >> + /* Copy events till the buffer filled, or no events are remained. */ >> + result = 0; >> + while (count >= sizeof(struct snd_ctl_event)) { >> + if (list_empty(&ctl->events)) >> + break; >> kev = snd_kctl_event(ctl->events.next); >> + list_del(&kev->list); >> + >> ev.type = SNDRV_CTL_EVENT_ELEM; >> ev.data.elem.mask = kev->mask; >> ev.data.elem.id = kev->id; >> - list_del(&kev->list); >> - spin_unlock_irq(&ctl->read_lock); >> kfree(kev); >> if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { >> err = -EFAULT; >> - goto __end; >> + break; >> } >> - spin_lock_irq(&ctl->read_lock); >> + >> buffer += sizeof(struct snd_ctl_event); >> count -= sizeof(struct snd_ctl_event); >> result += sizeof(struct snd_ctl_event); >> } >> - __end_lock: >> + >> spin_unlock_irq(&ctl->read_lock); >> - __end: >> - return result > 0 ? result : err; >> + return result; > > You can't ignore the error. -EFAULT should be still returned when it > happens at the first read. Exactly. It's my fault. I should have assign it to result, instead of err. Well, I'd like to post revised version, but it's just before a week to open merge window for Linux 4.01. Should I postpone the posting a few weeks later? Thanks. Takashi Sakamoto ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-09 7:35 ` Takashi Sakamoto @ 2015-04-09 8:17 ` Takashi Iwai 0 siblings, 0 replies; 15+ messages in thread From: Takashi Iwai @ 2015-04-09 8:17 UTC (permalink / raw) To: Takashi Sakamoto; +Cc: alsa-devel, clemens At Thu, 09 Apr 2015 16:35:06 +0900, Takashi Sakamoto wrote: > > On Apr 09 2015 14:33, Takashi Iwai wrote: > > At Thu, 9 Apr 2015 01:55:08 +0900, > > Takashi Sakamoto wrote: > >> > >> snd_ctl_read() has nested loop and complicated condition for return > >> status. This is not better for reading. > >> > >> This commit applies refactoring with two loops. > >> > >> Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> > >> --- > >> sound/core/control.c | 74 ++++++++++++++++++++++++++++++++-------------------- > >> 1 file changed, 46 insertions(+), 28 deletions(-) > >> > >> diff --git a/sound/core/control.c b/sound/core/control.c > >> index de19d56..6870baf 100644 > >> --- a/sound/core/control.c > >> +++ b/sound/core/control.c > >> @@ -1520,58 +1520,76 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, > >> size_t count, loff_t * offset) > >> { > >> struct snd_ctl_file *ctl; > >> - int err = 0; > >> - ssize_t result = 0; > >> + struct snd_ctl_event ev; > >> + struct snd_kctl_event *kev; > >> + wait_queue_t wait; > >> + size_t result; > >> + int err; > >> > >> ctl = file->private_data; > >> if (snd_BUG_ON(!ctl || !ctl->card)) > >> return -ENXIO; > >> if (!ctl->subscribed) > >> return -EBADFD; > >> + > >> + /* The size of given buffer should be larger than at least one event. */ > >> if (count < sizeof(struct snd_ctl_event)) > >> return -EINVAL; > >> + > >> + /* Block till any events were queued. */ > >> spin_lock_irq(&ctl->read_lock); > >> - while (count >= sizeof(struct snd_ctl_event)) { > >> - struct snd_ctl_event ev; > >> - struct snd_kctl_event *kev; > >> - while (list_empty(&ctl->events)) { > >> - wait_queue_t wait; > >> - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { > >> - err = -EAGAIN; > >> - goto __end_lock; > >> - } > >> - init_waitqueue_entry(&wait, current); > >> - add_wait_queue(&ctl->change_sleep, &wait); > >> - set_current_state(TASK_INTERRUPTIBLE); > >> + while (list_empty(&ctl->events)) { > >> + if (file->f_flags & O_NONBLOCK) { > >> + spin_unlock_irq(&ctl->read_lock); > >> + return -EAGAIN; > > > > It's better not to spread the unlock call allover the places but just > > "goto unlock". > > > >> + } > >> + > >> + /* The card was disconnected. The queued events are dropped. */ > >> + if (ctl->card->shutdown) { > >> spin_unlock_irq(&ctl->read_lock); > >> - schedule(); > >> - remove_wait_queue(&ctl->change_sleep, &wait); > >> - if (ctl->card->shutdown) > >> - return -ENODEV; > >> - if (signal_pending(current)) > >> - return -ERESTARTSYS; > >> - spin_lock_irq(&ctl->read_lock); > >> + return -ENODEV; > >> } > >> + > >> + > >> + init_waitqueue_entry(&wait, current); > >> + add_wait_queue(&ctl->change_sleep, &wait); > >> + set_current_state(TASK_INTERRUPTIBLE); > >> + spin_unlock_irq(&ctl->read_lock); > >> + > >> + schedule(); > >> + > >> + remove_wait_queue(&ctl->change_sleep, &wait); > >> + > >> + if (signal_pending(current)) > >> + return -ERESTARTSYS; > >> + > >> + spin_lock_irq(&ctl->read_lock); > >> + } > >> + > >> + /* Copy events till the buffer filled, or no events are remained. */ > >> + result = 0; > >> + while (count >= sizeof(struct snd_ctl_event)) { > >> + if (list_empty(&ctl->events)) > >> + break; > >> kev = snd_kctl_event(ctl->events.next); > >> + list_del(&kev->list); > >> + > >> ev.type = SNDRV_CTL_EVENT_ELEM; > >> ev.data.elem.mask = kev->mask; > >> ev.data.elem.id = kev->id; > >> - list_del(&kev->list); > >> - spin_unlock_irq(&ctl->read_lock); > >> kfree(kev); > >> if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { > >> err = -EFAULT; > >> - goto __end; > >> + break; > >> } > >> - spin_lock_irq(&ctl->read_lock); > >> + > >> buffer += sizeof(struct snd_ctl_event); > >> count -= sizeof(struct snd_ctl_event); > >> result += sizeof(struct snd_ctl_event); > >> } > >> - __end_lock: > >> + > >> spin_unlock_irq(&ctl->read_lock); > >> - __end: > >> - return result > 0 ? result : err; > >> + return result; > > > > You can't ignore the error. -EFAULT should be still returned when it > > happens at the first read. > > Exactly. It's my fault. I should have assign it to result, instead of err. > > Well, I'd like to post revised version, but it's just before a week to > open merge window for Linux 4.01. Should I postpone the posting a few > weeks later? These two patches are fine to take now as they are no intrusive changes. thanks, Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 0/2] control core refactoring 2015-04-08 16:55 [PATCH 0/2 RFC] control core refactoring Takashi Sakamoto 2015-04-08 16:55 ` [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value Takashi Sakamoto 2015-04-08 16:55 ` [PATCH 2/2] ALSA: ctl: refactoring for read operation Takashi Sakamoto @ 2015-04-09 23:42 ` Takashi Sakamoto 2015-04-09 23:43 ` [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value Takashi Sakamoto 2015-04-09 23:43 ` [PATCH 2/2] ALSA: ctl: refactoring for read operation Takashi Sakamoto 2 siblings, 2 replies; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-09 23:42 UTC (permalink / raw) To: clemens, tiwai; +Cc: alsa-devel This patchset is revised version of my previous one. [alsa-devel] [PATCH 0/2 RFC] control core refactoring http://mailman.alsa-project.org/pipermail/alsa-devel/2015-April/090202.html Changes: - 1/2 patch: * nothing - 2/2 patch: * use ssize_t instead of size_t as original code uses. * use goto statement to gather unlocking codes in the end of the function. Takashi Sakamoto (2): ALSA: ctl: evaluate macro instead of numerical value ALSA: ctl: refactoring for read operation sound/core/control.c | 90 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 35 deletions(-) -- 2.1.0 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value 2015-04-09 23:42 ` [PATCH 0/2] control core refactoring Takashi Sakamoto @ 2015-04-09 23:43 ` Takashi Sakamoto 2015-04-10 7:49 ` Takashi Iwai 2015-04-09 23:43 ` [PATCH 2/2] ALSA: ctl: refactoring for read operation Takashi Sakamoto 1 sibling, 1 reply; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-09 23:43 UTC (permalink / raw) To: clemens, tiwai; +Cc: alsa-devel SNDRV_CTL_TLV_OP_XXX is defined but not used in core code. Instead, raw numerical value is evaluated. This commit replaces these values to these macros for better looking. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> --- sound/core/control.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 2ab7ee5..de19d56 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1114,7 +1114,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, int change = 0; void *new_data; - if (op_flag > 0) { + if (op_flag == SNDRV_CTL_TLV_OP_WRITE) { if (size > 1024 * 128) /* sane value */ return -EINVAL; @@ -1411,9 +1411,12 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, goto __kctl_end; } vd = &kctl->vd[tlv.numid - kctl->id.numid]; - if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || - (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || - (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { + if ((op_flag == SNDRV_CTL_TLV_OP_READ && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || + (op_flag == SNDRV_CTL_TLV_OP_WRITE && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || + (op_flag == SNDRV_CTL_TLV_OP_CMD && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { err = -ENXIO; goto __kctl_end; } @@ -1430,7 +1433,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, return 0; } } else { - if (op_flag) { + if (op_flag != SNDRV_CTL_ELEM_ACCESS_TLV_READ) { err = -ENXIO; goto __kctl_end; } -- 2.1.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value 2015-04-09 23:43 ` [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value Takashi Sakamoto @ 2015-04-10 7:49 ` Takashi Iwai 2015-04-12 7:20 ` Takashi Iwai 0 siblings, 1 reply; 15+ messages in thread From: Takashi Iwai @ 2015-04-10 7:49 UTC (permalink / raw) To: Takashi Sakamoto; +Cc: alsa-devel, clemens At Fri, 10 Apr 2015 08:43:00 +0900, Takashi Sakamoto wrote: > > SNDRV_CTL_TLV_OP_XXX is defined but not used in core code. Instead, > raw numerical value is evaluated. > > This commit replaces these values to these macros for better looking. > > Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Applied, thanks. Takashi > --- > sound/core/control.c | 13 ++++++++----- > 1 file changed, 8 insertions(+), 5 deletions(-) > > diff --git a/sound/core/control.c b/sound/core/control.c > index 2ab7ee5..de19d56 100644 > --- a/sound/core/control.c > +++ b/sound/core/control.c > @@ -1114,7 +1114,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, > int change = 0; > void *new_data; > > - if (op_flag > 0) { > + if (op_flag == SNDRV_CTL_TLV_OP_WRITE) { > if (size > 1024 * 128) /* sane value */ > return -EINVAL; > > @@ -1411,9 +1411,12 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, > goto __kctl_end; > } > vd = &kctl->vd[tlv.numid - kctl->id.numid]; > - if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || > - (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || > - (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { > + if ((op_flag == SNDRV_CTL_TLV_OP_READ && > + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || > + (op_flag == SNDRV_CTL_TLV_OP_WRITE && > + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || > + (op_flag == SNDRV_CTL_TLV_OP_CMD && > + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { > err = -ENXIO; > goto __kctl_end; > } > @@ -1430,7 +1433,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, > return 0; > } > } else { > - if (op_flag) { > + if (op_flag != SNDRV_CTL_ELEM_ACCESS_TLV_READ) { > err = -ENXIO; > goto __kctl_end; > } > -- > 2.1.0 > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value 2015-04-10 7:49 ` Takashi Iwai @ 2015-04-12 7:20 ` Takashi Iwai 0 siblings, 0 replies; 15+ messages in thread From: Takashi Iwai @ 2015-04-12 7:20 UTC (permalink / raw) To: Takashi Sakamoto; +Cc: alsa-devel, clemens At Fri, 10 Apr 2015 09:49:48 +0200, Takashi Iwai wrote: > > At Fri, 10 Apr 2015 08:43:00 +0900, > Takashi Sakamoto wrote: > > @@ -1430,7 +1433,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, > > return 0; > > } > > } else { > > - if (op_flag) { > > + if (op_flag != SNDRV_CTL_ELEM_ACCESS_TLV_READ) { Grrr, this must be SNDRV_CTL_TLV_OP_READ. Fixed by the patch below. Takashi -- 8< -- From: Takashi Iwai <tiwai@suse.de> Subject: [PATCH] ALSA: control: Fix a typo of SNDRV_CTL_ELEM_ACCESS_TLV_* with SNDRV_CTL_TLV_OP_* The commit [39d118677baa: ALSA: ctl: evaluate macro instead of numerical value] replaced the numbers with constants, but one place was replaced wrongly with a different type. Fixed now. Fixes: 39d118677baa ('ALSA: ctl: evaluate macro instead of numerical value') Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/control.c b/sound/core/control.c index ccb1ca26a71e..be5b97cd8dc3 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1432,7 +1432,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, return 0; } } else { - if (op_flag != SNDRV_CTL_ELEM_ACCESS_TLV_READ) { + if (op_flag != SNDRV_CTL_TLV_OP_READ) { err = -ENXIO; goto __kctl_end; } -- 2.3.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-09 23:42 ` [PATCH 0/2] control core refactoring Takashi Sakamoto 2015-04-09 23:43 ` [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value Takashi Sakamoto @ 2015-04-09 23:43 ` Takashi Sakamoto 2015-04-10 7:48 ` Takashi Iwai 1 sibling, 1 reply; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-09 23:43 UTC (permalink / raw) To: clemens, tiwai; +Cc: alsa-devel snd_ctl_read() has nested loop and complicated condition for return value. This is not better for reading. This commit applies refactoring with two loops. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> --- sound/core/control.c | 77 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index de19d56..da6497d 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1520,58 +1520,75 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset) { struct snd_ctl_file *ctl; - int err = 0; - ssize_t result = 0; + struct snd_ctl_event ev; + struct snd_kctl_event *kev; + wait_queue_t wait; + ssize_t result; ctl = file->private_data; if (snd_BUG_ON(!ctl || !ctl->card)) return -ENXIO; if (!ctl->subscribed) return -EBADFD; + + /* The size of given buffer should be larger than at least one event. */ if (count < sizeof(struct snd_ctl_event)) return -EINVAL; + + /* Block till any events were queued. */ spin_lock_irq(&ctl->read_lock); - while (count >= sizeof(struct snd_ctl_event)) { - struct snd_ctl_event ev; - struct snd_kctl_event *kev; - while (list_empty(&ctl->events)) { - wait_queue_t wait; - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { - err = -EAGAIN; - goto __end_lock; - } - init_waitqueue_entry(&wait, current); - add_wait_queue(&ctl->change_sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&ctl->read_lock); - schedule(); - remove_wait_queue(&ctl->change_sleep, &wait); - if (ctl->card->shutdown) - return -ENODEV; - if (signal_pending(current)) - return -ERESTARTSYS; - spin_lock_irq(&ctl->read_lock); + while (list_empty(&ctl->events)) { + if (file->f_flags & O_NONBLOCK) { + result = -EAGAIN; + goto unlock; } + + /* The card was disconnected. The queued events are dropped. */ + if (ctl->card->shutdown) { + result = -ENODEV; + goto unlock; + } + + + init_waitqueue_entry(&wait, current); + add_wait_queue(&ctl->change_sleep, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&ctl->read_lock); + + schedule(); + + remove_wait_queue(&ctl->change_sleep, &wait); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irq(&ctl->read_lock); + } + + /* Copy events till the buffer filled, or no events are remained. */ + result = 0; + while (count >= sizeof(struct snd_ctl_event)) { + if (list_empty(&ctl->events)) + break; kev = snd_kctl_event(ctl->events.next); + list_del(&kev->list); + ev.type = SNDRV_CTL_EVENT_ELEM; ev.data.elem.mask = kev->mask; ev.data.elem.id = kev->id; - list_del(&kev->list); - spin_unlock_irq(&ctl->read_lock); kfree(kev); if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { - err = -EFAULT; - goto __end; + result = -EFAULT; + break; } - spin_lock_irq(&ctl->read_lock); + buffer += sizeof(struct snd_ctl_event); count -= sizeof(struct snd_ctl_event); result += sizeof(struct snd_ctl_event); } - __end_lock: +unlock: spin_unlock_irq(&ctl->read_lock); - __end: - return result > 0 ? result : err; + return result; } static unsigned int snd_ctl_poll(struct file *file, poll_table * wait) -- 2.1.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-09 23:43 ` [PATCH 2/2] ALSA: ctl: refactoring for read operation Takashi Sakamoto @ 2015-04-10 7:48 ` Takashi Iwai 2015-04-10 10:32 ` Takashi Sakamoto 0 siblings, 1 reply; 15+ messages in thread From: Takashi Iwai @ 2015-04-10 7:48 UTC (permalink / raw) To: Takashi Sakamoto; +Cc: alsa-devel, clemens At Fri, 10 Apr 2015 08:43:01 +0900, Takashi Sakamoto wrote: > > snd_ctl_read() has nested loop and complicated condition for return > value. This is not better for reading. > > This commit applies refactoring with two loops. > > Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> > --- > sound/core/control.c | 77 ++++++++++++++++++++++++++++++++-------------------- > 1 file changed, 47 insertions(+), 30 deletions(-) > > diff --git a/sound/core/control.c b/sound/core/control.c > index de19d56..da6497d 100644 > --- a/sound/core/control.c > +++ b/sound/core/control.c > @@ -1520,58 +1520,75 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, > size_t count, loff_t * offset) > { > struct snd_ctl_file *ctl; > - int err = 0; > - ssize_t result = 0; > + struct snd_ctl_event ev; > + struct snd_kctl_event *kev; > + wait_queue_t wait; > + ssize_t result; > > ctl = file->private_data; > if (snd_BUG_ON(!ctl || !ctl->card)) > return -ENXIO; > if (!ctl->subscribed) > return -EBADFD; > + > + /* The size of given buffer should be larger than at least one event. */ > if (count < sizeof(struct snd_ctl_event)) > return -EINVAL; > + > + /* Block till any events were queued. */ > spin_lock_irq(&ctl->read_lock); > - while (count >= sizeof(struct snd_ctl_event)) { > - struct snd_ctl_event ev; > - struct snd_kctl_event *kev; > - while (list_empty(&ctl->events)) { > - wait_queue_t wait; > - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { > - err = -EAGAIN; > - goto __end_lock; > - } > - init_waitqueue_entry(&wait, current); > - add_wait_queue(&ctl->change_sleep, &wait); > - set_current_state(TASK_INTERRUPTIBLE); > - spin_unlock_irq(&ctl->read_lock); > - schedule(); > - remove_wait_queue(&ctl->change_sleep, &wait); > - if (ctl->card->shutdown) > - return -ENODEV; > - if (signal_pending(current)) > - return -ERESTARTSYS; > - spin_lock_irq(&ctl->read_lock); > + while (list_empty(&ctl->events)) { > + if (file->f_flags & O_NONBLOCK) { > + result = -EAGAIN; > + goto unlock; > } > + > + /* The card was disconnected. The queued events are dropped. */ > + if (ctl->card->shutdown) { > + result = -ENODEV; > + goto unlock; > + } > + > + > + init_waitqueue_entry(&wait, current); > + add_wait_queue(&ctl->change_sleep, &wait); > + set_current_state(TASK_INTERRUPTIBLE); > + spin_unlock_irq(&ctl->read_lock); > + > + schedule(); > + > + remove_wait_queue(&ctl->change_sleep, &wait); > + > + if (signal_pending(current)) > + return -ERESTARTSYS; > + > + spin_lock_irq(&ctl->read_lock); > + } > + > + /* Copy events till the buffer filled, or no events are remained. */ > + result = 0; > + while (count >= sizeof(struct snd_ctl_event)) { > + if (list_empty(&ctl->events)) > + break; > kev = snd_kctl_event(ctl->events.next); > + list_del(&kev->list); > + > ev.type = SNDRV_CTL_EVENT_ELEM; > ev.data.elem.mask = kev->mask; > ev.data.elem.id = kev->id; > - list_del(&kev->list); > - spin_unlock_irq(&ctl->read_lock); > kfree(kev); > if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { > - err = -EFAULT; > - goto __end; > + result = -EFAULT; > + break; This still changes the behavior. The read returns the size that has been read at first even when an error happens if some data was already read. The error code is returned at the next read. This is a design problem of read syscall. Takashi > } > - spin_lock_irq(&ctl->read_lock); > + > buffer += sizeof(struct snd_ctl_event); > count -= sizeof(struct snd_ctl_event); > result += sizeof(struct snd_ctl_event); > } > - __end_lock: > +unlock: > spin_unlock_irq(&ctl->read_lock); > - __end: > - return result > 0 ? result : err; > + return result; > } > > static unsigned int snd_ctl_poll(struct file *file, poll_table * wait) > -- > 2.1.0 > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-10 7:48 ` Takashi Iwai @ 2015-04-10 10:32 ` Takashi Sakamoto 2015-04-10 10:43 ` Takashi Iwai 0 siblings, 1 reply; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-10 10:32 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, clemens On Apr 10 2015 16:48, Takashi Iwai wrote: > At Fri, 10 Apr 2015 08:43:01 +0900, > Takashi Sakamoto wrote: >> >> snd_ctl_read() has nested loop and complicated condition for return >> value. This is not better for reading. >> >> This commit applies refactoring with two loops. >> >> Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> >> --- >> sound/core/control.c | 77 ++++++++++++++++++++++++++++++++-------------------- >> 1 file changed, 47 insertions(+), 30 deletions(-) >> >> diff --git a/sound/core/control.c b/sound/core/control.c >> index de19d56..da6497d 100644 >> --- a/sound/core/control.c >> +++ b/sound/core/control.c >> @@ -1520,58 +1520,75 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, >> size_t count, loff_t * offset) >> { >> struct snd_ctl_file *ctl; >> - int err = 0; >> - ssize_t result = 0; >> + struct snd_ctl_event ev; >> + struct snd_kctl_event *kev; >> + wait_queue_t wait; >> + ssize_t result; >> >> ctl = file->private_data; >> if (snd_BUG_ON(!ctl || !ctl->card)) >> return -ENXIO; >> if (!ctl->subscribed) >> return -EBADFD; >> + >> + /* The size of given buffer should be larger than at least one event. */ >> if (count < sizeof(struct snd_ctl_event)) >> return -EINVAL; >> + >> + /* Block till any events were queued. */ >> spin_lock_irq(&ctl->read_lock); >> - while (count >= sizeof(struct snd_ctl_event)) { >> - struct snd_ctl_event ev; >> - struct snd_kctl_event *kev; >> - while (list_empty(&ctl->events)) { >> - wait_queue_t wait; >> - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { >> - err = -EAGAIN; >> - goto __end_lock; >> - } >> - init_waitqueue_entry(&wait, current); >> - add_wait_queue(&ctl->change_sleep, &wait); >> - set_current_state(TASK_INTERRUPTIBLE); >> - spin_unlock_irq(&ctl->read_lock); >> - schedule(); >> - remove_wait_queue(&ctl->change_sleep, &wait); >> - if (ctl->card->shutdown) >> - return -ENODEV; >> - if (signal_pending(current)) >> - return -ERESTARTSYS; >> - spin_lock_irq(&ctl->read_lock); >> + while (list_empty(&ctl->events)) { >> + if (file->f_flags & O_NONBLOCK) { >> + result = -EAGAIN; >> + goto unlock; >> } >> + >> + /* The card was disconnected. The queued events are dropped. */ >> + if (ctl->card->shutdown) { >> + result = -ENODEV; >> + goto unlock; >> + } >> + >> + >> + init_waitqueue_entry(&wait, current); >> + add_wait_queue(&ctl->change_sleep, &wait); >> + set_current_state(TASK_INTERRUPTIBLE); >> + spin_unlock_irq(&ctl->read_lock); >> + >> + schedule(); >> + >> + remove_wait_queue(&ctl->change_sleep, &wait); >> + >> + if (signal_pending(current)) >> + return -ERESTARTSYS; >> + >> + spin_lock_irq(&ctl->read_lock); >> + } >> + >> + /* Copy events till the buffer filled, or no events are remained. */ >> + result = 0; >> + while (count >= sizeof(struct snd_ctl_event)) { >> + if (list_empty(&ctl->events)) >> + break; >> kev = snd_kctl_event(ctl->events.next); >> + list_del(&kev->list); >> + >> ev.type = SNDRV_CTL_EVENT_ELEM; >> ev.data.elem.mask = kev->mask; >> ev.data.elem.id = kev->id; >> - list_del(&kev->list); >> - spin_unlock_irq(&ctl->read_lock); >> kfree(kev); >> if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { >> - err = -EFAULT; >> - goto __end; >> + result = -EFAULT; >> + break; > > This still changes the behavior. The read returns the size that has > been read at first even when an error happens if some data was already > read. The error code is returned at the next read. This is a design > problem of read syscall. I'm unaware of it... These code should be: if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { if (result == 0) result = -EFAULT; break; And I realize sound/firewire/fireworks/fireworks_hwdep.c has the same bug. I'll post another patch for this bug. Thanks Takashi Sakamoto > Takashi > >> } >> - spin_lock_irq(&ctl->read_lock); >> + >> buffer += sizeof(struct snd_ctl_event); >> count -= sizeof(struct snd_ctl_event); >> result += sizeof(struct snd_ctl_event); >> } >> - __end_lock: >> +unlock: >> spin_unlock_irq(&ctl->read_lock); >> - __end: >> - return result > 0 ? result : err; >> + return result; >> } >> >> static unsigned int snd_ctl_poll(struct file *file, poll_table * wait) >> -- >> 2.1.0 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-10 10:32 ` Takashi Sakamoto @ 2015-04-10 10:43 ` Takashi Iwai 2015-04-10 10:52 ` Takashi Sakamoto 0 siblings, 1 reply; 15+ messages in thread From: Takashi Iwai @ 2015-04-10 10:43 UTC (permalink / raw) To: Takashi Sakamoto; +Cc: alsa-devel, clemens At Fri, 10 Apr 2015 19:32:58 +0900, Takashi Sakamoto wrote: > > On Apr 10 2015 16:48, Takashi Iwai wrote: > > At Fri, 10 Apr 2015 08:43:01 +0900, > > Takashi Sakamoto wrote: > >> > >> snd_ctl_read() has nested loop and complicated condition for return > >> value. This is not better for reading. > >> > >> This commit applies refactoring with two loops. > >> > >> Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> > >> --- > >> sound/core/control.c | 77 ++++++++++++++++++++++++++++++++-------------------- > >> 1 file changed, 47 insertions(+), 30 deletions(-) > >> > >> diff --git a/sound/core/control.c b/sound/core/control.c > >> index de19d56..da6497d 100644 > >> --- a/sound/core/control.c > >> +++ b/sound/core/control.c > >> @@ -1520,58 +1520,75 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, > >> size_t count, loff_t * offset) > >> { > >> struct snd_ctl_file *ctl; > >> - int err = 0; > >> - ssize_t result = 0; > >> + struct snd_ctl_event ev; > >> + struct snd_kctl_event *kev; > >> + wait_queue_t wait; > >> + ssize_t result; > >> > >> ctl = file->private_data; > >> if (snd_BUG_ON(!ctl || !ctl->card)) > >> return -ENXIO; > >> if (!ctl->subscribed) > >> return -EBADFD; > >> + > >> + /* The size of given buffer should be larger than at least one event. */ > >> if (count < sizeof(struct snd_ctl_event)) > >> return -EINVAL; > >> + > >> + /* Block till any events were queued. */ > >> spin_lock_irq(&ctl->read_lock); > >> - while (count >= sizeof(struct snd_ctl_event)) { > >> - struct snd_ctl_event ev; > >> - struct snd_kctl_event *kev; > >> - while (list_empty(&ctl->events)) { > >> - wait_queue_t wait; > >> - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { > >> - err = -EAGAIN; > >> - goto __end_lock; > >> - } > >> - init_waitqueue_entry(&wait, current); > >> - add_wait_queue(&ctl->change_sleep, &wait); > >> - set_current_state(TASK_INTERRUPTIBLE); > >> - spin_unlock_irq(&ctl->read_lock); > >> - schedule(); > >> - remove_wait_queue(&ctl->change_sleep, &wait); > >> - if (ctl->card->shutdown) > >> - return -ENODEV; > >> - if (signal_pending(current)) > >> - return -ERESTARTSYS; > >> - spin_lock_irq(&ctl->read_lock); > >> + while (list_empty(&ctl->events)) { > >> + if (file->f_flags & O_NONBLOCK) { > >> + result = -EAGAIN; > >> + goto unlock; > >> } > >> + > >> + /* The card was disconnected. The queued events are dropped. */ > >> + if (ctl->card->shutdown) { > >> + result = -ENODEV; > >> + goto unlock; > >> + } > >> + > >> + > >> + init_waitqueue_entry(&wait, current); > >> + add_wait_queue(&ctl->change_sleep, &wait); > >> + set_current_state(TASK_INTERRUPTIBLE); > >> + spin_unlock_irq(&ctl->read_lock); > >> + > >> + schedule(); > >> + > >> + remove_wait_queue(&ctl->change_sleep, &wait); > >> + > >> + if (signal_pending(current)) > >> + return -ERESTARTSYS; > >> + > >> + spin_lock_irq(&ctl->read_lock); > >> + } > >> + > >> + /* Copy events till the buffer filled, or no events are remained. */ > >> + result = 0; > >> + while (count >= sizeof(struct snd_ctl_event)) { > >> + if (list_empty(&ctl->events)) > >> + break; > >> kev = snd_kctl_event(ctl->events.next); > >> + list_del(&kev->list); > >> + > >> ev.type = SNDRV_CTL_EVENT_ELEM; > >> ev.data.elem.mask = kev->mask; > >> ev.data.elem.id = kev->id; > >> - list_del(&kev->list); > >> - spin_unlock_irq(&ctl->read_lock); > >> kfree(kev); > >> if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { > >> - err = -EFAULT; > >> - goto __end; > >> + result = -EFAULT; > >> + break; > > > > This still changes the behavior. The read returns the size that has > > been read at first even when an error happens if some data was already > > read. The error code is returned at the next read. This is a design > > problem of read syscall. > > I'm unaware of it... These code should be: > > if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { > if (result == 0) > result = -EFAULT; > break; Well, it's not much better than the original code, IMO. > And I realize sound/firewire/fireworks/fireworks_hwdep.c has the same > bug. I'll post another patch for this bug. This is an implementation detail and I believe it rather depends on each driver. (But I should reread POSIX definition again before concluding it.) That said, it isn't wrong to return -EFAULT immediately, per se. The problem here is that you change the existing behavior. Especially a core code like this should be treated carefully even for such a small behavior change. Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] ALSA: ctl: refactoring for read operation 2015-04-10 10:43 ` Takashi Iwai @ 2015-04-10 10:52 ` Takashi Sakamoto 0 siblings, 0 replies; 15+ messages in thread From: Takashi Sakamoto @ 2015-04-10 10:52 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, clemens On Apr 10 2015 19:43, Takashi Iwai wrote: >> I'm unaware of it... These code should be: >> >> if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { >> if (result == 0) >> result = -EFAULT; >> break; > > Well, it's not much better than the original code, IMO. OK. I dropped this patch. >> And I realize sound/firewire/fireworks/fireworks_hwdep.c has the same >> bug. I'll post another patch for this bug. > > This is an implementation detail and I believe it rather depends on > each driver. (But I should reread POSIX definition again before > concluding it.) > > That said, it isn't wrong to return -EFAULT immediately, per se. > The problem here is that you change the existing behavior. Especially > a core code like this should be treated carefully even for such a > small behavior change. Thanks Takashi Sakamoto ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2015-04-12 7:20 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-04-08 16:55 [PATCH 0/2 RFC] control core refactoring Takashi Sakamoto 2015-04-08 16:55 ` [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value Takashi Sakamoto 2015-04-08 16:55 ` [PATCH 2/2] ALSA: ctl: refactoring for read operation Takashi Sakamoto 2015-04-09 5:33 ` Takashi Iwai 2015-04-09 7:35 ` Takashi Sakamoto 2015-04-09 8:17 ` Takashi Iwai 2015-04-09 23:42 ` [PATCH 0/2] control core refactoring Takashi Sakamoto 2015-04-09 23:43 ` [PATCH 1/2] ALSA: ctl: evaluate macro instead of numerical value Takashi Sakamoto 2015-04-10 7:49 ` Takashi Iwai 2015-04-12 7:20 ` Takashi Iwai 2015-04-09 23:43 ` [PATCH 2/2] ALSA: ctl: refactoring for read operation Takashi Sakamoto 2015-04-10 7:48 ` Takashi Iwai 2015-04-10 10:32 ` Takashi Sakamoto 2015-04-10 10:43 ` Takashi Iwai 2015-04-10 10:52 ` Takashi Sakamoto
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.