]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.10.42/leds-leds-pwm-properly-clean-up-after-probe-failure.patch
drop queue-4.14/mips-make-sure-dt-memory-regions-are-valid.patch
[thirdparty/kernel/stable-queue.git] / releases / 3.10.42 / leds-leds-pwm-properly-clean-up-after-probe-failure.patch
1 From 392369019eb96e914234ea21eda806cb51a1073e Mon Sep 17 00:00:00 2001
2 From: Russell King <rmk+kernel@arm.linux.org.uk>
3 Date: Sun, 6 Apr 2014 15:20:03 -0700
4 Subject: leds: leds-pwm: properly clean up after probe failure
5
6 From: Russell King <rmk+kernel@arm.linux.org.uk>
7
8 commit 392369019eb96e914234ea21eda806cb51a1073e upstream.
9
10 When probing with DT, we add each LED one at a time. If we find a LED
11 without a PWM device (because it is not available yet) we fail the
12 initialisation, unregister previous LEDs, and then by way of managed
13 resources, we free the structure.
14
15 The problem with this is we may have a scheduled and active work_struct
16 in this structure, and this results in a nasty kernel oops.
17
18 We need to cancel this work_struct properly upon cleanup - and the
19 cleanup we require is the same cleanup as we do when the LED platform
20 device is removed. Rather than writing this same code three times,
21 move it into a separate function and use it in all three places.
22
23 Fixes: c971ff185f64 ("leds: leds-pwm: Defer led_pwm_set() if PWM can sleep")
24 Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
25 Signed-off-by: Bryan Wu <cooloney@gmail.com>
26 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
27
28 ---
29 drivers/leds/leds-pwm.c | 23 +++++++++++++----------
30 1 file changed, 13 insertions(+), 10 deletions(-)
31
32 --- a/drivers/leds/leds-pwm.c
33 +++ b/drivers/leds/leds-pwm.c
34 @@ -82,6 +82,15 @@ static inline size_t sizeof_pwm_leds_pri
35 (sizeof(struct led_pwm_data) * num_leds);
36 }
37
38 +static void led_pwm_cleanup(struct led_pwm_priv *priv)
39 +{
40 + while (priv->num_leds--) {
41 + led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
42 + if (priv->leds[priv->num_leds].can_sleep)
43 + cancel_work_sync(&priv->leds[priv->num_leds].work);
44 + }
45 +}
46 +
47 static struct led_pwm_priv *led_pwm_create_of(struct platform_device *pdev)
48 {
49 struct device_node *node = pdev->dev.of_node;
50 @@ -139,8 +148,7 @@ static struct led_pwm_priv *led_pwm_crea
51
52 return priv;
53 err:
54 - while (priv->num_leds--)
55 - led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
56 + led_pwm_cleanup(priv);
57
58 return NULL;
59 }
60 @@ -200,8 +208,8 @@ static int led_pwm_probe(struct platform
61 return 0;
62
63 err:
64 - while (i--)
65 - led_classdev_unregister(&priv->leds[i].cdev);
66 + priv->num_leds = i;
67 + led_pwm_cleanup(priv);
68
69 return ret;
70 }
71 @@ -209,13 +217,8 @@ err:
72 static int led_pwm_remove(struct platform_device *pdev)
73 {
74 struct led_pwm_priv *priv = platform_get_drvdata(pdev);
75 - int i;
76
77 - for (i = 0; i < priv->num_leds; i++) {
78 - led_classdev_unregister(&priv->leds[i].cdev);
79 - if (priv->leds[i].can_sleep)
80 - cancel_work_sync(&priv->leds[i].work);
81 - }
82 + led_pwm_cleanup(priv);
83
84 return 0;
85 }