Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15a98fb2 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Mauro Carvalho Chehab
Browse files

media: dvb_frontend: split dvb_frontend_handle_ioctl function



Over time, dvb_frontend_handle_ioctl() has grown to the point where
we now get a warning from the compiler about excessive stack usage:

drivers/media/dvb-core/dvb_frontend.c: In function 'dvb_frontend_handle_ioctl':
drivers/media/dvb-core/dvb_frontend.c:2692:1: error: the frame size of 1048 bytes is larger than 1024 bytes [-Werror=frame-larger-than=]

Almost all of this is used by the dtv_frontend_properties structure
in the FE_GET_PROPERTY and FE_GET_FRONTEND commands. Splitting those
into separate function reduces the stack usage of the main function
to just 136 bytes, the others are under 500 each.

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarSean Young <sean@mess.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent a91418ac
Loading
Loading
Loading
Loading
+77 −63
Original line number Diff line number Diff line
@@ -2311,21 +2311,15 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
	return 0;
}

static int dvb_frontend_handle_ioctl(struct file *file,
				     unsigned int cmd, void *parg)
static int dvb_get_property(struct dvb_frontend *fe, struct file *file,
			    struct dtv_properties *tvps)
{
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_frontend *fe = dvbdev->priv;
	struct dvb_frontend_private *fepriv = fe->frontend_priv;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	int i, err = -ENOTSUPP;

	dev_dbg(fe->dvb->device, "%s:\n", __func__);

	switch (cmd) {
	case FE_SET_PROPERTY: {
		struct dtv_properties *tvps = parg;
	struct dtv_property *tvp = NULL;
	struct dtv_frontend_properties getp;
	int i, err;

	memcpy(&getp, &fe->dtv_property_cache, sizeof(getp));

	dev_dbg(fe->dvb->device, "%s: properties.num = %d\n",
		__func__, tvps->num);
@@ -2336,30 +2330,74 @@ static int dvb_frontend_handle_ioctl(struct file *file,
	 * Put an arbitrary limit on the number of messages that can
	 * be sent at once
	 */
		if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
	if (!tvps->num || tvps->num > DTV_IOCTL_MAX_MSGS)
		return -EINVAL;

	tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
	if (IS_ERR(tvp))
		return PTR_ERR(tvp);

	/*
	 * Let's use our own copy of property cache, in order to
	 * avoid mangling with DTV zigzag logic, as drivers might
	 * return crap, if they don't check if the data is available
	 * before updating the properties cache.
	 */
	if (fepriv->state != FESTATE_IDLE) {
		err = dtv_get_frontend(fe, &getp, NULL);
		if (err < 0)
			goto out;
	}
	for (i = 0; i < tvps->num; i++) {
			err = dtv_property_process_set(fe, file,
						       (tvp + i)->cmd,
						       (tvp + i)->u.data);
			if (err < 0) {
				kfree(tvp);
				return err;
		err = dtv_property_process_get(fe, &getp,
					       tvp + i, file);
		if (err < 0)
			goto out;
	}

	if (copy_to_user((void __user *)tvps->props, tvp,
			 tvps->num * sizeof(struct dtv_property))) {
		err = -EFAULT;
		goto out;
	}
		kfree(tvp);

	err = 0;
		break;
out:
	kfree(tvp);
	return err;
}

static int dvb_get_frontend(struct dvb_frontend *fe,
			    struct dvb_frontend_parameters *p_out)
{
	struct dtv_frontend_properties getp;

	/*
	 * Let's use our own copy of property cache, in order to
	 * avoid mangling with DTV zigzag logic, as drivers might
	 * return crap, if they don't check if the data is available
	 * before updating the properties cache.
	 */
	memcpy(&getp, &fe->dtv_property_cache, sizeof(getp));

	return dtv_get_frontend(fe, &getp, p_out);
}
	case FE_GET_PROPERTY: {

static int dvb_frontend_handle_ioctl(struct file *file,
				     unsigned int cmd, void *parg)
{
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_frontend *fe = dvbdev->priv;
	struct dvb_frontend_private *fepriv = fe->frontend_priv;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	int i, err = -ENOTSUPP;

	dev_dbg(fe->dvb->device, "%s:\n", __func__);

	switch (cmd) {
	case FE_SET_PROPERTY: {
		struct dtv_properties *tvps = parg;
		struct dtv_property *tvp = NULL;
		struct dtv_frontend_properties getp = fe->dtv_property_cache;

		dev_dbg(fe->dvb->device, "%s: properties.num = %d\n",
			__func__, tvps->num);
@@ -2377,37 +2415,22 @@ static int dvb_frontend_handle_ioctl(struct file *file,
		if (IS_ERR(tvp))
			return PTR_ERR(tvp);

		/*
		 * Let's use our own copy of property cache, in order to
		 * avoid mangling with DTV zigzag logic, as drivers might
		 * return crap, if they don't check if the data is available
		 * before updating the properties cache.
		 */
		if (fepriv->state != FESTATE_IDLE) {
			err = dtv_get_frontend(fe, &getp, NULL);
			if (err < 0) {
				kfree(tvp);
				return err;
			}
		}
		for (i = 0; i < tvps->num; i++) {
			err = dtv_property_process_get(fe, &getp,
						       tvp + i, file);
			err = dtv_property_process_set(fe, file,
						       (tvp + i)->cmd,
						       (tvp + i)->u.data);
			if (err < 0) {
				kfree(tvp);
				return err;
			}
		}

		if (copy_to_user((void __user *)tvps->props, tvp,
				 tvps->num * sizeof(struct dtv_property))) {
			kfree(tvp);
			return -EFAULT;
		}
		kfree(tvp);
		err = 0;
		break;
	}
	case FE_GET_PROPERTY:
		err = dvb_get_property(fe, file, parg);
		break;

	case FE_GET_INFO: {
		struct dvb_frontend_info *info = parg;
@@ -2545,7 +2568,6 @@ static int dvb_frontend_handle_ioctl(struct file *file,
		fepriv->tune_mode_flags = (unsigned long)parg;
		err = 0;
		break;

	/* DEPRECATED dish control ioctls */

	case FE_DISHNETWORK_SEND_LEGACY_CMD:
@@ -2664,22 +2686,14 @@ static int dvb_frontend_handle_ioctl(struct file *file,
			break;
		err = dtv_set_frontend(fe);
		break;

	case FE_GET_EVENT:
		err = dvb_frontend_get_event(fe, parg, file->f_flags);
		break;

	case FE_GET_FRONTEND: {
		struct dtv_frontend_properties getp = fe->dtv_property_cache;

		/*
		 * Let's use our own copy of property cache, in order to
		 * avoid mangling with DTV zigzag logic, as drivers might
		 * return crap, if they don't check if the data is available
		 * before updating the properties cache.
		 */
		err = dtv_get_frontend(fe, &getp, parg);
	case FE_GET_FRONTEND:
		err = dvb_get_frontend(fe, parg);
		break;
	}

	default:
		return -ENOTSUPP;