From b7b603c33d7cc369f1165773a0f3fa14f7f71baf Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Sun, 8 Dec 2019 01:30:38 +0300 Subject: [PATCH] media: soc_camera: rcar_vin: Fix crash when the module is removed The kernel may crash when removing rcar_csi2 or re-inserting rcar_vin module after having removed it. This happens when multiple ports are used. Multiple async clients are created in this case. Each client registers a notifier which is added to the notifier_list. However, only the last one, referenced by the async_client pointer, is removed form the notifier_list later when the rcar_vin module is removed. Fix this issue by using a linked list and removing all the async clients in the list when removing rcar_vin device. Signed-off-by: Valentine Barshak --- drivers/media/platform/soc_camera/rcar_vin.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 501598c..e13a046 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -922,7 +922,7 @@ struct rcar_vin_priv { bool deser_sync; int lut_updated; - struct rcar_vin_async_client *async_client; + struct list_head async_client; /* Asynchronous CSI2 linking */ struct v4l2_subdev *csi2_sd; /* Asynchronous Deserializer linking */ @@ -3032,7 +3032,7 @@ static int rcar_vin_soc_of_bind(struct rcar_vin_priv *priv, sasc->notifier.num_subdevs = 1; sasc->notifier.ops = &rcar_vin_sensor_ops; - priv->async_client = sasc; + list_add(&sasc->list, &priv->async_client); client = of_find_i2c_device_by_node(remote); @@ -3368,6 +3368,7 @@ static int rcar_vin_probe(struct platform_device *pdev) spin_lock_init(&priv->lock); INIT_LIST_HEAD(&priv->capture); + INIT_LIST_HEAD(&priv->async_client); priv->state = STOPPED; @@ -3417,11 +3418,16 @@ static int rcar_vin_remove(struct platform_device *pdev) struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); struct rcar_vin_priv *priv = container_of(soc_host, struct rcar_vin_priv, ici); + struct rcar_vin_async_client *sasc, *tmp; - platform_device_del(priv->async_client->pdev); - platform_device_put(priv->async_client->pdev); + list_for_each_entry_safe(sasc, tmp, &priv->async_client, list) { + v4l2_async_notifier_unregister(&sasc->notifier); + v4l2_async_notifier_cleanup(&sasc->notifier); + list_del(&sasc->list); - v4l2_async_notifier_unregister(&priv->async_client->notifier); + platform_device_del(sasc->pdev); + platform_device_put(sasc->pdev); + } soc_camera_host_unregister(soc_host); pm_runtime_disable(&pdev->dev); -- 2.7.4