From ce7a3de04d7b16bbbdb76efc57906a845d9e581d Mon Sep 17 00:00:00 2001 From: Anatolii Nikulin Date: Thu, 26 Nov 2015 15:47:42 +0300 Subject: [FIX] deadlock in img_proc_del_ip() Now we use reference count for proc objects to avoid deadlock Change-Id: I4c0b9359375fbddc85145bbe46cfe42f4929c188 Signed-off-by: Anatolii Nikulin --- us_manager/img/img_file.c | 19 +++++++++++++-- us_manager/img/img_file.h | 6 +++-- us_manager/img/img_proc.c | 61 +++++++++++++++++++++++++---------------------- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/us_manager/img/img_file.c b/us_manager/img/img_file.c index ec4903c4..978a78d9 100644 --- a/us_manager/img/img_file.c +++ b/us_manager/img/img_file.c @@ -37,7 +37,7 @@ static void img_del_ip_by_list(struct img_ip *ip); * @param dentry Dentry of file * @return Pointer to the created img_file struct */ -struct img_file *create_img_file(struct dentry *dentry) +struct img_file *img_file_create(struct dentry *dentry) { struct img_file *file; @@ -50,6 +50,7 @@ struct img_file *create_img_file(struct dentry *dentry) file->dentry = dentry; INIT_LIST_HEAD(&file->ip_list); INIT_LIST_HEAD(&file->list); + atomic_set(&file->use, 1); return file; } @@ -60,7 +61,7 @@ struct img_file *create_img_file(struct dentry *dentry) * @param file remove object * @return Void */ -void free_img_file(struct img_file *file) +static void img_file_free(struct img_file *file) { struct img_ip *ip, *tmp; @@ -82,6 +83,20 @@ static void img_del_ip_by_list(struct img_ip *ip) list_del(&ip->list); } +void img_file_get(struct img_file *file) +{ + WARN_ON(!atomic_read(&file->use)); + atomic_inc(&file->use); +} + +void img_file_put(struct img_file *file) +{ + if (atomic_dec_and_test(&file->use)) + img_file_free(file); + + return; +} + static struct img_ip *find_img_ip(struct img_file *file, unsigned long addr, struct probe_desc *pd) { diff --git a/us_manager/img/img_file.h b/us_manager/img/img_file.h index 7b33980a..82870e01 100644 --- a/us_manager/img/img_file.h +++ b/us_manager/img/img_file.h @@ -38,10 +38,12 @@ struct img_file { struct list_head list; /**< For img_proc */ struct dentry *dentry; /**< Dentry of file */ struct list_head ip_list; /**< For img_ip */ + atomic_t use; }; -struct img_file *create_img_file(struct dentry *dentry); -void free_img_file(struct img_file *ip); +struct img_file *img_file_create(struct dentry *dentry); +void img_file_get(struct img_file *file); +void img_file_put(struct img_file *file); int img_file_add_ip(struct img_file *file, unsigned long addr, struct probe_desc *pd); diff --git a/us_manager/img/img_proc.c b/us_manager/img/img_proc.c index ef6805f8..e6999417 100644 --- a/us_manager/img/img_proc.c +++ b/us_manager/img/img_proc.c @@ -69,10 +69,12 @@ void free_img_proc(struct img_proc *proc) { struct img_file *file, *tmp; + write_lock(&proc->rwlock); list_for_each_entry_safe(file, tmp, &proc->file_list, list) { img_del_file_by_list(file); - free_img_file(file); + img_file_put(file); } + write_unlock(&proc->rwlock); kfree(proc); } @@ -90,14 +92,16 @@ static void img_del_file_by_list(struct img_file *file) } /* called with read_[lock/unlock](&proc->rwlock) */ -static struct img_file *find_img_file(struct img_proc *proc, - struct dentry *dentry) +static struct img_file *img_file_find_get(struct img_proc *proc, + struct dentry *dentry) { struct img_file *file; list_for_each_entry(file, &proc->file_list, list) { - if (file->dentry == dentry) + if (file->dentry == dentry) { + img_file_get(file); return file; + } } return NULL; @@ -119,28 +123,25 @@ int img_proc_add_ip(struct img_proc *proc, struct dentry *dentry, struct img_file *file; write_lock(&proc->rwlock); - file = find_img_file(proc, dentry); - if (file) { - ret = img_file_add_ip(file, addr, pd); - goto unlock; - } + file = img_file_find_get(proc, dentry); + write_unlock(&proc->rwlock); + + if (!file) { + file = img_file_create(dentry); + if (!file) + return -ENOMEM; - file = create_img_file(dentry); - if (file == NULL) { - ret = -ENOMEM; - goto unlock; + img_file_get(file); + write_lock(&proc->rwlock); + img_add_file_by_list(proc, file); + write_unlock(&proc->rwlock); } ret = img_file_add_ip(file, addr, pd); - if (ret) { + if (ret) printk(KERN_INFO "Cannot add ip to img file\n"); - free_img_file(file); - } else { - img_add_file_by_list(proc, file); - } -unlock: - write_unlock(&proc->rwlock); + img_file_put(file); return ret; } @@ -161,21 +162,23 @@ int img_proc_del_ip(struct img_proc *proc, struct img_file *file; write_lock(&proc->rwlock); - file = find_img_file(proc, dentry); - if (file == NULL) { - ret = -EINVAL; - goto unlock; - } + file = img_file_find_get(proc, dentry); + write_unlock(&proc->rwlock); + + if (!file) + return -EINVAL; ret = img_file_del_ip(file, addr, pd); if (ret == 0 && img_file_empty(file)) { + write_lock(&proc->rwlock); img_del_file_by_list(file); - free_img_file(file); + write_unlock(&proc->rwlock); + img_file_put(file); } -unlock: - write_unlock(&proc->rwlock); - return ret; + img_file_put(file); + + return 0; } void img_proc_copy_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc) -- cgit v1.2.3