From 85d678c0bee883c63b760b35a4104feac9018a0f Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Tue, 28 Jul 2015 18:34:36 +0100 Subject: [PATCH] greybus: loopback: make loopback code thread safe Current code allows a sysfs callback and a kernel worker thread to write all over and act upon data that could be in the process of being updated by the other. This patch adds a reasonably coarse mutex to enscure sync between the two. Signed-off-by: Bryan O'Donoghue Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/loopback.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c index 5f7c1a6..afba4225 100644 --- a/drivers/staging/greybus/loopback.c +++ b/drivers/staging/greybus/loopback.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ struct gb_loopback { u8 version_major; u8 version_minor; + struct mutex mutex; struct task_struct *task; wait_queue_head_t wq; @@ -101,10 +103,13 @@ static ssize_t field##_store(struct device *dev, \ struct gb_connection *connection = to_gb_connection(dev); \ struct gb_loopback *gb = \ (struct gb_loopback *)connection->private; \ + mutex_lock(&gb->mutex); \ ret = sscanf(buf, "%"#type, &gb->field); \ if (ret != 1) \ - return -EINVAL; \ - gb_loopback_check_attr(gb); \ + len = -EINVAL; \ + else \ + gb_loopback_check_attr(gb); \ + mutex_unlock(&gb->mutex); \ return len; \ } \ static DEVICE_ATTR_RW(field) @@ -385,6 +390,7 @@ static void gb_loopback_calculate_stats(struct gb_loopback *gb) static int gb_loopback_fn(void *data) { int error = 0; + int ms_wait; struct gb_loopback *gb = (struct gb_loopback *)data; while (1) { @@ -393,6 +399,8 @@ static int gb_loopback_fn(void *data) kthread_should_stop()); if (kthread_should_stop()) break; + + mutex_lock(&gb->mutex); if (gb->iteration_max) { if (gb->iteration_count < gb->iteration_max) { gb->iteration_count++; @@ -400,6 +408,7 @@ static int gb_loopback_fn(void *data) "iteration_count"); } else { gb->type = 0; + mutex_unlock(&gb->mutex); continue; } } @@ -412,8 +421,10 @@ static int gb_loopback_fn(void *data) if (error) gb->error++; gb_loopback_calculate_stats(gb); - if (gb->ms_wait) - msleep(gb->ms_wait); + ms_wait = gb->ms_wait; + mutex_unlock(&gb->mutex); + if (ms_wait) + msleep(ms_wait); } return 0; } @@ -448,6 +459,7 @@ static int gb_loopback_connection_init(struct gb_connection *connection) gb_loopback_reset_stats(gb); init_waitqueue_head(&gb->wq); + mutex_init(&gb->mutex); gb->task = kthread_run(gb_loopback_fn, gb, "gb_loopback"); if (IS_ERR(gb->task)) { retval = PTR_ERR(gb->task); -- 2.7.4