Module: xenomai-jki
Branch: for-forge
Commit: 3aa24e314c81d52d8d2e00ce05da9c0e18a698d2
URL:    
http://git.xenomai.org/?p=xenomai-jki.git;a=commit;h=3aa24e314c81d52d8d2e00ce05da9c0e18a698d2

Author: Jan Kiszka <jan.kis...@siemens.com>
Date:   Fri Jun 17 17:41:37 2016 +0200

cobalt/autotune: Rework autotune_ioctl_nrt/rt for more robust request handling

Do not trigger any activity before a correct request has been
identified, do not copy data from user space as well. Account for races
between parallel IOCTL calls on the same device when changing or using
the tuner reference.

Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>

---

 kernel/drivers/autotune/autotune.c |   72 +++++++++++++++++++++++++-----------
 1 file changed, 51 insertions(+), 21 deletions(-)

diff --git a/kernel/drivers/autotune/autotune.c 
b/kernel/drivers/autotune/autotune.c
index 1d18163..8a0db39 100644
--- a/kernel/drivers/autotune/autotune.c
+++ b/kernel/drivers/autotune/autotune.c
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
+#include <linux/atomic.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
@@ -71,6 +72,7 @@ struct gravity_tuner {
        int quiet;
        struct tuning_score scores[AUTOTUNE_STEPS];
        int nscores;
+       atomic_t refcount;
 };
 
 struct irq_gravity_tuner {
@@ -95,12 +97,14 @@ struct uthread_gravity_tuner {
 struct autotune_context {
        struct gravity_tuner *tuner;
        struct autotune_setup setup;
+       rtdm_lock_t tuner_lock;
 };
 
 static inline void init_tuner(struct gravity_tuner *tuner)
 {
        rtdm_event_init(&tuner->done, 0);
        tuner->status = 0;
+       atomic_set(&tuner->refcount, 0);
 }
 
 static inline void destroy_tuner(struct gravity_tuner *tuner)
@@ -633,28 +637,14 @@ static int autotune_ioctl_nrt(struct rtdm_fd *fd, 
unsigned int request, void *ar
 {
        struct autotune_context *context;
        struct autotune_setup setup;
-       struct gravity_tuner *tuner;
+       struct gravity_tuner *tuner, *old_tuner;
+       rtdm_lockctx_t lock_ctx;
        int period, ret;
 
-       if (request == AUTOTUNE_RTIOC_RESET) {
+       switch (request) {
+       case AUTOTUNE_RTIOC_RESET:
                xnclock_reset_gravity(&nkclock);
                return 0;
-       }
-
-       ret = rtdm_copy_from_user(fd, &setup, arg, sizeof(setup));
-       if (ret)
-               return ret;
-
-       context = rtdm_fd_to_private(fd);
-
-       /* Clear previous tuner. */
-       tuner = context->tuner;
-       if (tuner) {
-               tuner->destroy_tuner(tuner);
-               context->tuner = NULL;
-       }
-
-       switch (request) {
        case AUTOTUNE_RTIOC_IRQ:
                tuner = &irq_tuner.tuner;
                break;
@@ -668,6 +658,10 @@ static int autotune_ioctl_nrt(struct rtdm_fd *fd, unsigned 
int request, void *ar
                return -EINVAL;
        }
 
+       ret = rtdm_copy_from_user(fd, &setup, arg, sizeof(setup));
+       if (ret)
+               return ret;
+
        ret = rtdm_safe_copy_from_user(fd, &period, arg, sizeof(period));
        if (ret)
                return ret;
@@ -676,9 +670,31 @@ static int autotune_ioctl_nrt(struct rtdm_fd *fd, unsigned 
int request, void *ar
        if (ret)
                return ret;
 
+       context = rtdm_fd_to_private(fd);
+
+       rtdm_lock_get_irqsave(&context->tuner_lock, lock_ctx);
+
+       old_tuner = context->tuner;
+       if (old_tuner) {
+               if (atomic_read(&old_tuner->refcount) > 0) {
+                       rtdm_lock_put_irqrestore(&context->tuner_lock,
+                                                lock_ctx);
+                       tuner->destroy_tuner(tuner);
+                       return -EBUSY;
+               }
+
+               /* Clear previous tuner. */
+               context->tuner = NULL;
+       }
+
        context->tuner = tuner;
        context->setup = setup;
 
+       rtdm_lock_put_irqrestore(&context->tuner_lock, lock_ctx);
+
+       if (old_tuner)
+               old_tuner->destroy_tuner(old_tuner);
+
        if (setup.quiet <= 1)
                printk(XENO_INFO "autotune(%s) started\n", tuner->name);
 
@@ -689,12 +705,21 @@ static int autotune_ioctl_rt(struct rtdm_fd *fd, unsigned 
int request, void *arg
 {
        struct autotune_context *context;
        struct gravity_tuner *tuner;
+       rtdm_lockctx_t lock_ctx;
        __u64 timestamp;
        __u32 gravity;
        int ret;
 
        context = rtdm_fd_to_private(fd);
+
+       rtdm_lock_get_irqsave(&context->tuner_lock, lock_ctx);
+
        tuner = context->tuner;
+       if (tuner)
+               atomic_inc(&tuner->refcount);
+
+       rtdm_lock_put_irqrestore(&context->tuner_lock, lock_ctx);
+
        if (tuner == NULL)
                return -ENOSYS;
 
@@ -710,18 +735,22 @@ static int autotune_ioctl_rt(struct rtdm_fd *fd, unsigned 
int request, void *arg
                                             sizeof(gravity));
                break;
        case AUTOTUNE_RTIOC_PULSE:
-               if (tuner != &uthread_tuner.tuner)
-                       return -EINVAL;
+               if (tuner != &uthread_tuner.tuner) {
+                       ret = -EINVAL;
+                       break;
+               }
                ret = rtdm_safe_copy_from_user(fd, &timestamp, arg,
                                               sizeof(timestamp));
                if (ret)
-                       return ret;
+                       break;
                ret = add_uthread_sample(tuner, timestamp);
                break;
        default:
                ret = -ENOSYS;
        }
 
+       atomic_dec(&tuner->refcount);
+
        return ret;
 }
 
@@ -731,6 +760,7 @@ static int autotune_open(struct rtdm_fd *fd, int oflags)
 
        context = rtdm_fd_to_private(fd);
        context->tuner = NULL;
+       rtdm_lock_init(&context->tuner_lock);
 
        return 0;
 }


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to