From: Vyacheslav Cherkashin Date: Fri, 15 Apr 2016 12:15:43 +0000 (+0300) Subject: [FIX] sspt_ip usage after removing X-Git-Tag: submit/tizen/20161124.145503~40^2~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=87e1ca7a74d7e04c72164c18785414b19046efdf;p=kernel%2Fswap-modules.git [FIX] sspt_ip usage after removing Change-Id: I5d897ad063a31ac02e15ae4ccb9b8aca54e1fae7 Signed-off-by: Vyacheslav Cherkashin --- diff --git a/us_manager/img/img_file.c b/us_manager/img/img_file.c index 377fdfb..b90ef0a 100644 --- a/us_manager/img/img_file.c +++ b/us_manager/img/img_file.c @@ -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; } diff --git a/us_manager/img/img_ip.c b/us_manager/img/img_ip.c index 3d99b8d..368ddb4 100644 --- a/us_manager/img/img_ip.c +++ b/us_manager/img/img_ip.c @@ -25,6 +25,7 @@ #include "img_ip.h" #include +#include #include #include @@ -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); } /** diff --git a/us_manager/img/img_ip.h b/us_manager/img/img_ip.h index fa57531..14c2bd3 100644 --- a/us_manager/img/img_ip.h +++ b/us_manager/img/img_ip.h @@ -27,7 +27,11 @@ #define _IMG_IP_H #include -#include +#include + + +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); diff --git a/us_manager/sspt/sspt_file.c b/us_manager/sspt/sspt_file.c index c55da68..0190898 100644 --- a/us_manager/sspt/sspt_file.c +++ b/us_manager/sspt/sspt_file.c @@ -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); } diff --git a/us_manager/sspt/sspt_ip.c b/us_manager/sspt/sspt_ip.c index b69cd21..0f0b4ff 100644 --- a/us_manager/sspt/sspt_ip.c +++ b/us_manager/sspt/sspt_ip.c @@ -23,6 +23,7 @@ */ #include +#include #include #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); + } +} diff --git a/us_manager/sspt/sspt_ip.h b/us_manager/sspt/sspt_ip.h index 14954b8..226173e 100644 --- a/us_manager/sspt/sspt_ip.h +++ b/us_manager/sspt/sspt_ip.h @@ -25,6 +25,7 @@ */ #include +#include #include #include @@ -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 */ diff --git a/us_manager/sspt/sspt_page.c b/us_manager/sspt/sspt_page.c index 476996b..6eed534 100644 --- a/us_manager/sspt/sspt_page.c +++ b/us_manager/sspt/sspt_page.c @@ -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, ¬_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, ¬_inst_head, list) { + sspt_ip_clean(ip); + sspt_ip_put(ip); + } + return 0; } diff --git a/us_manager/sspt/sspt_page.h b/us_manager/sspt/sspt_page.h index 1ed8a67..bf7fa89 100644 --- a/us_manager/sspt/sspt_page.h +++ b/us_manager/sspt/sspt_page.h @@ -26,6 +26,7 @@ #include #include +#include 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);