[alsa-devel] [PATCH 3/3] ALSA: core: set kcontrol's count field correctly
Takashi Iwai
tiwai at suse.de
Wed Aug 24 10:42:05 CEST 2011
At Wed, 24 Aug 2011 08:26:47 +0200,
Takashi Iwai wrote:
>
> At Wed, 24 Aug 2011 14:17:57 +0800,
> Lu Guanqun wrote:
> >
> > On Wed, Aug 24, 2011 at 02:06:34PM +0800, Takashi Iwai wrote:
> > > At Wed, 24 Aug 2011 11:12:43 +0800,
> > > Lu Guanqun wrote:
> > > >
> > > > I don't see how info's owner field relates to kcontrol's count field. It should
> > > > assign to info's count instead.
> > > >
> > > > Let's assume this scenario:
> > > >
> > > > 1. user reads the control element from kernel (the owner field is set)
> > > > 2. user changes some values
> > > > 3. user issues 'SNDRV_CTL_IOCTL_ELEM_REPLACE' ioctl.
> > > >
> > > > With the original code, 'kctl' here gets a large count number due to its
> > > > non-empty owner field. Therefore it fails on subsequent call snd_ctl_new().
> > >
> > > In IOCTL_ELEM_ADD and REPLACE, count and owner struct fields have
> > > different meanings from others. The count contains the array size,
> > > not the number of identical elements. And the owner contains the
> > > number of elements to be created. So, the current code is correct.
> >
> > This sounds tricky...
> >
> > in snd_ctl_elem_info():
> > info->owner = pid_vnr(vd->owner->pid);
> > } else {
> > info->owner = -1;
> >
> > This is where owner of info get assigned, but it's not number of
> > elements to be created.
>
> The kcontrol.count field is never exposed to user-space.
>
> > I'm a bit unclear on this.
> >
> > >
> > > What we need is the documentation of this feature...
> >
> > So my test case seems to be wrong, but how should I change it? Do I need
> > to clear the owner field when user space application sends down the
> > REPLACE ioctl?
>
> Yes. Maybe it'd be better to define a new struct and use it in
> ADD/REPLACE ioctls so that user sees a clear difference. The struct
> will be identical except for renaming from owner to elem_count or
> such.
I mean a patch like below (untested).
Takashi
---
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 5d6074f..9f5f55d 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -813,6 +813,33 @@ struct snd_ctl_elem_info {
unsigned char reserved[64-4*sizeof(unsigned short)];
};
+/* The struct used for ELEM_ADD and ELEM_REPLACE ioctls;
+ * This is is identical with snd_ctl_elem_info, but just owner field is
+ * different, keeping the number of elements to be created.
+ * The unused fields are stripped for simplicity.
+ */
+struct snd_ctl_elem_add_info {
+ struct snd_ctl_elem_id id; /* element ID */
+ snd_ctl_elem_type_t type; /* value type */
+ unsigned int access; /* value access (bitmask) */
+ unsigned int count; /* count of values */
+ __kernel_pid_t elem_count; /* # of elements to create (0=1) */
+ union {
+ struct {
+ long min; /* R: minimum value */
+ long max; /* R: maximum value */
+ long step; /* R: step (0 variable) */
+ } integer;
+ struct {
+ long long min; /* R: minimum value */
+ long long max; /* R: maximum value */
+ long long step; /* R: step (0 variable) */
+ } integer64;
+ unsigned char reserved[128];
+ } value;
+ unsigned char reserved[64];
+};
+
struct snd_ctl_elem_value {
struct snd_ctl_elem_id id; /* W: element ID */
unsigned int indirect: 1; /* W: indirect access - obsoleted */
@@ -854,8 +881,8 @@ struct snd_ctl_tlv {
#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
-#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info)
-#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_add_info)
+#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_add_info)
#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv)
#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv)
diff --git a/sound/core/control.c b/sound/core/control.c
index dc2a440..15c171d 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1064,7 +1064,7 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
}
static int snd_ctl_elem_add(struct snd_ctl_file *file,
- struct snd_ctl_elem_info *info, int replace)
+ struct snd_ctl_elem_add_info *info, int replace)
{
struct snd_card *card = file->card;
struct snd_kcontrol kctl, *_kctl;
@@ -1099,7 +1099,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
if (err < 0)
return err;
memcpy(&kctl.id, &info->id, sizeof(info->id));
- kctl.count = info->owner ? info->owner : 1;
+ kctl.count = info->elem_count ? info->elem_count : 1;
access |= SNDRV_CTL_ELEM_ACCESS_USER;
kctl.info = snd_ctl_elem_user_info;
if (access & SNDRV_CTL_ELEM_ACCESS_READ)
@@ -1139,7 +1139,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
if (ue == NULL)
return -ENOMEM;
- ue->info = *info;
+ memcpy(&ue->info, info, sizeof(*info));
ue->info.access = 0;
ue->elem_data = (char *)ue + sizeof(*ue);
ue->elem_data_size = private_size;
@@ -1164,9 +1164,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
}
static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
- struct snd_ctl_elem_info __user *_info, int replace)
+ struct snd_ctl_elem_add_info __user *_info,
+ int replace)
{
- struct snd_ctl_elem_info info;
+ struct snd_ctl_elem_add_info info;
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
return snd_ctl_elem_add(file, &info, replace);
More information about the Alsa-devel
mailing list