[FIX] deadlock in img_proc_del_ip()
[platform/kernel/swap-modules.git] / us_manager / img / img_proc.c
1 /*
2  *  SWAP uprobe manager
3  *  modules/us_manager/img/img_proc.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2013
20  *
21  * 2013  Vyacheslav Cherkashin: SWAP us_manager implement
22  *
23  */
24
25
26 #include <linux/slab.h>
27 #include <linux/list.h>
28 #include <linux/spinlock.h>
29 #include <us_manager/sspt/sspt_proc.h>
30 #include <us_manager/sspt/sspt_file.h>
31 #include "img_ip.h"
32 #include "img_proc.h"
33 #include "img_file.h"
34
35
36 struct img_proc {
37         struct list_head file_list;
38         rwlock_t rwlock;
39 };
40
41
42 static void img_del_file_by_list(struct img_file *file);
43
44 /**
45  * @brief Create img_proc struct
46  *
47  * @return Pointer to the created img_proc struct
48  */
49 struct img_proc *create_img_proc(void)
50 {
51         struct img_proc *proc;
52
53         proc = kmalloc(sizeof(*proc), GFP_ATOMIC);
54         if (proc) {
55                 INIT_LIST_HEAD(&proc->file_list);
56                 rwlock_init(&proc->rwlock);
57         }
58
59         return proc;
60 }
61
62 /**
63  * @brief Remove img_proc struct
64  *
65  * @param file remove object
66  * @return Void
67  */
68 void free_img_proc(struct img_proc *proc)
69 {
70         struct img_file *file, *tmp;
71
72         write_lock(&proc->rwlock);
73         list_for_each_entry_safe(file, tmp, &proc->file_list, list) {
74                 img_del_file_by_list(file);
75                 img_file_put(file);
76         }
77         write_unlock(&proc->rwlock);
78
79         kfree(proc);
80 }
81
82 /* called with write_[lock/unlock](&proc->rwlock) */
83 static void img_add_file_by_list(struct img_proc *proc, struct img_file *file)
84 {
85         list_add(&file->list, &proc->file_list);
86 }
87
88 /* called with write_[lock/unlock](&proc->rwlock) */
89 static void img_del_file_by_list(struct img_file *file)
90 {
91         list_del(&file->list);
92 }
93
94 /* called with read_[lock/unlock](&proc->rwlock) */
95 static struct img_file *img_file_find_get(struct img_proc *proc,
96                                           struct dentry *dentry)
97 {
98         struct img_file *file;
99
100         list_for_each_entry(file, &proc->file_list, list) {
101                 if (file->dentry == dentry) {
102                         img_file_get(file);
103                         return file;
104                 }
105         }
106
107         return NULL;
108 }
109
110 /**
111  * @brief Add instrumentation pointer
112  *
113  * @param proc Pointer to the img_proc struct
114  * @param dentry Dentry of file
115  * @param addr Function address
116  * @param probe_i Pointer to a probe_info struct related with the probe
117  * @return Error code
118  */
119 int img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
120                     unsigned long addr, struct probe_desc *pd)
121 {
122         int ret;
123         struct img_file *file;
124
125         write_lock(&proc->rwlock);
126         file = img_file_find_get(proc, dentry);
127         write_unlock(&proc->rwlock);
128
129         if (!file) {
130                 file = img_file_create(dentry);
131                 if (!file)
132                         return -ENOMEM;
133
134                 img_file_get(file);
135                 write_lock(&proc->rwlock);
136                 img_add_file_by_list(proc, file);
137                 write_unlock(&proc->rwlock);
138         }
139
140         ret = img_file_add_ip(file, addr, pd);
141         if (ret)
142                 printk(KERN_INFO "Cannot add ip to img file\n");
143
144         img_file_put(file);
145         return ret;
146 }
147
148 /**
149  * @brief Remove instrumentation pointer
150  *
151  * @param proc Pointer to the img_proc struct
152  * @param dentry Dentry of file
153  * @param args Function address
154  * @return Error code
155  */
156 int img_proc_del_ip(struct img_proc *proc,
157                     struct dentry *dentry,
158                     unsigned long addr,
159                     struct probe_desc *pd)
160 {
161         int ret;
162         struct img_file *file;
163
164         write_lock(&proc->rwlock);
165         file = img_file_find_get(proc, dentry);
166         write_unlock(&proc->rwlock);
167
168         if (!file)
169                 return -EINVAL;
170
171         ret = img_file_del_ip(file, addr, pd);
172         if (ret == 0 && img_file_empty(file)) {
173                 write_lock(&proc->rwlock);
174                 img_del_file_by_list(file);
175                 write_unlock(&proc->rwlock);
176                 img_file_put(file);
177         }
178
179         img_file_put(file);
180
181         return 0;
182 }
183
184 void img_proc_copy_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc)
185 {
186         struct sspt_file *file;
187         struct img_file *i_file;
188
189         read_lock(&i_proc->rwlock);
190         list_for_each_entry(i_file, &i_proc->file_list, list) {
191                 file = sspt_proc_find_file_or_new(proc, i_file->dentry);
192                 if (file) {
193                         struct img_ip *i_ip;
194
195                         list_for_each_entry(i_ip, &i_file->ip_list, list)
196                                 sspt_file_add_ip(file, i_ip);
197                 }
198         }
199         read_unlock(&i_proc->rwlock);
200 }
201
202 /**
203  * @brief For debug
204  *
205  * @param proc Pointer to the img_proc struct
206  * @return Void
207  */
208
209 /* debug */
210 void img_proc_print(struct img_proc *proc)
211 {
212         struct img_file *file;
213
214         printk(KERN_INFO "### img_proc_print:\n");
215
216         read_lock(&proc->rwlock);
217         list_for_each_entry(file, &proc->file_list, list) {
218                 img_file_print(file);
219         }
220         read_unlock(&proc->rwlock);
221 }
222 /* debug */