diff options
author | Hans de Goede <hdegoede@redhat.com> | 2012-05-22 05:40:26 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2012-05-30 01:55:23 -0400 |
commit | f4e9c82f64b524314a390b13d3ba7d483f09258f (patch) | |
tree | 82d688ae7782234dc01c6a340596bac21531aae4 /drivers/watchdog/watchdog_dev.c | |
parent | 7a87982420e5e126bfefeb42232d1fd92052794e (diff) |
watchdog: Add Locking support
This patch fixes some potential multithreading issues, despite only
allowing one process to open the /dev/watchdog device, we can still get
called multiple times at the same time, since a program could be using thread,
or could share the fd after a fork.
This causes 2 potential problems:
1) watchdog_start / open do an unlocked test_n_set / test_n_clear,
if these 2 race, the watchdog could be stopped while the active
bit indicates it is running or visa versa.
2) Most watchdog_dev drivers probably assume that only one
watchdog-op will get called at a time, this is not necessary
true atm.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog/watchdog_dev.c')
-rw-r--r-- | drivers/watchdog/watchdog_dev.c | 21 |
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 76d2572fed25..4d295d229a07 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c | |||
@@ -63,6 +63,8 @@ static int watchdog_ping(struct watchdog_device *wddev) | |||
63 | { | 63 | { |
64 | int err = 0; | 64 | int err = 0; |
65 | 65 | ||
66 | mutex_lock(&wddev->lock); | ||
67 | |||
66 | if (!watchdog_active(wddev)) | 68 | if (!watchdog_active(wddev)) |
67 | goto out_ping; | 69 | goto out_ping; |
68 | 70 | ||
@@ -72,6 +74,7 @@ static int watchdog_ping(struct watchdog_device *wddev) | |||
72 | err = wddev->ops->start(wddev); /* restart watchdog */ | 74 | err = wddev->ops->start(wddev); /* restart watchdog */ |
73 | 75 | ||
74 | out_ping: | 76 | out_ping: |
77 | mutex_unlock(&wddev->lock); | ||
75 | return err; | 78 | return err; |
76 | } | 79 | } |
77 | 80 | ||
@@ -88,6 +91,8 @@ static int watchdog_start(struct watchdog_device *wddev) | |||
88 | { | 91 | { |
89 | int err = 0; | 92 | int err = 0; |
90 | 93 | ||
94 | mutex_lock(&wddev->lock); | ||
95 | |||
91 | if (watchdog_active(wddev)) | 96 | if (watchdog_active(wddev)) |
92 | goto out_start; | 97 | goto out_start; |
93 | 98 | ||
@@ -96,6 +101,7 @@ static int watchdog_start(struct watchdog_device *wddev) | |||
96 | set_bit(WDOG_ACTIVE, &wddev->status); | 101 | set_bit(WDOG_ACTIVE, &wddev->status); |
97 | 102 | ||
98 | out_start: | 103 | out_start: |
104 | mutex_unlock(&wddev->lock); | ||
99 | return err; | 105 | return err; |
100 | } | 106 | } |
101 | 107 | ||
@@ -113,6 +119,8 @@ static int watchdog_stop(struct watchdog_device *wddev) | |||
113 | { | 119 | { |
114 | int err = 0; | 120 | int err = 0; |
115 | 121 | ||
122 | mutex_lock(&wddev->lock); | ||
123 | |||
116 | if (!watchdog_active(wddev)) | 124 | if (!watchdog_active(wddev)) |
117 | goto out_stop; | 125 | goto out_stop; |
118 | 126 | ||
@@ -127,6 +135,7 @@ static int watchdog_stop(struct watchdog_device *wddev) | |||
127 | clear_bit(WDOG_ACTIVE, &wddev->status); | 135 | clear_bit(WDOG_ACTIVE, &wddev->status); |
128 | 136 | ||
129 | out_stop: | 137 | out_stop: |
138 | mutex_unlock(&wddev->lock); | ||
130 | return err; | 139 | return err; |
131 | } | 140 | } |
132 | 141 | ||
@@ -147,8 +156,11 @@ static int watchdog_get_status(struct watchdog_device *wddev, | |||
147 | if (!wddev->ops->status) | 156 | if (!wddev->ops->status) |
148 | return -EOPNOTSUPP; | 157 | return -EOPNOTSUPP; |
149 | 158 | ||
159 | mutex_lock(&wddev->lock); | ||
160 | |||
150 | *status = wddev->ops->status(wddev); | 161 | *status = wddev->ops->status(wddev); |
151 | 162 | ||
163 | mutex_unlock(&wddev->lock); | ||
152 | return err; | 164 | return err; |
153 | } | 165 | } |
154 | 166 | ||
@@ -171,8 +183,11 @@ static int watchdog_set_timeout(struct watchdog_device *wddev, | |||
171 | (timeout < wddev->min_timeout || timeout > wddev->max_timeout)) | 183 | (timeout < wddev->min_timeout || timeout > wddev->max_timeout)) |
172 | return -EINVAL; | 184 | return -EINVAL; |
173 | 185 | ||
186 | mutex_lock(&wddev->lock); | ||
187 | |||
174 | err = wddev->ops->set_timeout(wddev, timeout); | 188 | err = wddev->ops->set_timeout(wddev, timeout); |
175 | 189 | ||
190 | mutex_unlock(&wddev->lock); | ||
176 | return err; | 191 | return err; |
177 | } | 192 | } |
178 | 193 | ||
@@ -193,8 +208,11 @@ static int watchdog_get_timeleft(struct watchdog_device *wddev, | |||
193 | if (!wddev->ops->get_timeleft) | 208 | if (!wddev->ops->get_timeleft) |
194 | return -EOPNOTSUPP; | 209 | return -EOPNOTSUPP; |
195 | 210 | ||
211 | mutex_lock(&wddev->lock); | ||
212 | |||
196 | *timeleft = wddev->ops->get_timeleft(wddev); | 213 | *timeleft = wddev->ops->get_timeleft(wddev); |
197 | 214 | ||
215 | mutex_unlock(&wddev->lock); | ||
198 | return err; | 216 | return err; |
199 | } | 217 | } |
200 | 218 | ||
@@ -213,8 +231,11 @@ static int watchdog_ioctl_op(struct watchdog_device *wddev, unsigned int cmd, | |||
213 | if (!wddev->ops->ioctl) | 231 | if (!wddev->ops->ioctl) |
214 | return -ENOIOCTLCMD; | 232 | return -ENOIOCTLCMD; |
215 | 233 | ||
234 | mutex_lock(&wddev->lock); | ||
235 | |||
216 | err = wddev->ops->ioctl(wddev, cmd, arg); | 236 | err = wddev->ops->ioctl(wddev, cmd, arg); |
217 | 237 | ||
238 | mutex_unlock(&wddev->lock); | ||
218 | return err; | 239 | return err; |
219 | } | 240 | } |
220 | 241 | ||