On Thu, 17 Mar 2016 04:52:52 +0100, Takashi Sakamoto wrote:
Hi,
When testing ioctl compatibility layer for ALSA ctl interface, I found that error code of some ioctl commands are different depending on binary architecture.
The commands are SNDRV_CTL_IOCTL_ELEM_READ/SNDRV_CTL_IOCTL_ELEM_WRITE. When passing data for non-existent element, ENOENT is returned by the core implementation. On the other hand, ENXIO is returned by the compatibility layer.
This code is for reproduction of this bug.
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <errno.h> #include <string.h>
#include <sound/asound.h>
static void check_elem_read(int fd) { struct snd_ctl_elem_value data = {0}; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_READ, &data) < 0) { printf("ioctl(SNDRV_CTL_IOCTL_ELEM_READ): %s\n", strerror(errno)); } }
static void check_elem_write(int fd) { struct snd_ctl_elem_value data = {0}; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &data) < 0) { printf("ioctl(SNDRV_CTL_IOCTL_ELEM_WRITE): %s\n", strerror(errno)); } }
int main(void) { int fd;
fd = open("/dev/snd/controlC0", O_RDONLY); if (fd < 0) { printf("open(2): %s\n", strerror(errno)); return EXIT_FAILURE; } check_elem_read(fd); check_elem_write(fd); return EXIT_SUCCESS;
}
I tested on x86_64 machine with enough support for multi-arch.
$ gcc -Wall -m64 -o ./test ./test.c ; ./test ioctl(SNDRV_CTL_IOCTL_ELEM_READ): No such file or directory ioctl(SNDRV_CTL_IOCTL_ELEM_WRITE): No such file or directory
$ gcc -Wall -m32 -o ./test ./test.c ; ./test ioctl(SNDRV_CTL_IOCTL_ELEM_READ): No such device or address ioctl(SNDRV_CTL_IOCTL_ELEM_WRITE): No such device or address
This bug is due to return value of condition statement for 'snd_ctl_find()'. I wrote a patch to fix it.
From d7a8fd14a1bc100dbaf9bf28af47094d5ccb882b Mon Sep 17 00:00:00 2001
From: Takashi Sakamoto o-takashi@sakamocchi.jp Date: Wed, 16 Mar 2016 13:40:31 +0900 Subject: [PATCH] ALSA: ctl: change error code in compatibility layer so that it's the same code as core implementation
In control compatibility layer, when no elements are found by ELEM_READ/ELEM_WRITE ioctl commands, ENXIO is returned. On the other hand, in core implementation, ENOENT is returned. This is not good for applications.
This commit changes the return value from the compatibility layer so that the same error code is returned.
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 0608f21..1fa7076 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -196,7 +196,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, kctl = snd_ctl_find_id(card, id); if (! kctl) { up_read(&card->controls_rwsem);
return -ENXIO;
return -ENOENT; } info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) {
Well, it's already in merge window for Linux 4.6. I don't mind to postpone this patch to next developing cycle, while I also think it better to fix the bug now. So I leave the decision to maintainers.
Looks good to me, and trivial enough to be merged for 4.6. Please resubmit with a proper sign off.
thanks,
Takashi