1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
From b7b603c33d7cc369f1165773a0f3fa14f7f71baf Mon Sep 17 00:00:00 2001
From: Valentine Barshak <valentine.barshak@cogentembedded.com>
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 <valentine.barshak@cogentembedded.com>
---
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
|