Re: [PATCH 07/18] [media] dvbdev: returns error if graph object creation fails

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 09/06/2015 07:30 PM, Mauro Carvalho Chehab wrote:
> Right now, if something gets wrong at dvb_create_media_entity()
> or at dvb_create_media_graph(), the device will still be
> registered.
> 
> Change the logic to properly handle it and free all media graph
> objects if something goes wrong at dvb_register_device().
> 
> Also, change the logic at dvb_create_media_graph() to return
> an error code if something goes wrong. It is up to the
> caller to implement the right logic and to call
> dvb_unregister_device() to unregister the already-created
> objects.
> 
> While here, add a missing logic to unregister the created
> interfaces.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab@xxxxxxxxxxxxxxx>

Acked-by: Hans Verkuil <hans.verkuil@xxxxxxxxx>

> 
> diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
> index 5c4fb41060b4..5c51084a331a 100644
> --- a/drivers/media/dvb-core/dvbdev.c
> +++ b/drivers/media/dvb-core/dvbdev.c
> @@ -183,7 +183,29 @@ skip:
>  	return -ENFILE;
>  }
>  
> -static void dvb_create_tsout_entity(struct dvb_device *dvbdev,
> +static void dvb_media_device_free(struct dvb_device *dvbdev)
> +{
> +#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
> +	if (dvbdev->entity) {
> +		int i;
> +
> +		for (i = 0; i < dvbdev->tsout_num_entities; i++) {
> +			media_device_unregister_entity(&dvbdev->tsout_entity[i]);
> +			kfree(dvbdev->tsout_entity[i].name);
> +		}
> +		media_device_unregister_entity(dvbdev->entity);
> +
> +		kfree(dvbdev->entity);
> +		kfree(dvbdev->pads);
> +		kfree(dvbdev->tsout_entity);
> +		kfree(dvbdev->tsout_pads);
> +	}
> +	if (dvbdev->intf_devnode)
> +		media_devnode_remove(dvbdev->intf_devnode);
> +#endif
> +}
> +
> +static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
>  				    const char *name, int npads)
>  {
>  #if defined(CONFIG_MEDIA_CONTROLLER_DVB)
> @@ -192,77 +214,60 @@ static void dvb_create_tsout_entity(struct dvb_device *dvbdev,
>  	dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
>  				     GFP_KERNEL);
>  	if (!dvbdev->tsout_pads)
> -		return;
> +		return -ENOMEM;
> +
>  	dvbdev->tsout_entity = kcalloc(npads, sizeof(*dvbdev->tsout_entity),
>  				       GFP_KERNEL);
> -	if (!dvbdev->tsout_entity) {
> -		kfree(dvbdev->tsout_pads);
> -		dvbdev->tsout_pads = NULL;
> -		return;
> -	}
> +	if (!dvbdev->tsout_entity)
> +		return -ENOMEM;
> +
>  	for (i = 0; i < npads; i++) {
>  		struct media_pad *pads = &dvbdev->tsout_pads[i];
>  		struct media_entity *entity = &dvbdev->tsout_entity[i];
>  
>  		entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
> -		if (!entity->name) {
> -			ret = -ENOMEM;
> -			break;
> -		}
> +		if (!entity->name)
> +			return ret;
>  
>  		entity->type = MEDIA_ENT_T_DVB_TSOUT;
>  		pads->flags = MEDIA_PAD_FL_SINK;
>  
>  		ret = media_entity_init(entity, 1, pads);
>  		if (ret < 0)
> -			break;
> +			return ret;
>  
>  		ret = media_device_register_entity(dvbdev->adapter->mdev,
>  						   entity);
>  		if (ret < 0)
> -			break;
> +			return ret;
>  	}
> -
> -	if (!ret) {
> -		dvbdev->tsout_num_entities = npads;
> -		return;
> -	}
> -
> -	for (i--; i >= 0; i--) {
> -		media_device_unregister_entity(&dvbdev->tsout_entity[i]);
> -		kfree(dvbdev->tsout_entity[i].name);
> -	}
> -
> -	printk(KERN_ERR
> -		"%s: media_device_register_entity failed for %s\n",
> -		__func__, name);
> -
> -	kfree(dvbdev->tsout_entity);
> -	kfree(dvbdev->tsout_pads);
> -	dvbdev->tsout_entity = NULL;
> -	dvbdev->tsout_pads = NULL;
>  #endif
> +	return 0;
>  }
>  
>  #define DEMUX_TSOUT	"demux-tsout"
>  #define DVR_TSOUT	"dvr-tsout"
>  
> -static void dvb_create_media_entity(struct dvb_device *dvbdev,
> -				    int type, int demux_sink_pads)
> +static int dvb_create_media_entity(struct dvb_device *dvbdev,
> +				   int type, int demux_sink_pads)
>  {
>  #if defined(CONFIG_MEDIA_CONTROLLER_DVB)
> -	int i, ret = 0, npads;
> +	int i, ret, npads;
>  
>  	switch (type) {
>  	case DVB_DEVICE_FRONTEND:
>  		npads = 2;
>  		break;
>  	case DVB_DEVICE_DVR:
> -		dvb_create_tsout_entity(dvbdev, DVR_TSOUT, demux_sink_pads);
> -		return;
> +		ret = dvb_create_tsout_entity(dvbdev, DVR_TSOUT,
> +					      demux_sink_pads);
> +		return ret;
>  	case DVB_DEVICE_DEMUX:
>  		npads = 1 + demux_sink_pads;
> -		dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT, demux_sink_pads);
> +		ret = dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT,
> +					      demux_sink_pads);
> +		if (ret < 0)
> +			return ret;
>  		break;
>  	case DVB_DEVICE_CA:
>  		npads = 2;
> @@ -277,24 +282,22 @@ static void dvb_create_media_entity(struct dvb_device *dvbdev,
>  		 * the Media Controller, let's not create the decap
>  		 * entities yet.
>  		 */
> -		return;
> +		return 0;
>  	default:
> -		return;
> +		return 0;
>  	}
>  
>  	dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
>  	if (!dvbdev->entity)
> -		return;
> +		return -ENOMEM;
>  
>  	dvbdev->entity->name = dvbdev->name;
>  
>  	if (npads) {
>  		dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
>  				       GFP_KERNEL);
> -		if (!dvbdev->pads) {
> -			kfree(dvbdev->entity);
> -			return;
> -		}
> +		if (!dvbdev->pads)
> +			return -ENOMEM;
>  	}
>  
>  	switch (type) {
> @@ -316,49 +319,43 @@ static void dvb_create_media_entity(struct dvb_device *dvbdev,
>  		break;
>  	default:
>  		kfree(dvbdev->entity);
> +		kfree(dvbdev->pads);
>  		dvbdev->entity = NULL;
> -		return;
> +		return 0;
>  	}
>  
> -	if (npads)
> +	if (npads) {
>  		ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads);
> -	if (!ret)
> -		ret = media_device_register_entity(dvbdev->adapter->mdev,
> -						   dvbdev->entity);
> -	if (ret < 0) {
> -		printk(KERN_ERR
> -			"%s: media_device_register_entity failed for %s\n",
> -			__func__, dvbdev->entity->name);
> -
> -		media_device_unregister_entity(dvbdev->entity);
> -		for (i = 0; i < dvbdev->tsout_num_entities; i++) {
> -			media_device_unregister_entity(&dvbdev->tsout_entity[i]);
> -			kfree(dvbdev->tsout_entity[i].name);
> -		}
> -		kfree(dvbdev->pads);
> -		kfree(dvbdev->entity);
> -		kfree(dvbdev->tsout_pads);
> -		kfree(dvbdev->tsout_entity);
> -		dvbdev->entity = NULL;
> -		return;
> +		if (ret)
> +			return ret;
>  	}
> +	ret = media_device_register_entity(dvbdev->adapter->mdev,
> +					   dvbdev->entity);
> +	if (ret)
> +		return (ret);
>  
>  	printk(KERN_DEBUG "%s: media entity '%s' registered.\n",
>  		__func__, dvbdev->entity->name);
> +
>  #endif
> +	return 0;
>  }
>  
> -static void dvb_register_media_device(struct dvb_device *dvbdev,
> -				      int type, int minor,
> -				      unsigned demux_sink_pads)
> +static int dvb_register_media_device(struct dvb_device *dvbdev,
> +				     int type, int minor,
> +				     unsigned demux_sink_pads)
>  {
>  #if defined(CONFIG_MEDIA_CONTROLLER_DVB)
> +	struct media_link *link;
>  	u32 intf_type;
> +	int ret;
>  
>  	if (!dvbdev->adapter->mdev)
> -		return;
> +		return 0;
>  
> -	dvb_create_media_entity(dvbdev, type, demux_sink_pads);
> +	ret = dvb_create_media_entity(dvbdev, type, demux_sink_pads);
> +	if (ret)
> +		return ret;
>  
>  	switch (type) {
>  	case DVB_DEVICE_FRONTEND:
> @@ -377,13 +374,16 @@ static void dvb_register_media_device(struct dvb_device *dvbdev,
>  		intf_type = MEDIA_INTF_T_DVB_NET;
>  		break;
>  	default:
> -		return;
> +		return 0;
>  	}
>  
>  	dvbdev->intf_devnode = media_devnode_create(dvbdev->adapter->mdev,
> -						 intf_type, 0,
> -						 DVB_MAJOR, minor,
> -						 GFP_KERNEL);
> +						    intf_type, 0,
> +						    DVB_MAJOR, minor,
> +						    GFP_KERNEL);
> +
> +	if (!dvbdev->intf_devnode)
> +		return -ENOMEM;
>  
>  	/*
>  	 * Create the "obvious" link, e. g. the ones that represent
> @@ -393,13 +393,15 @@ static void dvb_register_media_device(struct dvb_device *dvbdev,
>  	 *		DVB demux intf -> dvr
>  	 */
>  
> -	if (!dvbdev->entity || !dvbdev->intf_devnode)
> -		return;
> -
> -	media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
> -			       MEDIA_LNK_FL_ENABLED);
> +	if (!dvbdev->entity)
> +		return 0;
>  
> +	link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
> +				      MEDIA_LNK_FL_ENABLED);
> +	if (!link)
> +		return -ENOMEM;
>  #endif
> +	return 0;
>  }
>  
>  int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
> @@ -410,7 +412,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
>  	struct file_operations *dvbdevfops;
>  	struct device *clsdev;
>  	int minor;
> -	int id;
> +	int id, ret;
>  
>  	mutex_lock(&dvbdev_register_lock);
>  
> @@ -428,6 +430,17 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
>  		return -ENOMEM;
>  	}
>  
> +	ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
> +	if (ret) {
> +		printk(KERN_ERR
> +		      "%s: dvb_register_media_device failed to create the mediagraph\n",
> +		      __func__);
> +
> +		dvb_media_device_free(dvbdev);
> +		mutex_unlock(&dvbdev_register_lock);
> +		return ret;
> +	}
> +
>  	dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
>  
>  	if (!dvbdevfops){
> @@ -483,8 +496,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
>  	dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
>  		adap->num, dnames[type], id, minor, minor);
>  
> -	dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
> -
>  	return 0;
>  }
>  EXPORT_SYMBOL(dvb_register_device);
> @@ -499,25 +510,10 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
>  	dvb_minors[dvbdev->minor] = NULL;
>  	up_write(&minor_rwsem);
>  
> +	dvb_media_device_free(dvbdev);
> +
>  	device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
>  
> -#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
> -	if (dvbdev->entity) {
> -		int i;
> -
> -		media_device_unregister_entity(dvbdev->entity);
> -		for (i = 0; i < dvbdev->tsout_num_entities; i++) {
> -			media_device_unregister_entity(&dvbdev->tsout_entity[i]);
> -			kfree(dvbdev->tsout_entity[i].name);
> -		}
> -
> -		kfree(dvbdev->entity);
> -		kfree(dvbdev->pads);
> -		kfree(dvbdev->tsout_entity);
> -		kfree(dvbdev->tsout_pads);
> -	}
> -#endif
> -
>  	list_del (&dvbdev->list_head);
>  	kfree (dvbdev->fops);
>  	kfree (dvbdev);
> @@ -526,17 +522,19 @@ EXPORT_SYMBOL(dvb_unregister_device);
>  
>  
>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
> -void dvb_create_media_graph(struct dvb_adapter *adap)
> +int dvb_create_media_graph(struct dvb_adapter *adap)
>  {
>  	struct media_device *mdev = adap->mdev;
>  	struct media_entity *entity, *tuner = NULL, *demod = NULL;
>  	struct media_entity *demux = NULL, *ca = NULL;
> +	struct media_link *link;
>  	struct media_interface *intf;
>  	unsigned demux_pad = 0;
>  	unsigned dvr_pad = 0;
> +	int ret;
>  
>  	if (!mdev)
> -		return;
> +		return 0;
>  
>  	media_device_for_each_entity(entity, mdev) {
>  		switch (entity->type) {
> @@ -555,57 +553,94 @@ void dvb_create_media_graph(struct dvb_adapter *adap)
>  		}
>  	}
>  
> -	if (tuner && demod)
> -		media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT, demod, 0, 0);
> +	if (tuner && demod) {
> +		ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT,
> +					    demod, 0, MEDIA_LNK_FL_ENABLED);
> +		if (ret)
> +			return ret;
> +	}
>  
> -	if (demod && demux)
> -		media_create_pad_link(demod, 1, demux, 0, MEDIA_LNK_FL_ENABLED);
> -	if (demux && ca)
> -		media_create_pad_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED);
> +	if (demod && demux) {
> +		ret = media_create_pad_link(demod, 1, demux,
> +					    0, MEDIA_LNK_FL_ENABLED);
> +		if (ret)
> +			return -ENOMEM;
> +	}
> +	if (demux && ca) {
> +		ret = media_create_pad_link(demux, 1, ca,
> +					    0, MEDIA_LNK_FL_ENABLED);
> +		if (!ret)
> +			return -ENOMEM;
> +	}
>  
>  	/* Create demux links for each ringbuffer/pad */
>  	if (demux) {
>  		media_device_for_each_entity(entity, mdev) {
>  			if (entity->type == MEDIA_ENT_T_DVB_TSOUT) {
>  				if (!strncmp(entity->name, DVR_TSOUT,
> -					strlen(DVR_TSOUT)))
> -					media_create_pad_link(demux,
> -							      ++dvr_pad,
> -							entity, 0, 0);
> +				    strlen(DVR_TSOUT))) {
> +					ret = media_create_pad_link(demux,
> +								++dvr_pad,
> +							    entity, 0, 0);
> +					if (ret)
> +						return ret;
> +				}
>  				if (!strncmp(entity->name, DEMUX_TSOUT,
> -					strlen(DEMUX_TSOUT)))
> -					media_create_pad_link(demux,
> +				    strlen(DEMUX_TSOUT))) {
> +					ret = media_create_pad_link(demux,
>  							      ++demux_pad,
> -							entity, 0, 0);
> +							    entity, 0, 0);
> +					if (ret)
> +						return ret;
> +				}
>  			}
>  		}
>  	}
>  
>  	/* Create indirect interface links for FE->tuner, DVR->demux and CA->ca */
>  	media_device_for_each_intf(intf, mdev) {
> -		if (intf->type == MEDIA_INTF_T_DVB_CA && ca)
> -			media_create_intf_link(ca, intf, MEDIA_LNK_FL_ENABLED);
> +		if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
> +			link = media_create_intf_link(ca, intf,
> +						      MEDIA_LNK_FL_ENABLED);
> +			if (!link)
> +				return -ENOMEM;
> +		}
>  
> -		if (intf->type == MEDIA_INTF_T_DVB_FE && tuner)
> -			media_create_intf_link(tuner, intf,
> -					       MEDIA_LNK_FL_ENABLED);
> +		if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
> +			link = media_create_intf_link(tuner, intf,
> +						      MEDIA_LNK_FL_ENABLED);
> +			if (!link)
> +				return -ENOMEM;
> +		}
>  
> -		if (intf->type == MEDIA_INTF_T_DVB_DVR && demux)
> -			media_create_intf_link(demux, intf,
> -					       MEDIA_LNK_FL_ENABLED);
> +		if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
> +			link = media_create_intf_link(demux, intf,
> +						      MEDIA_LNK_FL_ENABLED);
> +			if (!link)
> +				return -ENOMEM;
> +		}
>  
>  		media_device_for_each_entity(entity, mdev) {
>  			if (entity->type == MEDIA_ENT_T_DVB_TSOUT) {
> -				if (!strcmp(entity->name, DVR_TSOUT))
> -					media_create_intf_link(entity, intf,
> -							       MEDIA_LNK_FL_ENABLED);
> -				if (!strcmp(entity->name, DEMUX_TSOUT))
> -					media_create_intf_link(entity, intf,
> -							       MEDIA_LNK_FL_ENABLED);
> +				if (!strcmp(entity->name, DVR_TSOUT)) {
> +					link = media_create_intf_link(entity,
> +							intf,
> +							MEDIA_LNK_FL_ENABLED);
> +					if (!link)
> +						return -ENOMEM;
> +				}
> +				if (!strcmp(entity->name, DEMUX_TSOUT)) {
> +					link = media_create_intf_link(entity,
> +							intf,
> +							MEDIA_LNK_FL_ENABLED);
> +					if (!link)
> +						return -ENOMEM;
> +				}
>  				break;
>  			}
>  		}
>  	}
> +	return 0;
>  }
>  EXPORT_SYMBOL_GPL(dvb_create_media_graph);
>  #endif
> diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
> index 0b140e8595de..9e24aafeb9ea 100644
> --- a/drivers/media/dvb-core/dvbdev.h
> +++ b/drivers/media/dvb-core/dvbdev.h
> @@ -210,7 +210,7 @@ int dvb_register_device(struct dvb_adapter *adap,
>  void dvb_unregister_device(struct dvb_device *dvbdev);
>  
>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
> -void dvb_create_media_graph(struct dvb_adapter *adap);
> +int dvb_create_media_graph(struct dvb_adapter *adap);
>  static inline void dvb_register_media_controller(struct dvb_adapter *adap,
>  						 struct media_device *mdev)
>  {
> @@ -218,7 +218,10 @@ static inline void dvb_register_media_controller(struct dvb_adapter *adap,
>  }
>  
>  #else
> -static inline void dvb_create_media_graph(struct dvb_adapter *adap) {}
> +static inline int dvb_create_media_graph(struct dvb_adapter *adap)
> +{
> +	return 0;
> +};
>  #define dvb_register_media_controller(a, b) {}
>  #endif
>  
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux