[IMPROVE] Us_manager: start/stop callbacks 87/41787/3
authorAlexander Aksenov <a.aksenov@samsung.com>
Wed, 17 Jun 2015 11:23:51 +0000 (14:23 +0300)
committerAlexander Aksenov <a.aksenov@samsung.com>
Wed, 17 Jun 2015 12:43:09 +0000 (15:43 +0300)
Change-Id: Id10bacc1f17a0d7dfcb9425483746f07c63a6730
Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
preload/preload_module.c
us_manager/Kbuild
us_manager/callbacks.c [new file with mode: 0644]
us_manager/callbacks.h [new file with mode: 0644]
us_manager/us_manager.c

index b26f116..02b0db2 100644 (file)
@@ -13,6 +13,7 @@
 #include <us_manager/sspt/sspt_file.h>
 #include <us_manager/sspt/sspt_proc.h>
 #include <us_manager/sspt/ip.h>
+#include <us_manager/callbacks.h>
 #include <writer/kernel_operations.h>
 #include <master/swap_initializer.h>
 #include <task_data/task_data.h>
@@ -53,6 +54,9 @@ enum {
 
 static enum preload_status_t __preload_status = SWAP_PRELOAD_NOT_READY;
 
+static int __preload_cbs_start_h = -1;
+static int __preload_cbs_stop_h = -1;
+
 static inline struct process_data *__get_process_data(struct uretprobe *rp)
 {
     struct process_data *pd;
@@ -372,6 +376,108 @@ static bool __should_we_preload_handlers(struct task_struct *task,
 
 
 
+enum mmap_type_t {
+       MMAP_LOADER,
+       MMAP_HANDLERS,
+       MMAP_SKIP
+};
+
+struct mmap_priv {
+       enum mmap_type_t type;
+};
+
+static inline bool check_prot(unsigned long prot)
+{
+       return !!((prot & PROT_READ) && (prot & PROT_EXEC));
+}
+
+static int mmap_entry_handler(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       struct file *file = (struct file *)swap_get_karg(regs, 0);
+       unsigned long prot = swap_get_karg(regs, 3);
+       struct mmap_priv *priv = (struct mmap_priv *)ri->data;
+       struct dentry *dentry, *loader_dentry;
+       struct bin_info *hi;
+
+       priv->type = MMAP_SKIP;
+       if (!check_prot(prot))
+               return 0;
+
+       if (!file)
+               return 0;
+       dentry = file->f_dentry;
+       if (dentry == NULL)
+               return 0;
+
+       hi = preload_storage_get_handlers_info();
+       loader_dentry = preload_debugfs_get_loader_dentry();
+       if (dentry == loader_dentry)
+               priv->type = MMAP_LOADER;
+       else if (hi->dentry != NULL && dentry == hi->dentry)
+               priv->type = MMAP_HANDLERS;
+
+       if (hi != NULL)
+               preload_storage_put_handlers_info(hi);
+
+       return 0;
+}
+
+static int mmap_ret_handler(struct kretprobe_instance *ri,
+                           struct pt_regs *regs)
+{
+       struct mmap_priv *priv = (struct mmap_priv *)ri->data;
+       struct task_struct *task = current->group_leader;
+       struct sspt_proc *proc;
+       unsigned long vaddr;
+
+       if (!task->mm)
+               return 0;
+
+       vaddr = (unsigned long)regs_return_value(regs);
+       if (IS_ERR_VALUE(vaddr))
+               return 0;
+
+       proc = sspt_proc_get_by_task(task);
+       if (!proc)
+               return 0;
+
+       switch (priv->type) {
+       case MMAP_LOADER:
+               preload_pd_set_loader_base(proc->private_data, vaddr);
+               break;
+       case MMAP_HANDLERS:
+               preload_pd_set_handlers_base(proc->private_data, vaddr);
+               break;
+       case MMAP_SKIP:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct kretprobe mmap_rp = {
+       .kp.symbol_name = "do_mmap_pgoff",
+       .data_size = sizeof(struct mmap_priv),
+       .entry_handler = mmap_entry_handler,
+       .handler = mmap_ret_handler
+};
+
+static void preload_start_cb(void)
+{
+       int res;
+
+       res = swap_register_kretprobe(&mmap_rp);
+       if (res != 0)
+               printk(KERN_ERR PRELOAD_PREFIX "Registering do_mmap_pgoff probe failed\n");
+}
+
+static void preload_stop_cb(void)
+{
+       swap_unregister_kretprobe(&mmap_rp);
+}
+
 static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs)
 {
        struct process_data *pd = __get_process_data(ri->rp);
@@ -521,86 +627,6 @@ static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs)
        return 0;
 }
 
-enum mmap_type_t {
-       MMAP_LOADER,
-       MMAP_HANDLERS,
-       MMAP_SKIP
-};
-
-struct mmap_priv {
-       enum mmap_type_t type;
-};
-
-static inline bool check_prot(unsigned long prot)
-{
-       return !!((prot & PROT_READ) && (prot & PROT_EXEC));
-}
-
-static int mmap_entry_handler(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       struct file *file = (struct file *)swap_get_karg(regs, 0);
-       unsigned long prot = swap_get_karg(regs, 3);
-       struct mmap_priv *priv = (struct mmap_priv *)ri->data;
-       struct dentry *dentry, *loader_dentry;
-       struct bin_info *hi;
-
-       priv->type = MMAP_SKIP;
-       if (!check_prot(prot))
-               return 0;
-
-       if (!file)
-               return 0;
-       dentry = file->f_dentry;
-       if (dentry == NULL)
-               return 0;
-
-       hi = preload_storage_get_handlers_info();
-       loader_dentry = preload_debugfs_get_loader_dentry();
-       if (dentry == loader_dentry)
-               priv->type = MMAP_LOADER;
-       else if (hi->dentry != NULL && dentry == hi->dentry) 
-               priv->type = MMAP_HANDLERS;
-
-       if (hi != NULL)
-               preload_storage_put_handlers_info(hi);
-
-       return 0;
-}
-
-static int mmap_ret_handler(struct kretprobe_instance *ri,
-                           struct pt_regs *regs)
-{
-       struct mmap_priv *priv = (struct mmap_priv *)ri->data;
-       struct task_struct *task = current->group_leader;
-       struct sspt_proc *proc;
-       unsigned long vaddr;
-
-       if (!task->mm)
-               return 0;
-
-       vaddr = (unsigned long)regs_return_value(regs);
-       if (IS_ERR_VALUE(vaddr))
-               return 0;
-
-       proc = sspt_proc_get_by_task(task);
-       if (!proc)
-               return 0;
-
-       switch (priv->type) {
-       case MMAP_LOADER:
-               preload_pd_set_loader_base(proc->private_data, vaddr);
-               break;
-       case MMAP_HANDLERS:
-               preload_pd_set_handlers_base(proc->private_data, vaddr);
-               break;
-       case MMAP_SKIP:
-       default:
-               break;
-       }
-
-       return 0;
-}
 
 
 static int get_caller_handler(struct kprobe *p, struct pt_regs *regs)
@@ -666,14 +692,6 @@ void preload_module_get_call_type_exit(struct us_ip *ip)
 {
 }
 
-
-static struct kretprobe mmap_rp = {
-       .kp.symbol_name = "do_mmap_pgoff",
-       .data_size = sizeof(struct mmap_priv),
-       .entry_handler = mmap_entry_handler,
-       .handler = mmap_ret_handler
-};
-
 int preload_module_uprobe_init(struct us_ip *ip)
 {
        struct uretprobe *rp = &ip->retprobe;
@@ -686,18 +704,13 @@ int preload_module_uprobe_init(struct us_ip *ip)
                        return ret;
        }
 
-       preload_pd_inc_refs(proc->private_data);
-
        rp->entry_handler = preload_us_entry;
        rp->handler = preload_us_ret;
        /* FIXME actually additional data_size is needed only when we jump
         * to dlopen */
        rp->data_size = sizeof(struct us_priv);
 
-       ret = swap_register_kretprobe(&mmap_rp);
-       if (ret == 0) {
-               return -EFAULT; /* failed to get THIS_MODULE */
-       }
+       preload_pd_inc_refs(proc->private_data);
 
        return 0;
 }
@@ -707,8 +720,6 @@ void preload_module_uprobe_exit(struct us_ip *ip)
        struct sspt_proc *proc = ip_to_proc(ip);
 
        preload_pd_dec_refs(proc->private_data);
-
-       swap_unregister_kretprobe(&mmap_rp);
 }
 
 int preload_set(void)
@@ -760,8 +771,22 @@ static int preload_module_init(void)
        if (ret)
                goto exit_threads;
 
+       __preload_cbs_start_h = us_manager_reg_cb(START_CB, preload_start_cb);
+       if (__preload_cbs_start_h < 0)
+               goto exit_start_cb;
+
+       __preload_cbs_stop_h = us_manager_reg_cb(STOP_CB, preload_stop_cb);
+       if (__preload_cbs_stop_h < 0)
+               goto exit_stop_cb;
+
        return 0;
 
+exit_stop_cb:
+       us_manager_unreg_cb(__preload_cbs_start_h);
+
+exit_start_cb:
+       unregister_preload_probes();
+
 exit_threads:
        preload_threads_exit();
 
@@ -786,6 +811,8 @@ out_err:
 
 static void preload_module_exit(void)
 {
+       us_manager_unreg_cb(__preload_cbs_start_h);
+       us_manager_unreg_cb(__preload_cbs_stop_h);
        unregister_preload_probes();
        preload_threads_exit();
        preload_control_exit();
index e4d8f9d..67707a6 100644 (file)
@@ -11,4 +11,5 @@ swap_us_manager-y := us_manager.o us_slot_manager.o helper.o debugfs_us_manager.
                      img/img_proc.o img/img_file.o img/img_ip.o \
                      probes/probes.o \
                      probes/probe_info_new.o \
-                     usm_msg.o
+                     usm_msg.o \
+                     callbacks.o
diff --git a/us_manager/callbacks.c b/us_manager/callbacks.c
new file mode 100644 (file)
index 0000000..23a8dc8
--- /dev/null
@@ -0,0 +1,139 @@
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "callbacks.h"
+
+static LIST_HEAD(cbs_list);
+static DEFINE_MUTEX(cbs_mutex);
+static int cur_handle = 0;
+
+struct cb_item {
+       struct list_head list;
+       enum callback_t type;
+       int handle;
+       void (*func)(void);
+};
+
+static inline void __lock_cbs_list(void)
+{
+       mutex_lock(&cbs_mutex);
+}
+
+static inline void __unlock_cbs_list(void)
+{
+       mutex_unlock(&cbs_mutex);
+}
+
+static inline int __get_new_handle(void)
+{
+       return cur_handle++;
+}
+
+static inline void __free_cb(struct cb_item *cb)
+{
+       list_del(&cb->list);
+       kfree(cb);
+}
+
+static struct cb_item *__get_cb_by_handle(int handle)
+{
+       struct cb_item *cb;
+
+       list_for_each_entry(cb, &cbs_list, list)
+               if (cb->handle == handle)
+                       return cb;
+
+       return NULL;
+}
+
+
+/**
+ * @brief Executes callbacks on start/stop
+ *
+ * @param cbt Callback type
+ * @return Void
+ */
+void exec_cbs(enum callback_t cbt)
+{
+       struct cb_item *cb;
+
+       __lock_cbs_list();
+
+       list_for_each_entry(cb, &cbs_list, list)
+               if (cb->type == cbt)
+                       cb->func();
+
+       __unlock_cbs_list();
+}
+
+/**
+ * @brief Removes all callbacks from list
+ *
+ * @return Void
+ */
+void remove_all_cbs(void)
+{
+       struct cb_item *cb, *n;
+
+       __lock_cbs_list();
+
+       list_for_each_entry_safe(cb, n, &cbs_list, list)
+               __free_cb(cb);
+
+       __unlock_cbs_list();
+}
+
+/**
+ * @brief Registers callback on event
+ *
+ * @param cbt Callback type
+ * @param func Callback function
+ * @return Handle on succes, error code on error
+ */
+int us_manager_reg_cb(enum callback_t cbt, void (*func)(void))
+{
+       struct cb_item *cb;
+       int handle;
+
+       cb = kmalloc(sizeof(*cb), GFP_KERNEL);
+       if (cb == NULL)
+               return -ENOMEM;
+
+       handle = __get_new_handle();
+
+       INIT_LIST_HEAD(&cb->list);
+       cb->type = cbt;
+       cb->handle = handle;
+       cb->func = func;
+
+       __lock_cbs_list();
+       list_add_tail(&cb->list, &cbs_list);
+       __unlock_cbs_list();
+
+       return handle;
+}
+EXPORT_SYMBOL_GPL(us_manager_reg_cb);
+
+/**
+ * @brief Unegisters callback by handle
+ *
+ * @param handle Callback handle
+ * @return Void
+ */
+void us_manager_unreg_cb(int handle)
+{
+       struct cb_item *cb;
+
+       __lock_cbs_list();
+
+       cb = __get_cb_by_handle(handle);
+       if (cb == NULL)
+               goto handle_not_found;
+
+       __free_cb(cb);
+
+handle_not_found:
+       __unlock_cbs_list();
+}
+EXPORT_SYMBOL_GPL(us_manager_unreg_cb);
diff --git a/us_manager/callbacks.h b/us_manager/callbacks.h
new file mode 100644 (file)
index 0000000..a952af6
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __CALLBACKS_H__
+#define __CALLBACKS_H__
+
+enum callback_t {
+       START_CB = 0,
+       STOP_CB
+};
+
+/* Gets callback type (on start or on stop) and function pointer.
+ * Returns positive callback's handle that is used to unregister on success,
+ * negative error code otherwise.
+ * Exported function. */
+int us_manager_reg_cb(enum callback_t cbt, void (*func)(void));
+
+/* Gets handle and unregisters function with this handle.
+ * Exported function. */
+void us_manager_unreg_cb(int handle);
+
+/* Used to execute callbacks when start/stop is occuring. */
+void exec_cbs(enum callback_t cbt);
+
+/* Removes all callbacks */
+void remove_all_cbs(void);
+
+#endif /* __CALLBACKS_H__ */
index a5974be..56efc67 100644 (file)
@@ -31,6 +31,7 @@
 #include "us_manager.h"
 #include "usm_msg.h"
 #include "debugfs_us_manager.h"
+#include "callbacks.h"
 #include <writer/event_filter.h>
 #include <master/swap_initializer.h>
 
@@ -41,6 +42,8 @@ static enum status_type status = ST_OFF;
 
 static void do_usm_stop(void)
 {
+       exec_cbs(STOP_CB);
+
        unregister_helper_top();
        uninstall_all();
        unregister_helper_bottom();
@@ -57,6 +60,8 @@ static int do_usm_start(void)
 
        install_all();
 
+       exec_cbs(START_CB);
+
        return 0;
 }
 
@@ -238,6 +243,8 @@ static void exit_us_manager(void)
        if (status == ST_ON)
                do_usm_stop();
 
+       remove_all_cbs();
+
        exit_us_filter();
        pin_exit();
 }