[FIX] sspt_ip usage after removing 61/66161/3
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Fri, 15 Apr 2016 12:15:43 +0000 (15:15 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Mon, 18 Apr 2016 07:18:40 +0000 (10:18 +0300)
Change-Id: I5d897ad063a31ac02e15ae4ccb9b8aca54e1fae7
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
us_manager/img/img_file.c
us_manager/img/img_ip.c
us_manager/img/img_ip.h
us_manager/sspt/sspt_file.c
us_manager/sspt/sspt_ip.c
us_manager/sspt/sspt_ip.h
us_manager/sspt/sspt_page.c
us_manager/sspt/sspt_page.h

index 377fdfb..b90ef0a 100644 (file)
@@ -68,7 +68,8 @@ static void img_file_free(struct img_file *file)
 
        list_for_each_entry_safe(ip, tmp, &file->ips.head, list) {
                img_del_ip_by_list(ip);
-               img_ip_free(ip);
+               img_ip_clean(ip);
+               img_ip_put(ip);
        }
 
        kfree(file);
@@ -174,7 +175,8 @@ int img_file_del_ip(struct img_file *file, unsigned long addr,
        img_del_ip_by_list(ip);
        mutex_unlock(&file->ips.mtx);
 
-       img_ip_free(ip);
+       img_ip_clean(ip);
+       img_ip_put(ip);
 
        return 0;
 }
index 3d99b8d..368ddb4 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "img_ip.h"
 #include <us_manager/probes/use_probes.h>
+#include <us_manager/sspt/sspt.h>
 #include <us_manager/sspt/sspt_ip.h>
 #include <linux/slab.h>
 
@@ -44,32 +45,68 @@ struct img_ip *img_ip_create(unsigned long addr, struct probe_desc *pd)
                return NULL;
 
        INIT_LIST_HEAD(&ip->list);
-       INIT_LIST_HEAD(&ip->sspt_head);
+       kref_init(&ip->ref);
+       mutex_init(&ip->sspt.mtx);
+       INIT_LIST_HEAD(&ip->sspt.head);
        ip->addr = addr;
        ip->desc = pd;
 
        return ip;
 }
 
-/**
- * @brief Remove img_ip struct
- *
- * @param ip remove object
- * @return Void
- */
-void img_ip_free(struct img_ip *ip)
+static void img_ip_release(struct kref *ref)
+{
+       struct img_ip *ip = container_of(ref, struct img_ip, ref);
+
+       WARN_ON(!list_empty(&ip->sspt.head));
+       kfree(ip);
+}
+
+void img_ip_clean(struct img_ip *ip)
 {
        struct sspt_ip *p, *n;
+       LIST_HEAD(head);
 
-       list_for_each_entry_safe(p, n, &ip->sspt_head, img_list) {
-               list_del_init(&p->img_list);
-               p->img_ip = NULL;
-               list_del(&p->list);
-               probe_info_unregister(p->desc->type, p, 1);
-               sspt_ip_free(p);
+       mutex_lock(&ip->sspt.mtx);
+       list_for_each_entry_safe(p, n, &ip->sspt.head, img_list) {
+               if (sspt_page_is_installed_ip(p->page, p))
+                       sspt_unregister_usprobe(NULL, p, US_UNREGS_PROBE);
+
+               sspt_ip_get(p);
+               list_move(&p->img_list, &head);
        }
+       mutex_unlock(&ip->sspt.mtx);
 
-       kfree(ip);
+       list_for_each_entry_safe(p, n, &head, img_list) {
+               sspt_ip_clean(p);
+               sspt_ip_put(p);
+       }
+}
+
+void img_ip_get(struct img_ip *ip)
+{
+       kref_get(&ip->ref);
+}
+
+void img_ip_put(struct img_ip *ip)
+{
+       kref_put(&ip->ref, img_ip_release);
+}
+
+void img_ip_add_ip(struct img_ip *ip, struct sspt_ip *sspt_ip)
+{
+       sspt_ip->img_ip = ip;
+       list_add(&sspt_ip->img_list, &ip->sspt.head);
+}
+
+void img_ip_lock(struct img_ip *ip)
+{
+       mutex_lock(&ip->sspt.mtx);
+}
+
+void img_ip_unlock(struct img_ip *ip)
+{
+       mutex_unlock(&ip->sspt.mtx);
 }
 
 /**
index fa57531..14c2bd3 100644 (file)
 #define _IMG_IP_H
 
 #include <linux/types.h>
-#include <us_manager/probes/probes.h>
+#include <linux/kref.h>
+
+
+struct sspt_ip;
+struct probe_desc;
 
 /**
  * @struct img_ip
@@ -37,15 +41,26 @@ struct img_ip {
        /* img_file */
        struct list_head list;          /**< List for img_file */
 
+       struct kref ref;
+
        /* sspt_ip */
-       struct list_head sspt_head;     /**< Head for sspt_ip */
+       struct {
+               struct mutex mtx;
+               struct list_head head;
+       } sspt;
 
        unsigned long addr;             /**< Function address */
        struct probe_desc *desc;        /**< Probe info */
 };
 
 struct img_ip *img_ip_create(unsigned long addr, struct probe_desc *info);
-void img_ip_free(struct img_ip *ip);
+void img_ip_clean(struct img_ip *ip);
+void img_ip_get(struct img_ip *ip);
+void img_ip_put(struct img_ip *ip);
+
+void img_ip_add_ip(struct img_ip *ip, struct sspt_ip *sspt_ip);
+void img_ip_lock(struct img_ip *ip);
+void img_ip_unlock(struct img_ip *ip);
 
 /* debug */
 void img_ip_print(struct img_ip *ip);
index c55da68..0190898 100644 (file)
@@ -124,7 +124,8 @@ void sspt_file_free(struct sspt_file *file)
                head = htable_head_by_idx(file, i);
                swap_hlist_for_each_entry_safe(page, p, n, head, hlist) {
                        hlist_del(&page->hlist);
-                       sspt_page_free(page);
+                       sspt_page_clean(page);
+                       sspt_page_put(page);
                }
        }
        up_write(&file->htable.sem);
@@ -223,12 +224,10 @@ void sspt_file_add_ip(struct sspt_file *file, struct img_ip *img_ip)
        if (!page)
                return;
 
-       /* FIXME: delete ip */
-       ip = sspt_ip_create(img_ip);
+       ip = sspt_ip_create(img_ip, page);
        if (!ip)
                return;
 
-       sspt_add_ip(page, ip);
        probe_info_init(ip->desc->type, ip);
 }
 
index b69cd21..0f0b4ff 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/list.h>
 #include <linux/module.h>
 #include "sspt_ip.h"
 #include "sspt_page.h"
@@ -39,7 +40,7 @@
  * @param page Pointer to the parent sspt_page struct
  * @return Pointer to the created us_ip struct
  */
-struct sspt_ip *sspt_ip_create(struct img_ip *img_ip)
+struct sspt_ip *sspt_ip_create(struct img_ip *img_ip, struct sspt_page *page)
 {
        struct sspt_ip *ip;
 
@@ -50,24 +51,69 @@ struct sspt_ip *sspt_ip_create(struct img_ip *img_ip)
        memset(ip, 0, sizeof(*ip));
        INIT_LIST_HEAD(&ip->list);
        INIT_LIST_HEAD(&ip->img_list);
-       ip->offset = img_ip->addr;
+       ip->offset = img_ip->addr & ~PAGE_MASK;
        ip->desc = img_ip->desc;
-       ip->img_ip = img_ip;
-       list_add(&ip->img_list, &img_ip->sspt_head);
+       atomic_set(&ip->usage, 2);      /* for 'img_ip' and 'page' */
+
+       /* add to img_ip list */
+       img_ip_get(img_ip);
+       img_ip_lock(img_ip);
+       img_ip_add_ip(img_ip, ip);
+       img_ip_unlock(img_ip);
+
+       /* add to page list */
+       sspt_page_get(page);
+       sspt_page_lock(page);
+       sspt_page_add_ip(page, ip);
+       sspt_page_unlock(page);
 
        return ip;
 }
 
-/**
- * @brief Remove us_ip struct
- *
- * @param ip remove object
- * @return Void
- */
-void sspt_ip_free(struct sspt_ip *ip)
+static void sspt_ip_free(struct sspt_ip *ip)
 {
-       if (!list_empty(&ip->img_list))
-               list_del(&ip->img_list);
+       WARN_ON(!list_empty(&ip->list) || !list_empty(&ip->img_list));
 
        kfree(ip);
 }
+
+void sspt_ip_get(struct sspt_ip *ip)
+{
+       atomic_inc(&ip->usage);
+}
+
+void sspt_ip_put(struct sspt_ip *ip)
+{
+       if (atomic_dec_and_test(&ip->usage))
+               sspt_ip_free(ip);
+}
+
+void sspt_ip_clean(struct sspt_ip *ip)
+{
+       bool put_page = false;
+       bool put_ip = false;
+
+       /* remove from page */
+       sspt_page_lock(ip->page);
+       if (!list_empty(&ip->list)) {
+               list_del_init(&ip->list);
+               put_page = true;
+       }
+       sspt_page_unlock(ip->page);
+       if (put_page) {
+               sspt_page_put(ip->page);
+               sspt_ip_put(ip);
+       }
+
+       /* remove from img_ip */
+       img_ip_lock(ip->img_ip);
+       if (!list_empty(&ip->img_list)) {
+               list_del_init(&ip->img_list);
+               put_ip = true;
+       }
+       img_ip_unlock(ip->img_ip);
+       if (put_ip) {
+               img_ip_put(ip->img_ip);
+               sspt_ip_put(ip);
+       }
+}
index 14954b8..226173e 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/list.h>
+#include <linux/atomic.h>
 #include <uprobe/swap_uprobes.h>
 #include <us_manager/probes/probes.h>
 
@@ -43,6 +44,8 @@ struct sspt_ip {
        struct img_ip *img_ip;      /**< Pointer on the img_ip (parent) */
        struct list_head img_list;  /**< For img_ip */
 
+       atomic_t usage;
+
        unsigned long orig_addr;    /**< Function address */
        unsigned long offset;       /**< Page offset */
 
@@ -55,8 +58,10 @@ struct sspt_ip {
 };
 
 
-struct sspt_ip *sspt_ip_create(struct img_ip *img_ip);
-void sspt_ip_free(struct sspt_ip *ip);
+struct sspt_ip *sspt_ip_create(struct img_ip *img_ip, struct sspt_page *page);
+void sspt_ip_clean(struct sspt_ip *ip);
+void sspt_ip_get(struct sspt_ip *ip);
+void sspt_ip_put(struct sspt_ip *ip);
 
 
 #endif /* _SSPT_IP */
index 476996b..6eed534 100644 (file)
@@ -46,42 +46,54 @@ struct sspt_page *sspt_page_create(unsigned long offset)
                INIT_LIST_HEAD(&obj->ip_list.not_inst);
                obj->offset = offset;
                obj->file = NULL;
+               kref_init(&obj->ref);
        }
 
        return obj;
 }
 
-/**
- * @brief Remove sspt_page struct
- *
- * @param page remove object
- * @return Void
- */
-void sspt_page_free(struct sspt_page *page)
+void sspt_page_clean(struct sspt_page *page)
 {
        struct sspt_ip *ip, *n;
+       LIST_HEAD(head);
 
+       mutex_lock(&page->ip_list.mtx);
+       WARN_ON(!list_empty(&page->ip_list.inst));
        list_for_each_entry_safe(ip, n, &page->ip_list.inst, list) {
-               list_del(&ip->list);
-               sspt_ip_free(ip);
+               sspt_ip_get(ip);
+               list_move(&ip->list, &head);
        }
 
        list_for_each_entry_safe(ip, n, &page->ip_list.not_inst, list) {
-               list_del(&ip->list);
-               sspt_ip_free(ip);
+               sspt_ip_get(ip);
+               list_move(&ip->list, &head);
+       }
+       mutex_unlock(&page->ip_list.mtx);
+
+       list_for_each_entry_safe(ip, n, &head, list) {
+               sspt_ip_clean(ip);
+               sspt_ip_put(ip);
        }
+}
+
+static void sspt_page_release(struct kref *ref)
+{
+       struct sspt_page *page = container_of(ref, struct sspt_page, ref);
+
+       WARN_ON(!list_empty(&page->ip_list.inst) ||
+               !list_empty(&page->ip_list.not_inst));
 
        kfree(page);
 }
 
-static void sspt_list_add_ip(struct sspt_page *page, struct sspt_ip *ip)
+void sspt_page_get(struct sspt_page *page)
 {
-       list_add(&ip->list, &page->ip_list.not_inst);
+       kref_get(&page->ref);
 }
 
-static void sspt_list_del_ip(struct sspt_ip *ip)
+void sspt_page_put(struct sspt_page *page)
 {
-       list_del(&ip->list);
+       kref_put(&page->ref, sspt_page_release);
 }
 
 /**
@@ -91,23 +103,20 @@ static void sspt_list_del_ip(struct sspt_ip *ip)
  * @param ip Pointer to the us_ip struct
  * @return Void
  */
-void sspt_add_ip(struct sspt_page *page, struct sspt_ip *ip)
+void sspt_page_add_ip(struct sspt_page *page, struct sspt_ip *ip)
 {
-       ip->offset &= ~PAGE_MASK;
        ip->page = page;
-       sspt_list_add_ip(page, ip);
+       list_add(&ip->list, &page->ip_list.not_inst);
 }
 
-/**
- * @brief Del instruction pointer from sspt_page
- *
- * @param ip Pointer to the us_ip struct
- * @return Void
- */
-void sspt_del_ip(struct sspt_ip *ip)
+void sspt_page_lock(struct sspt_page *page)
+{
+       mutex_lock(&page->ip_list.mtx);
+}
+
+void sspt_page_unlock(struct sspt_page *page)
 {
-       sspt_list_del_ip(ip);
-       sspt_ip_free(ip);
+       mutex_unlock(&page->ip_list.mtx);
 }
 
 /**
@@ -121,6 +130,18 @@ bool sspt_page_is_installed(struct sspt_page *page)
        return !list_empty(&page->ip_list.inst);
 }
 
+bool sspt_page_is_installed_ip(struct sspt_page *page, struct sspt_ip *ip)
+{
+       struct sspt_ip *p;
+
+       list_for_each_entry(p, &page->ip_list.inst, list) {
+               if (p == ip)
+                       return true;
+       }
+
+       return false;
+}
+
 /**
  * @brief Install probes on the page
  *
@@ -132,6 +153,7 @@ int sspt_register_page(struct sspt_page *page, struct sspt_file *file)
 {
        int err = 0;
        struct sspt_ip *ip, *n;
+       LIST_HEAD(not_inst_head);
 
        mutex_lock(&page->ip_list.mtx);
        if (list_empty(&page->ip_list.not_inst)) {
@@ -150,8 +172,8 @@ int sspt_register_page(struct sspt_page *page, struct sspt_file *file)
 
                err = sspt_register_usprobe(ip);
                if (err) {
-                       list_del(&ip->list);
-                       sspt_ip_free(ip);
+                       sspt_ip_get(ip);
+                       list_move(&ip->list, &not_inst_head);
                        continue;
                }
        }
@@ -161,6 +183,11 @@ int sspt_register_page(struct sspt_page *page, struct sspt_file *file)
 unlock:
        mutex_unlock(&page->ip_list.mtx);
 
+       list_for_each_entry_safe(ip, n, &not_inst_head, list) {
+               sspt_ip_clean(ip);
+               sspt_ip_put(ip);
+       }
+
        return 0;
 }
 
index 1ed8a67..bf7fa89 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/types.h>
 #include <linux/mutex.h>
+#include <linux/kref.h>
 
 struct sspt_ip;
 struct sspt_file;
@@ -49,13 +50,19 @@ struct sspt_page {
        } ip_list;
 
        unsigned long offset;                   /**< File offset */
+
+       struct kref ref;
 };
 
 struct sspt_page *sspt_page_create(unsigned long offset);
-void sspt_page_free(struct sspt_page *page);
+void sspt_page_clean(struct sspt_page *page);
+void sspt_page_get(struct sspt_page *page);
+void sspt_page_put(struct sspt_page *page);
 
-void sspt_add_ip(struct sspt_page *page, struct sspt_ip *ip);
-void sspt_del_ip(struct sspt_ip *ip);
+bool sspt_page_is_installed_ip(struct sspt_page *page, struct sspt_ip *ip);
+void sspt_page_add_ip(struct sspt_page *page, struct sspt_ip *ip);
+void sspt_page_lock(struct sspt_page *page);
+void sspt_page_unlock(struct sspt_page *page);
 
 bool sspt_page_is_installed(struct sspt_page *page);