Commit ae921398 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: pcm: Use automatic cleanup of kfree()



There are common patterns where a temporary buffer is allocated and
freed at the exit, and those can be simplified with the recent cleanup
mechanism via __free(kfree).

A caveat is that some allocations are memdup_user() and they return an
error pointer instead of NULL.  Those need special cares and the value
has to be cleared with no_free_ptr() at the allocation error path.

Other than that, the conversions are straightforward.

No functional changes, only code refactoring.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20240222111509.28390-2-tiwai@suse.de
parent ec89fc1b
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -342,7 +342,7 @@ static const char *snd_pcm_oss_format_name(int format)
static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
				   struct snd_info_buffer *buffer)
{
	struct snd_pcm_info *info;
	struct snd_pcm_info *info __free(kfree) = NULL;
	int err;

	if (! substream)
@@ -355,7 +355,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
	err = snd_pcm_info(substream, info);
	if (err < 0) {
		snd_iprintf(buffer, "error %d\n", err);
		kfree(info);
		return;
	}
	snd_iprintf(buffer, "card: %d\n", info->card);
@@ -369,7 +368,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
	snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
	snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
	snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
	kfree(info);
}

static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
+10 −19
Original line number Diff line number Diff line
@@ -235,7 +235,7 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
					  int refine, 
					  struct snd_pcm_hw_params32 __user *data32)
{
	struct snd_pcm_hw_params *data;
	struct snd_pcm_hw_params *data __free(kfree) = NULL;
	struct snd_pcm_runtime *runtime;
	int err;

@@ -248,34 +248,28 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
		return -ENOMEM;

	/* only fifo_size (RO from userspace) is different, so just copy all */
	if (copy_from_user(data, data32, sizeof(*data32))) {
		err = -EFAULT;
		goto error;
	}
	if (copy_from_user(data, data32, sizeof(*data32)))
		return -EFAULT;

	if (refine) {
		err = snd_pcm_hw_refine(substream, data);
		if (err < 0)
			goto error;
			return err;
		err = fixup_unreferenced_params(substream, data);
	} else {
		err = snd_pcm_hw_params(substream, data);
	}
	if (err < 0)
		goto error;
		return err;
	if (copy_to_user(data32, data, sizeof(*data32)) ||
	    put_user(data->fifo_size, &data32->fifo_size)) {
		err = -EFAULT;
		goto error;
	}
	    put_user(data->fifo_size, &data32->fifo_size))
		return -EFAULT;

	if (! refine) {
		unsigned int new_boundary = recalculate_boundary(runtime);
		if (new_boundary)
			runtime->boundary = new_boundary;
	}
 error:
	kfree(data);
	return err;
}

@@ -338,7 +332,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
	compat_caddr_t buf;
	compat_caddr_t __user *bufptr;
	u32 frames;
	void __user **bufs;
	void __user **bufs __free(kfree) = NULL;
	int err, ch, i;

	if (! substream->runtime)
@@ -360,10 +354,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
		return -ENOMEM;
	for (i = 0; i < ch; i++) {
		u32 ptr;
		if (get_user(ptr, bufptr)) {
			kfree(bufs);
		if (get_user(ptr, bufptr))
			return -EFAULT;
		}
		bufs[i] = compat_ptr(ptr);
		bufptr++;
	}
@@ -373,9 +365,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
		err = snd_pcm_lib_readv(substream, bufs, frames);
	if (err >= 0) {
		if (put_user(err, &data32->result))
			err = -EFAULT;
			return -EFAULT;
	}
	kfree(bufs);
	return err;
}

+38 −61
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
int snd_pcm_info_user(struct snd_pcm_substream *substream,
		      struct snd_pcm_info __user * _info)
{
	struct snd_pcm_info *info;
	struct snd_pcm_info *info __free(kfree) = NULL;
	int err;

	info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -247,7 +247,6 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
		if (copy_to_user(_info, info, sizeof(*info)))
			err = -EFAULT;
	}
	kfree(info);
	return err;
}

@@ -359,7 +358,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_constraints *constrs =
					&substream->runtime->hw_constraints;
	unsigned int k;
	unsigned int *rstamps;
	unsigned int *rstamps __free(kfree) = NULL;
	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
	unsigned int stamp;
	struct snd_pcm_hw_rule *r;
@@ -435,10 +434,8 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
		}

		changed = r->func(params, r);
		if (changed < 0) {
			err = changed;
			goto out;
		}
		if (changed < 0)
			return changed;

		/*
		 * When the parameter is changed, notify it to the caller
@@ -469,8 +466,6 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
	if (again)
		goto retry;

 out:
	kfree(rstamps);
	return err;
}

@@ -571,26 +566,24 @@ EXPORT_SYMBOL(snd_pcm_hw_refine);
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params __user * _params)
{
	struct snd_pcm_hw_params *params;
	struct snd_pcm_hw_params *params __free(kfree) = NULL;
	int err;

	params = memdup_user(_params, sizeof(*params));
	if (IS_ERR(params))
		return PTR_ERR(params);
		return PTR_ERR(no_free_ptr(params));

	err = snd_pcm_hw_refine(substream, params);
	if (err < 0)
		goto end;
		return err;

	err = fixup_unreferenced_params(substream, params);
	if (err < 0)
		goto end;
		return err;

	if (copy_to_user(_params, params, sizeof(*params)))
		err = -EFAULT;
end:
	kfree(params);
	return err;
		return -EFAULT;
	return 0;
}

static int period_to_usecs(struct snd_pcm_runtime *runtime)
@@ -864,21 +857,19 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params __user * _params)
{
	struct snd_pcm_hw_params *params;
	struct snd_pcm_hw_params *params __free(kfree) = NULL;
	int err;

	params = memdup_user(_params, sizeof(*params));
	if (IS_ERR(params))
		return PTR_ERR(params);
		return PTR_ERR(no_free_ptr(params));

	err = snd_pcm_hw_params(substream, params);
	if (err < 0)
		goto end;
		return err;

	if (copy_to_user(_params, params, sizeof(*params)))
		err = -EFAULT;
end:
	kfree(params);
		return -EFAULT;
	return err;
}

@@ -2271,7 +2262,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
	int res = 0;
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream1;
	struct snd_pcm_group *group, *target_group;
	struct snd_pcm_group *group __free(kfree) = NULL;
	struct snd_pcm_group *target_group;
	bool nonatomic = substream->pcm->nonatomic;
	struct fd f = fdget(fd);

@@ -2281,6 +2273,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
		res = -EBADFD;
		goto _badf;
	}

	pcm_file = f.file->private_data;
	substream1 = pcm_file->substream;

@@ -2292,8 +2285,9 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
	group = kzalloc(sizeof(*group), GFP_KERNEL);
	if (!group) {
		res = -ENOMEM;
		goto _nolock;
		goto _badf;
	}

	snd_pcm_group_init(group);

	down_write(&snd_pcm_link_rwsem);
@@ -2324,8 +2318,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
	snd_pcm_group_unlock_irq(target_group, nonatomic);
 _end:
	up_write(&snd_pcm_link_rwsem);
 _nolock:
	kfree(group);
 _badf:
	fdput(f);
	return res;
@@ -3279,7 +3271,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
{
	struct snd_xfern xfern;
	struct snd_pcm_runtime *runtime = substream->runtime;
	void *bufs;
	void *bufs __free(kfree) = NULL;
	snd_pcm_sframes_t result;

	if (runtime->state == SNDRV_PCM_STATE_OPEN)
@@ -3293,12 +3285,11 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,

	bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
	if (IS_ERR(bufs))
		return PTR_ERR(bufs);
		return PTR_ERR(no_free_ptr(bufs));
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
	else
		result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
	kfree(bufs);
	if (put_user(result, &_xfern->result))
		return -EFAULT;
	return result < 0 ? result : 0;
@@ -3566,7 +3557,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
	struct snd_pcm_runtime *runtime;
	snd_pcm_sframes_t result;
	unsigned long i;
	void __user **bufs;
	void __user **bufs __free(kfree) = NULL;
	snd_pcm_uframes_t frames;
	const struct iovec *iov = iter_iov(to);

@@ -3595,7 +3586,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
	result = snd_pcm_lib_readv(substream, bufs, frames);
	if (result > 0)
		result = frames_to_bytes(runtime, result);
	kfree(bufs);
	return result;
}

@@ -3606,7 +3596,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
	struct snd_pcm_runtime *runtime;
	snd_pcm_sframes_t result;
	unsigned long i;
	void __user **bufs;
	void __user **bufs __free(kfree) = NULL;
	snd_pcm_uframes_t frames;
	const struct iovec *iov = iter_iov(from);

@@ -3634,7 +3624,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
	result = snd_pcm_lib_writev(substream, bufs, frames);
	if (result > 0)
		result = frames_to_bytes(runtime, result);
	kfree(bufs);
	return result;
}

@@ -4076,8 +4065,8 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params_old __user * _oparams)
{
	struct snd_pcm_hw_params *params;
	struct snd_pcm_hw_params_old *oparams = NULL;
	struct snd_pcm_hw_params *params __free(kfree) = NULL;
	struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
	int err;

	params = kmalloc(sizeof(*params), GFP_KERNEL);
@@ -4085,34 +4074,28 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
		return -ENOMEM;

	oparams = memdup_user(_oparams, sizeof(*oparams));
	if (IS_ERR(oparams)) {
		err = PTR_ERR(oparams);
		goto out;
	}
	if (IS_ERR(oparams))
		return PTR_ERR(no_free_ptr(oparams));
	snd_pcm_hw_convert_from_old_params(params, oparams);
	err = snd_pcm_hw_refine(substream, params);
	if (err < 0)
		goto out_old;
		return err;

	err = fixup_unreferenced_params(substream, params);
	if (err < 0)
		goto out_old;
		return err;

	snd_pcm_hw_convert_to_old_params(oparams, params);
	if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
		err = -EFAULT;
out_old:
	kfree(oparams);
out:
	kfree(params);
	return err;
		return -EFAULT;
	return 0;
}

static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params_old __user * _oparams)
{
	struct snd_pcm_hw_params *params;
	struct snd_pcm_hw_params_old *oparams = NULL;
	struct snd_pcm_hw_params *params __free(kfree) = NULL;
	struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
	int err;

	params = kmalloc(sizeof(*params), GFP_KERNEL);
@@ -4120,24 +4103,18 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
		return -ENOMEM;

	oparams = memdup_user(_oparams, sizeof(*oparams));
	if (IS_ERR(oparams)) {
		err = PTR_ERR(oparams);
		goto out;
	}
	if (IS_ERR(oparams))
		return PTR_ERR(no_free_ptr(oparams));

	snd_pcm_hw_convert_from_old_params(params, oparams);
	err = snd_pcm_hw_params(substream, params);
	if (err < 0)
		goto out_old;
		return err;

	snd_pcm_hw_convert_to_old_params(oparams, params);
	if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
		err = -EFAULT;
out_old:
	kfree(oparams);
out:
	kfree(params);
	return err;
		return -EFAULT;
	return 0;
}
#endif /* CONFIG_SND_SUPPORT_OLD_API */