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 <mche...@osg.samsung.com>

Acked-by: Hans Verkuil <hans.verk...@cisco.com>

> 
> 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to