Skip to content

Commit 76675f6

Browse files
feckertlag-linaro
authored andcommitted
leds: ledtrig-tty: Replace mutex with completion
With this commit, the mutex handling is replaced by the completion handling. When handling mutex, it must always be ensured that the held mutex is also released again. This is more error-prone should the number of code paths increase. This is a preparatory commit to make the trigger more configurable via additional sysfs parameters. With this change, the worker always runs and is no longer stopped if no ttyname is set. Signed-off-by: Florian Eckert <fe@dev.tdt.de> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Link: https://lore.kernel.org/r/20231127110311.3583957-3-fe@dev.tdt.de Signed-off-by: Lee Jones <lee@kernel.org>
1 parent 4ff4379 commit 76675f6

File tree

1 file changed

+30
-29
lines changed

1 file changed

+30
-29
lines changed

drivers/leds/trigger/ledtrig-tty.c

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3+
#include <linux/completion.h>
34
#include <linux/delay.h>
45
#include <linux/leds.h>
56
#include <linux/module.h>
@@ -12,30 +13,40 @@
1213
struct ledtrig_tty_data {
1314
struct led_classdev *led_cdev;
1415
struct delayed_work dwork;
15-
struct mutex mutex;
16+
struct completion sysfs;
1617
const char *ttyname;
1718
struct tty_struct *tty;
1819
int rx, tx;
1920
};
2021

21-
static void ledtrig_tty_restart(struct ledtrig_tty_data *trigger_data)
22+
static int ledtrig_tty_wait_for_completion(struct device *dev)
2223
{
23-
schedule_delayed_work(&trigger_data->dwork, 0);
24+
struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
25+
int ret;
26+
27+
ret = wait_for_completion_timeout(&trigger_data->sysfs,
28+
msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 20));
29+
if (ret == 0)
30+
return -ETIMEDOUT;
31+
32+
return ret;
2433
}
2534

2635
static ssize_t ttyname_show(struct device *dev,
2736
struct device_attribute *attr, char *buf)
2837
{
2938
struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
3039
ssize_t len = 0;
40+
int completion;
3141

32-
mutex_lock(&trigger_data->mutex);
42+
reinit_completion(&trigger_data->sysfs);
43+
completion = ledtrig_tty_wait_for_completion(dev);
44+
if (completion < 0)
45+
return completion;
3346

3447
if (trigger_data->ttyname)
3548
len = sprintf(buf, "%s\n", trigger_data->ttyname);
3649

37-
mutex_unlock(&trigger_data->mutex);
38-
3950
return len;
4051
}
4152

@@ -46,7 +57,7 @@ static ssize_t ttyname_store(struct device *dev,
4657
struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
4758
char *ttyname;
4859
ssize_t ret = size;
49-
bool running;
60+
int completion;
5061

5162
if (size > 0 && buf[size - 1] == '\n')
5263
size -= 1;
@@ -59,21 +70,17 @@ static ssize_t ttyname_store(struct device *dev,
5970
ttyname = NULL;
6071
}
6172

62-
mutex_lock(&trigger_data->mutex);
63-
64-
running = trigger_data->ttyname != NULL;
73+
reinit_completion(&trigger_data->sysfs);
74+
completion = ledtrig_tty_wait_for_completion(dev);
75+
if (completion < 0)
76+
return completion;
6577

6678
kfree(trigger_data->ttyname);
6779
tty_kref_put(trigger_data->tty);
6880
trigger_data->tty = NULL;
6981

7082
trigger_data->ttyname = ttyname;
7183

72-
mutex_unlock(&trigger_data->mutex);
73-
74-
if (ttyname && !running)
75-
ledtrig_tty_restart(trigger_data);
76-
7784
return ret;
7885
}
7986
static DEVICE_ATTR_RW(ttyname);
@@ -85,13 +92,8 @@ static void ledtrig_tty_work(struct work_struct *work)
8592
struct serial_icounter_struct icount;
8693
int ret;
8794

88-
mutex_lock(&trigger_data->mutex);
89-
90-
if (!trigger_data->ttyname) {
91-
/* exit without rescheduling */
92-
mutex_unlock(&trigger_data->mutex);
93-
return;
94-
}
95+
if (!trigger_data->ttyname)
96+
goto out;
9597

9698
/* try to get the tty corresponding to $ttyname */
9799
if (!trigger_data->tty) {
@@ -116,11 +118,8 @@ static void ledtrig_tty_work(struct work_struct *work)
116118
}
117119

118120
ret = tty_get_icount(trigger_data->tty, &icount);
119-
if (ret) {
120-
dev_info(trigger_data->tty->dev, "Failed to get icount, stopped polling\n");
121-
mutex_unlock(&trigger_data->mutex);
122-
return;
123-
}
121+
if (ret)
122+
goto out;
124123

125124
if (icount.rx != trigger_data->rx ||
126125
icount.tx != trigger_data->tx) {
@@ -134,7 +133,7 @@ static void ledtrig_tty_work(struct work_struct *work)
134133
}
135134

136135
out:
137-
mutex_unlock(&trigger_data->mutex);
136+
complete_all(&trigger_data->sysfs);
138137
schedule_delayed_work(&trigger_data->dwork,
139138
msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2));
140139
}
@@ -157,7 +156,9 @@ static int ledtrig_tty_activate(struct led_classdev *led_cdev)
157156

158157
INIT_DELAYED_WORK(&trigger_data->dwork, ledtrig_tty_work);
159158
trigger_data->led_cdev = led_cdev;
160-
mutex_init(&trigger_data->mutex);
159+
init_completion(&trigger_data->sysfs);
160+
161+
schedule_delayed_work(&trigger_data->dwork, 0);
161162

162163
return 0;
163164
}

0 commit comments

Comments
 (0)