[FIX] put_pf_group() implement 43/39943/1
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 26 May 2015 15:50:11 +0000 (18:50 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 26 May 2015 17:01:55 +0000 (20:01 +0300)
Change-Id: Ia720edadc41860bcbccc75d0e1cd23a074700580
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
parser/msg_cmd.c
parser/swap_msg_parser.c
parser/us_inst.c
parser/us_inst.h
us_manager/pf/pf_group.c
webprobe/webprobe_prof.c

index 5d6f01c..352e757 100644 (file)
@@ -133,6 +133,8 @@ int msg_stop(struct msg_buf *mb)
        if (ret)
                return ret;
 
+       pfg_put_all();
+
        conf.use_features0 = 0;
        conf.use_features1 = 0;
        ret = set_config(&conf);
index 412dac7..453d9f5 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/uaccess.h>
 
 #include "parser_defs.h"
+#include "us_inst.h"
 #include "msg_buf.h"
 #include "msg_cmd.h"
 #include "cpu_ctrl.h"
@@ -163,6 +164,7 @@ static int reg_msg_handler(void)
 static void unreg_msg_handler(void)
 {
        set_msg_handler(NULL);
+       pfg_put_all();
 }
 
 static int once(void)
index 4bf143e..bb40481 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/errno.h>
 #include "us_inst.h"
 
 
+struct pfg_item {
+       struct list_head list;
+       struct pf_group *pfg;
+};
+
+
+static LIST_HEAD(pfg_item_list);
+static DEFINE_SPINLOCK(pfg_item_lock);
+
+
+static struct pfg_item *pfg_item_create(struct pf_group *pfg)
+{
+       struct pfg_item *item;
+
+       item = kmalloc(sizeof(*item), GFP_KERNEL);
+       if (item) {
+               INIT_LIST_HEAD(&item->list);
+               item->pfg = pfg;
+       }
+
+       return item;
+}
+
+static void pfg_item_free(struct pfg_item *item)
+{
+       kfree(item);
+}
+
+/* called with pfg_item_lock held */
+static bool pfg_check(struct pf_group *pfg)
+{
+       struct pfg_item *item;
+
+       list_for_each_entry(item, &pfg_item_list, list) {
+               if (item->pfg == pfg)
+                       return true;
+       }
+
+       return false;
+}
+
+static int pfg_add(struct pf_group *pfg)
+{
+       bool already;
+
+       spin_lock(&pfg_item_lock);
+       already = pfg_check(pfg);
+       spin_unlock(&pfg_item_lock);
+
+       if (already) {
+               put_pf_group(pfg);
+       } else {
+               struct pfg_item *item;
+
+               item = pfg_item_create(pfg);
+               if (item == NULL)
+                       return -ENOMEM;
+
+               spin_lock(&pfg_item_lock);
+               list_add(&item->list, &pfg_item_list);
+               spin_unlock(&pfg_item_lock);
+       }
+
+       return 0;
+}
+
+void pfg_put_all(void)
+{
+       LIST_HEAD(tmp_list);
+       struct pfg_item *item, *n;
+
+       spin_lock(&pfg_item_lock);
+       list_splice_init(&pfg_item_list, &tmp_list);
+       spin_unlock(&pfg_item_lock);
+
+       list_for_each_entry_safe(item, n, &tmp_list, list) {
+               list_del(&item->list);
+               put_pf_group(item->pfg);
+               pfg_item_free(item);
+       }
+}
+
 static int mod_func_inst(struct func_inst_data *func, struct pf_group *pfg,
                         struct dentry *dentry, enum MOD_TYPE mt)
 {
@@ -130,6 +213,13 @@ static int mod_us_app_inst(struct app_inst_data *app_inst, enum MOD_TYPE mt)
                return ret;
        }
 
+       ret = pfg_add(pfg);
+       if (ret) {
+               put_pf_group(pfg);
+               printk(KERN_INFO "Cannot pfg_add, ret=%d\n", ret);
+               return ret;
+       }
+
        for (i = 0; i < app_inst->cnt_func; ++i) {
                /* TODO: */
                dentry = dentry_by_path(app_inst->app_info->exec_path);
index 9b430bc..e3fc6bc 100644 (file)
@@ -42,5 +42,6 @@ enum MOD_TYPE {
 struct us_inst_data;
 
 int mod_us_inst(struct us_inst_data *us_inst, enum MOD_TYPE mt);
+void pfg_put_all(void);
 
 #endif /* _US_INST_H */
index 9b3e7e3..349e8c3 100644 (file)
@@ -40,6 +40,7 @@ struct pf_group {
        struct list_head list;
        struct img_proc *i_proc;
        struct proc_filter filter;
+       atomic_t usage;
 
        /* TODO: proc_list*/
        struct list_head proc_list;
@@ -51,6 +52,7 @@ struct pl_struct {
 };
 
 static LIST_HEAD(pfg_list);
+static DEFINE_RWLOCK(pfg_list_lock);
 
 /* struct pl_struct */
 static struct pl_struct *create_pl_struct(struct sspt_proc *proc)
@@ -148,6 +150,7 @@ static struct pf_group *create_pfg(void)
        INIT_LIST_HEAD(&pfg->list);
        memset(&pfg->filter, 0, sizeof(pfg->filter));
        INIT_LIST_HEAD(&pfg->proc_list);
+       atomic_set(&pfg->usage, 1);
 
        return pfg;
 
@@ -169,11 +172,13 @@ static void free_pfg(struct pf_group *pfg)
        kfree(pfg);
 }
 
+/* called with pfg_list_lock held */
 static void add_pfg_by_list(struct pf_group *pfg)
 {
        list_add(&pfg->list, &pfg_list);
 }
 
+/* called with pfg_list_lock held */
 static void del_pfg_by_list(struct pf_group *pfg)
 {
        list_del(&pfg->list);
@@ -251,19 +256,24 @@ struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv)
 {
        struct pf_group *pfg;
 
+       write_lock(&pfg_list_lock);
        list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_pf_by_dentry(&pfg->filter, dentry))
-                       return pfg;
+               if (check_pf_by_dentry(&pfg->filter, dentry)) {
+                       atomic_inc(&pfg->usage);
+                       goto unlock;
+               }
        }
 
        pfg = create_pfg();
        if (pfg == NULL)
-               return NULL;
+               goto unlock;
 
        set_pf_by_dentry(&pfg->filter, dentry, priv);
 
        add_pfg_by_list(pfg);
 
+unlock:
+       write_unlock(&pfg_list_lock);
        return pfg;
 }
 EXPORT_SYMBOL_GPL(get_pf_group_by_dentry);
@@ -279,19 +289,24 @@ struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv)
 {
        struct pf_group *pfg;
 
+       write_lock(&pfg_list_lock);
        list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_pf_by_tgid(&pfg->filter, tgid))
-                       return pfg;
+               if (check_pf_by_tgid(&pfg->filter, tgid)) {
+                       atomic_inc(&pfg->usage);
+                       goto unlock;
+               }
        }
 
        pfg = create_pfg();
        if (pfg == NULL)
-               return NULL;
+               goto unlock;
 
        set_pf_by_tgid(&pfg->filter, tgid, priv);
 
        add_pfg_by_list(pfg);
 
+unlock:
+       write_unlock(&pfg_list_lock);
        return pfg;
 }
 EXPORT_SYMBOL_GPL(get_pf_group_by_tgid);
@@ -308,24 +323,29 @@ struct pf_group *get_pf_group_by_comm(char *comm, void *priv)
        int ret;
        struct pf_group *pfg;
 
+       write_lock(&pfg_list_lock);
        list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_pf_by_comm(&pfg->filter, comm))
-                       return pfg;
+               if (check_pf_by_comm(&pfg->filter, comm)) {
+                       atomic_inc(&pfg->usage);
+                       goto unlock;
+               }
        }
 
        pfg = create_pfg();
        if (pfg == NULL)
-               return NULL;
+               goto unlock;
 
        ret = set_pf_by_comm(&pfg->filter, comm, priv);
        if (ret) {
                printk(KERN_ERR "ERROR: set_pf_by_comm, ret=%d\n", ret);
                free_pfg(pfg);
-               return NULL;
+               pfg = NULL;
+               goto unlock;
        }
 
        add_pfg_by_list(pfg);
-
+unlock:
+       write_unlock(&pfg_list_lock);
        return pfg;
 }
 EXPORT_SYMBOL_GPL(get_pf_group_by_comm);
@@ -340,19 +360,24 @@ struct pf_group *get_pf_group_dumb(void *priv)
 {
        struct pf_group *pfg;
 
+       write_lock(&pfg_list_lock);
        list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_pf_dumb(&pfg->filter))
-                       return pfg;
+               if (check_pf_dumb(&pfg->filter)) {
+                       atomic_inc(&pfg->usage);
+                       goto unlock;
+               }
        }
 
        pfg = create_pfg();
        if (pfg == NULL)
-               return NULL;
+               goto unlock;
 
        set_pf_dumb(&pfg->filter, priv);
 
        add_pfg_by_list(pfg);
 
+unlock:
+       write_unlock(&pfg_list_lock);
        return pfg;
 }
 EXPORT_SYMBOL_GPL(get_pf_group_dumb);
@@ -365,7 +390,13 @@ EXPORT_SYMBOL_GPL(get_pf_group_dumb);
  */
 void put_pf_group(struct pf_group *pfg)
 {
+       if (atomic_dec_and_test(&pfg->usage)) {
+               write_lock(&pfg_list_lock);
+               del_pfg_by_list(pfg);
+               write_unlock(&pfg_list_lock);
 
+               free_pfg(pfg);
+       }
 }
 
 /**
@@ -411,10 +442,12 @@ int check_task_on_filters(struct task_struct *task)
 {
        struct pf_group *pfg;
 
+       read_lock(&pfg_list_lock);
        list_for_each_entry(pfg, &pfg_list, list) {
                if (check_task_f(&pfg->filter, task))
                        return 1;
        }
+       read_unlock(&pfg_list_lock);
 
        return 0;
 }
@@ -430,6 +463,7 @@ void check_task_and_install(struct task_struct *task)
        struct pf_group *pfg;
        struct sspt_proc *proc = NULL;
 
+       read_lock(&pfg_list_lock);
        list_for_each_entry(pfg, &pfg_list, list) {
                if (check_task_f(&pfg->filter, task) == NULL)
                        continue;
@@ -443,7 +477,8 @@ void check_task_and_install(struct task_struct *task)
                                printk(KERN_ERR "SWAP US_MANAGER: Error! Trying"
                                                " to first install filter that "
                                                "already exists in proc!\n");
-                               return;
+                               proc = NULL;
+                               goto unlock;
                        }
                        break;
                }
@@ -454,6 +489,9 @@ void check_task_and_install(struct task_struct *task)
                }
        }
 
+unlock:
+       read_unlock(&pfg_list_lock);
+
        if (proc)
                first_install(task, proc, pfg);
 }
@@ -470,6 +508,7 @@ void call_page_fault(struct task_struct *task, unsigned long page_addr)
        struct pf_group *pfg, *pfg_first = NULL;
        struct sspt_proc *proc = NULL;
 
+       read_lock(&pfg_list_lock);
        list_for_each_entry(pfg, &pfg_list, list) {
                if ((check_task_f(&pfg->filter, task) == NULL))
                        continue;
@@ -489,6 +528,7 @@ void call_page_fault(struct task_struct *task, unsigned long page_addr)
                        break;
                }
        }
+       read_unlock(&pfg_list_lock);
 
        if (proc) {
                if (pfg_first)
@@ -512,6 +552,7 @@ void uninstall_proc(struct sspt_proc *proc)
        struct pf_group *pfg;
        struct pl_struct *pls;
 
+       read_lock(&pfg_list_lock);
        list_for_each_entry(pfg, &pfg_list, list) {
                pls = find_pl_struct(pfg, task);
                if (pls) {
@@ -519,6 +560,7 @@ void uninstall_proc(struct sspt_proc *proc)
                        free_pl_struct(pls);
                }
        }
+       read_unlock(&pfg_list_lock);
 
        task_lock(task);
        BUG_ON(task->mm == NULL);
@@ -588,16 +630,6 @@ void install_all(void)
 #endif /* CONFIG_ARM */
 }
 
-static void clean_pfg(void)
-{
-       struct pf_group *pfg, *n;
-
-       list_for_each_entry_safe(pfg, n, &pfg_list, list) {
-               del_pfg_by_list(pfg);
-               free_pfg(pfg);
-       }
-}
-
 static void on_each_uninstall_proc(struct sspt_proc *proc, void *data)
 {
        uninstall_proc(proc);
@@ -613,8 +645,6 @@ void uninstall_all(void)
        sspt_proc_write_lock();
        on_each_proc_no_lock(on_each_uninstall_proc, NULL);
        sspt_proc_write_unlock();
-
-       clean_pfg();
 }
 
 /**
index 1c325b2..897427a 100644 (file)
@@ -127,6 +127,9 @@ int web_prof_data_set(char *app_path, char *app_id)
        if (web_data->lib_dentry == NULL)
                return -EFAULT;
 
+       if (web_data->pfg)
+               put_pf_group(web_data->pfg);
+
        web_data->pfg = get_pf_group_by_comm(app_id, web_data->app_dentry);
        if (web_data->pfg == NULL)
                return -EFAULT;
@@ -212,5 +215,8 @@ int web_prof_init(void)
 
 void web_prof_exit(void)
 {
+       if (web_data->pfg)
+               put_pf_group(web_data->pfg);
+
        kfree(web_data);
 }