[FIX] RCU waiting after removing each syscall
authorAlexander Aksenov <a.aksenov@samsung.com>
Wed, 11 Dec 2013 09:17:34 +0000 (13:17 +0400)
committerNikita Kalyazin <n.kalyazin@samsung.com>
Tue, 21 Jan 2014 11:04:23 +0000 (03:04 -0800)
Now we do synchronize_sched only once, after all syscalls from syscall
group were removed.

Change-Id: Ib8b86460ed8485499d7085aaec381139bcac840f
Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
ks_features/ks_features.c

index 4ce55de..8af0d36 100644 (file)
@@ -24,6 +24,8 @@
 
 
 #include <linux/module.h>
+#include <linux/slab.h>
+
 #include <asm/errno.h>
 #include <ksyms/ksyms.h>
 #include <kprobe/dbi_kprobes.h>
@@ -229,6 +231,7 @@ static int register_syscall(size_t id)
        return ret;
 }
 
+
 static int unregister_syscall(size_t id)
 {
        printk("unregister_syscall: %s\n", get_sys_name(id));
@@ -241,6 +244,42 @@ static int unregister_syscall(size_t id)
        return 0;
 }
 
+static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
+{
+       struct kretprobe **rpp;
+       const size_t end = ((size_t) 0) - 1;
+       size_t i = 0, id;
+       int ret = 0;
+
+       if (cnt == 1)
+               return unregister_syscall(id_p[0]);
+
+       --cnt;
+
+       rpp = kmalloc(GFP_KERNEL, sizeof(&(((struct ks_probe *) 0)->rp)) * cnt);
+       if (rpp == NULL) {
+               for (; cnt != end; --cnt) {
+                       ret = unregister_syscall(id_p[cnt]);
+                       if (ret)
+                               return ret;
+        }
+               return ret;
+       }
+
+       for (; cnt != end; --cnt) {
+               id = id_p[cnt];
+               if (ksp[id].rp.kp.addr != NULL) {
+                               rpp[i] = &ksp[id].rp;
+                               ++i;
+               }
+       }
+
+       dbi_unregister_kretprobes(rpp, i);
+       kfree(rpp);
+
+       return 0;
+}
+
 static void set_pst(struct feature *f, size_t id)
 {
        ksp[id].sub_type |= f->sub_type;
@@ -254,30 +293,45 @@ static void unset_pst(struct feature *f, size_t id)
 static void do_uninstall_features(struct feature *f, size_t i)
 {
        int ret;
+       size_t *id_p;
        size_t id;
+       size_t cnt = 0;
        const size_t end = ((size_t) 0) - 1;
 
+       id_p = kmalloc(GFP_KERNEL, sizeof(id) * (i + 1));
+       /* NULL check is below in loop */
+
        for (; i != end; --i) {
                id = f->feature_list[i];
 
                if (get_counter(id) == 0) {
                        printk("syscall %s not installed\n",
                               get_sys_name(id));
+                       kfree(id_p);
                        BUG();
                }
 
                dec_counter(id);
 
                if (get_counter(id) == 0) {
-                       ret = unregister_syscall(id);
-                       if (ret)
-                               printk("syscall %s uninstall error, ret=%d\n",
-                                      get_sys_name(id), ret);
-
+                       if (id_p != NULL) {
+                               id_p[cnt] = id;
+                               ++cnt;
+                       } else {
+                               ret = unregister_syscall(id);
+                               if (ret)
+                                       printk("syscall %s uninstall error, ret=%d\n",
+                                                  get_sys_name(id), ret);
+                       }
                }
 
                unset_pst(f, id);
        }
+
+       if (id_p != NULL) {
+               unregister_multiple_syscalls(id_p, cnt);
+               kfree(id_p);
+       }
 }
 
 static int do_install_features(struct feature *f)
@@ -337,12 +391,11 @@ static int uninstall_features(struct feature *f)
                ret = -EINVAL;
                goto unlock;
        }
-
        do_uninstall_features(f, f->cnt - 1);
-
        f->enable = 0;
 unlock:
        mutex_unlock(&mutex_features);
+
        return ret;
 }