Skip to content

Commit d501d37

Browse files
author
William Breathitt Gray
committed
counter: 104-quad-8: Fix race getting function mode and direction
The quad8_action_read() function checks the Count function mode and Count direction without first acquiring a lock. This is a race condition because the function mode could change by the time the direction is checked. Because the quad8_function_read() already acquires a lock internally, the quad8_function_read() is refactored to spin out the no-lock code to a new quad8_function_get() function. To resolve the race condition in quad8_action_read(), a lock is acquired before calling quad8_function_get() and quad8_direction_read() in order to get both function mode and direction atomically. Fixes: f1d8a07 ("counter: 104-quad-8: Add Generic Counter interface support") Cc: [email protected] Link: https://lore.kernel.org/r/[email protected]/ Signed-off-by: William Breathitt Gray <[email protected]>
1 parent d917a62 commit d501d37

File tree

1 file changed

+42
-22
lines changed

1 file changed

+42
-22
lines changed

drivers/counter/104-quad-8.c

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -232,34 +232,45 @@ static const enum counter_function quad8_count_functions_list[] = {
232232
COUNTER_FUNCTION_QUADRATURE_X4,
233233
};
234234

235+
static int quad8_function_get(const struct quad8 *const priv, const size_t id,
236+
enum counter_function *const function)
237+
{
238+
if (!priv->quadrature_mode[id]) {
239+
*function = COUNTER_FUNCTION_PULSE_DIRECTION;
240+
return 0;
241+
}
242+
243+
switch (priv->quadrature_scale[id]) {
244+
case 0:
245+
*function = COUNTER_FUNCTION_QUADRATURE_X1_A;
246+
return 0;
247+
case 1:
248+
*function = COUNTER_FUNCTION_QUADRATURE_X2_A;
249+
return 0;
250+
case 2:
251+
*function = COUNTER_FUNCTION_QUADRATURE_X4;
252+
return 0;
253+
default:
254+
/* should never reach this path */
255+
return -EINVAL;
256+
}
257+
}
258+
235259
static int quad8_function_read(struct counter_device *counter,
236260
struct counter_count *count,
237261
enum counter_function *function)
238262
{
239263
struct quad8 *const priv = counter_priv(counter);
240-
const int id = count->id;
241264
unsigned long irqflags;
265+
int retval;
242266

243267
spin_lock_irqsave(&priv->lock, irqflags);
244268

245-
if (priv->quadrature_mode[id])
246-
switch (priv->quadrature_scale[id]) {
247-
case 0:
248-
*function = COUNTER_FUNCTION_QUADRATURE_X1_A;
249-
break;
250-
case 1:
251-
*function = COUNTER_FUNCTION_QUADRATURE_X2_A;
252-
break;
253-
case 2:
254-
*function = COUNTER_FUNCTION_QUADRATURE_X4;
255-
break;
256-
}
257-
else
258-
*function = COUNTER_FUNCTION_PULSE_DIRECTION;
269+
retval = quad8_function_get(priv, count->id, function);
259270

260271
spin_unlock_irqrestore(&priv->lock, irqflags);
261272

262-
return 0;
273+
return retval;
263274
}
264275

265276
static int quad8_function_write(struct counter_device *counter,
@@ -359,6 +370,7 @@ static int quad8_action_read(struct counter_device *counter,
359370
enum counter_synapse_action *action)
360371
{
361372
struct quad8 *const priv = counter_priv(counter);
373+
unsigned long irqflags;
362374
int err;
363375
enum counter_function function;
364376
const size_t signal_a_id = count->synapses[0].signal->id;
@@ -374,9 +386,21 @@ static int quad8_action_read(struct counter_device *counter,
374386
return 0;
375387
}
376388

377-
err = quad8_function_read(counter, count, &function);
378-
if (err)
389+
spin_lock_irqsave(&priv->lock, irqflags);
390+
391+
/* Get Count function and direction atomically */
392+
err = quad8_function_get(priv, count->id, &function);
393+
if (err) {
394+
spin_unlock_irqrestore(&priv->lock, irqflags);
395+
return err;
396+
}
397+
err = quad8_direction_read(counter, count, &direction);
398+
if (err) {
399+
spin_unlock_irqrestore(&priv->lock, irqflags);
379400
return err;
401+
}
402+
403+
spin_unlock_irqrestore(&priv->lock, irqflags);
380404

381405
/* Default action mode */
382406
*action = COUNTER_SYNAPSE_ACTION_NONE;
@@ -389,10 +413,6 @@ static int quad8_action_read(struct counter_device *counter,
389413
return 0;
390414
case COUNTER_FUNCTION_QUADRATURE_X1_A:
391415
if (synapse->signal->id == signal_a_id) {
392-
err = quad8_direction_read(counter, count, &direction);
393-
if (err)
394-
return err;
395-
396416
if (direction == COUNTER_COUNT_DIRECTION_FORWARD)
397417
*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
398418
else

0 commit comments

Comments
 (0)