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);
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;
}
#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>
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);
}
/**
#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
/* 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);
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);
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);
}
*/
#include <linux/slab.h>
+#include <linux/list.h>
#include <linux/module.h>
#include "sspt_ip.h"
#include "sspt_page.h"
* @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;
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);
+ }
+}
*/
#include <linux/list.h>
+#include <linux/atomic.h>
#include <uprobe/swap_uprobes.h>
#include <us_manager/probes/probes.h>
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 */
};
-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 */
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);
}
/**
* @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);
}
/**
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
*
{
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)) {
err = sspt_register_usprobe(ip);
if (err) {
- list_del(&ip->list);
- sspt_ip_free(ip);
+ sspt_ip_get(ip);
+ list_move(&ip->list, ¬_inst_head);
continue;
}
}
unlock:
mutex_unlock(&page->ip_list.mtx);
+ list_for_each_entry_safe(ip, n, ¬_inst_head, list) {
+ sspt_ip_clean(ip);
+ sspt_ip_put(ip);
+ }
+
return 0;
}
#include <linux/types.h>
#include <linux/mutex.h>
+#include <linux/kref.h>
struct sspt_ip;
struct sspt_file;
} 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);