In current implementation, an execution path of ELEM_REPLACE request joins in an execution path of ELEM_ADD in the last. An advance preparation of the replacement can be split from processing of the addition. This separation might be a good granularity of helper functions.
For a preparation to it, this commit adds an unique helper function for the replacement. In this time, the execution path still joins in the one of the addition.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/core/control.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/sound/core/control.c b/sound/core/control.c index a321576a6308..9e23f84d284d 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1406,7 +1406,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, }
static int snd_ctl_elem_add_user(struct snd_ctl_file *ctl_file, - void __user *arg, int replace) + void __user *arg) { struct snd_ctl_elem_info *info; int err; @@ -1415,7 +1415,29 @@ static int snd_ctl_elem_add_user(struct snd_ctl_file *ctl_file, if (IS_ERR(info)) return PTR_ERR(info);
- err = snd_ctl_elem_add(ctl_file, info, replace); + err = snd_ctl_elem_add(ctl_file, info, 0); + if (err >= 0) { + if (copy_to_user(arg, info, sizeof(*info))) { + snd_ctl_remove_user_ctl(ctl_file, &info->id); + err = -EFAULT; + } + } + + kfree(info); + return err; +} + +static int snd_ctl_elem_replace_user(struct snd_ctl_file *ctl_file, + void __user *arg) +{ + struct snd_ctl_elem_info *info; + int err; + + info = memdup_user(arg, sizeof(*info)); + if (IS_ERR(info)) + return PTR_ERR(info); + + err = snd_ctl_elem_add(ctl_file, info, 1); if (err >= 0) { if (copy_to_user(arg, info, sizeof(*info))) { snd_ctl_remove_user_ctl(ctl_file, &info->id); @@ -1592,9 +1614,9 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_ELEM_UNLOCK: return snd_ctl_elem_unlock(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_ADD: - return snd_ctl_elem_add_user(ctl, argp, 0); + return snd_ctl_elem_add_user(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_REPLACE: - return snd_ctl_elem_add_user(ctl, argp, 1); + return snd_ctl_elem_replace_user(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_REMOVE: return snd_ctl_elem_remove(ctl, argp); case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: