Tizen 2.4.0 rev3 SDK Public Release
[kernel/swap-modules.git] / nsp / nsp_tdata.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  *
16  * Copyright (C) Samsung Electronics, 2015
17  *
18  * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
19  *
20  */
21
22
23 #include <linux/list.h>
24 #include <linux/slab.h>
25 #include <linux/spinlock.h>
26 #include <writer/swap_msg.h>
27 #include <kprobe/swap_kprobes.h>
28 #include <ksyms/ksyms.h>
29 #include "nsp_tdata.h"
30 #include "nsp_print.h"
31
32
33 /* ============================================================================
34  * =                                priv_tdata                                =
35  * ============================================================================
36  */
37 struct priv_tdata {
38         struct list_head list;
39         struct task_struct *task;
40
41         struct tdata tdata;
42 };
43
44
45 static LIST_HEAD(task_list);
46 static DEFINE_SPINLOCK(task_list_lock);
47
48
49 /* called with task_list_lock held */
50 static struct priv_tdata *priv_tdata_create(struct task_struct *task)
51 {
52         struct priv_tdata *p_tdata;
53
54         p_tdata = kmalloc(sizeof(*p_tdata), GFP_ATOMIC);
55         if (p_tdata) {
56                 INIT_LIST_HEAD(&p_tdata->list);
57                 p_tdata->task = task;
58
59                 /* add to list */
60                 list_add(&p_tdata->list, &task_list);
61         }
62
63         return p_tdata;
64 }
65
66 /* called with task_list_lock held */
67 static void priv_tdata_destroy(struct priv_tdata *p_tdata)
68 {
69         /* delete from list */
70         list_del(&p_tdata->list);
71
72         kfree(p_tdata);
73 }
74
75 /* called with task_list_lock held */
76 static void __priv_tdata_destroy(struct tdata *tdata)
77 {
78         struct priv_tdata *p_tdata;
79
80         p_tdata = container_of(tdata, struct priv_tdata, tdata);
81         priv_tdata_destroy(p_tdata);
82 }
83
84 /* called with task_list_lock held */
85 static void priv_tdata_destroy_all(void)
86 {
87         struct priv_tdata *p_tdata, *n;
88
89         list_for_each_entry_safe(p_tdata, n, &task_list, list)
90                 priv_tdata_destroy(p_tdata);
91 }
92
93
94
95
96
97 /* ============================================================================
98  * =                                  tdata                                   =
99  * ============================================================================
100  */
101 struct tdata *tdata_create(struct task_struct *task)
102 {
103         struct priv_tdata *p_tdata;
104
105         spin_lock(&task_list_lock);
106         p_tdata = priv_tdata_create(task);
107         if (p_tdata)
108                 return &p_tdata->tdata;
109         spin_unlock(&task_list_lock);
110
111         return NULL;
112
113 }
114
115 void tdata_destroy(struct tdata *tdata)
116 {
117         __priv_tdata_destroy(tdata);
118         spin_unlock(&task_list_lock);
119 }
120
121 struct tdata *tdata_find(struct task_struct *task)
122 {
123         struct priv_tdata *p_tdata;
124
125         list_for_each_entry(p_tdata, &task_list, list) {
126                 if (p_tdata->task == task)
127                         return &p_tdata->tdata;
128         }
129
130         return NULL;
131 }
132
133 struct tdata *tdata_get(struct task_struct *task)
134 {
135         struct tdata *tdata;
136
137         spin_lock(&task_list_lock);
138         tdata = tdata_find(task);
139         if (tdata)
140                 return tdata;
141         spin_unlock(&task_list_lock);
142
143         return NULL;
144 }
145
146 void tdata_put(struct tdata *tdata)
147 {
148         spin_unlock(&task_list_lock);
149 }
150
151
152
153
154
155 /* ============================================================================
156  * =                                 do_exit                                  =
157  * ============================================================================
158  */
159 static int do_exit_handler(struct kprobe *p, struct pt_regs *regs)
160 {
161         struct tdata *tdata;
162
163         tdata = tdata_get(current);
164         if (tdata)
165                 tdata_destroy(tdata);
166
167         return 0;
168 }
169
170 struct kprobe do_exit_kp = {
171         .pre_handler = do_exit_handler,
172 };
173
174 int tdata_enable(void)
175 {
176         int ret;
177
178         ret = swap_register_kprobe(&do_exit_kp);
179         if (ret)
180                 return ret;
181
182         return ret;
183 }
184
185 void tdata_disable(void)
186 {
187         swap_unregister_kprobe(&do_exit_kp);
188
189         spin_lock(&task_list_lock);
190         priv_tdata_destroy_all();
191         spin_unlock(&task_list_lock);
192 }
193
194 int tdata_once(void)
195 {
196         const char *sym;
197
198         sym = "do_exit";
199         do_exit_kp.addr = (void *)swap_ksyms(sym);
200         if (do_exit_kp.addr == NULL)
201                 goto not_found;
202
203         return 0;
204
205 not_found:
206         nsp_print("ERROR: symbol '%s' not found\n", sym);
207         return -ESRCH;
208 }