upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / misc / slp_process_monitor.c
1
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/init.h>
5 #include <linux/irq.h>
6 #include <linux/interrupt.h>
7 #include <linux/fs.h>
8 #include <linux/device.h>
9 #include <linux/platform_device.h>
10 #include <asm/thread_notify.h>
11
12 #include <linux/poll.h>
13 #include <linux/wait.h>
14 #include <linux/sched.h>
15 #include <linux/slab.h>
16
17 #define PMON_DEVICE "pmon"
18
19 struct _process_mon_data {
20         int major;
21         int initialized;
22         struct class *cls;
23         struct device *dev;
24
25         struct list_head mp_list;       /* monitor process list */
26         struct list_head dp_list;       /* dead process list  */
27         struct work_struct pmon_work;
28
29         int watcher_pid;
30 };
31
32 enum mp_entry_type {
33         MP_VIP,
34         MP_PERMANENT,
35         MP_NONE
36 };
37
38 struct mp_entry {
39         struct list_head list;
40         enum mp_entry_type type;
41         pid_t pid;
42 };
43
44 struct dp_entry {
45         struct list_head list;
46         pid_t pid;
47 };
48
49 static struct _process_mon_data pmon_data = {
50         .initialized = 0,
51         .watcher_pid = 0
52 };
53
54 static DEFINE_SPINLOCK(mp_list_lock);
55 static DEFINE_SPINLOCK(dp_list_lock);
56 static DECLARE_WAIT_QUEUE_HEAD(pmon_wait);
57 static atomic_t nr_watcher_task = ATOMIC_INIT(0);
58
59 static int pmon_open(struct inode *inode, struct file *file)
60 {
61         int nr_read_task;
62
63         /* only 1 process can do "read open" */
64         if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
65                 nr_read_task = atomic_read(&nr_watcher_task);
66                 if (nr_read_task > 0)
67                         return -EACCES;
68                 else {
69                         atomic_inc(&nr_watcher_task);
70                         pmon_data.watcher_pid = get_current()->pid;
71                         pr_info("add process monitor task = %d\n",
72                                 pmon_data.watcher_pid);
73                 }
74         }
75
76         return 0;
77 }
78
79 static int pmon_release(struct inode *inode, struct file *file)
80 {
81         if ((file->f_flags & O_ACCMODE) == O_RDONLY)
82                 atomic_dec(&nr_watcher_task);
83
84         return 0;
85 }
86
87 static ssize_t pmon_read(struct file *file, char __user *buf, size_t count,
88                          loff_t *ppos)
89 {
90         struct dp_entry *dp;
91         ssize_t ret = 0;
92
93         spin_lock(&dp_list_lock);
94
95         if (!list_empty(&pmon_data.dp_list)) {
96                 dp = list_first_entry(&pmon_data.dp_list, struct dp_entry,
97                                       list);
98                 if (copy_to_user(buf, &(dp->pid), sizeof(pid_t))) {
99                         spin_unlock(&dp_list_lock);
100                         return -EFAULT;
101                 }
102                 ret = sizeof(pid_t);
103                 list_del(&dp->list);
104                 kfree(dp);
105         }
106
107         spin_unlock(&dp_list_lock);
108
109         return ret;
110 }
111
112 static unsigned int pmon_poll(struct file *file, poll_table *wait)
113 {
114         unsigned int retval = 0;
115         poll_wait(file, &pmon_wait, wait);
116         spin_lock(&dp_list_lock);
117         if (!list_empty(&pmon_data.dp_list))
118                 retval = POLLIN;
119         spin_unlock(&dp_list_lock);
120
121         return retval;
122 }
123
124 static int mp_store(const char *buf, enum mp_entry_type type, size_t count)
125 {
126         struct mp_entry *new_mp;
127         int *pid;
128         int ret = 0;
129
130         pid = (int *)buf;
131         pr_debug("monitor process - %d : %d\n", *pid, type);
132
133         spin_lock(&mp_list_lock);
134         list_for_each_entry(new_mp, &pmon_data.mp_list, list) {
135                 if (new_mp->pid == *pid) {
136                         pr_info("Already exist ! pid: %d\n", *pid);
137                         ret = -1;
138                         break;
139                 }
140         }
141         spin_unlock(&mp_list_lock);
142         if (ret == -1)
143                 return count;
144
145         new_mp = NULL;
146         new_mp = kmalloc(sizeof(struct mp_entry), GFP_KERNEL);
147         if (!new_mp)
148                 return -ENOMEM;
149         new_mp->pid = *pid;
150         new_mp->type = type;
151
152         spin_lock(&mp_list_lock);
153         list_add_tail(&new_mp->list, &pmon_data.mp_list);
154         spin_unlock(&mp_list_lock);
155
156         return count;
157 }
158
159 static ssize_t mp_remove(struct class *class, struct class_attribute *attr,
160                          const char *buf, size_t count)
161 {
162         struct mp_entry *rm_mp, *next;
163         int pid, ret = -1;
164
165         if (buf == NULL)
166                 return -1;
167         pid = (int)simple_strtoul(buf, NULL, 10);
168
169         spin_lock(&mp_list_lock);
170         list_for_each_entry_safe(rm_mp, next, &pmon_data.mp_list, list) {
171                 if (rm_mp->pid == pid) {
172                         list_del(&rm_mp->list);
173                         kfree(rm_mp);
174                         pr_debug("remove the monitoring process - %d\n", pid);
175                         ret = 0;
176                         break;
177                 }
178         }
179         spin_unlock(&mp_list_lock);
180
181         if (ret == -1) {
182                 pr_info("No precess to be removed - %d\n", pid);
183         }
184
185         return count;
186 }
187
188 static ssize_t mp_vip_store(struct class *class, struct class_attribute *attr,
189                             const char *buf, size_t count)
190 {
191         return mp_store(buf, MP_VIP, count);
192 }
193
194 static ssize_t mp_pnp_store(struct class *class, struct class_attribute *attr,
195                             const char *buf, size_t count)
196 {
197         return mp_store(buf, MP_PERMANENT, count);
198 }
199
200 static void pmon_work_thread(struct work_struct *work)
201 {
202         if (pmon_data.watcher_pid)
203                 wake_up_interruptible_all(&pmon_wait);
204         else
205                 kobject_uevent(&pmon_data.dev->kobj, KOBJ_CHANGE);
206 }
207
208 static int check_pernament_process(int pid, char *tsk_name)
209 {
210         struct dp_entry *new_dp;
211         struct mp_entry *mp, *next;
212         pid_t found_pid = 0;
213         enum mp_entry_type mtype = MP_NONE;
214
215         if (!pmon_data.initialized)
216                 return -1;
217
218         spin_lock(&mp_list_lock);
219         list_for_each_entry_safe(mp, next, &pmon_data.mp_list, list) {
220                 if (mp->pid == pid) {
221                         found_pid = mp->pid;
222                         mtype = mp->type;
223                         list_del(&mp->list);
224                         kfree(mp);
225                         break;
226                 }
227         }
228         spin_unlock(&mp_list_lock);
229
230         if (pmon_data.watcher_pid == pid || mtype == MP_VIP) {
231                 if (pmon_data.watcher_pid == pid)
232                         pr_info("<<< process monitor process dead: %d (%s)\n",
233                                 pid, tsk_name);
234                 else
235                         pr_info("<<< VIP process dead: %d (%s)>>>\n", pid,
236                                 tsk_name);
237                 pmon_data.watcher_pid = 0;
238                 schedule_work(&pmon_data.pmon_work);
239                 return 0;
240         }
241
242         if (found_pid) {
243                 new_dp = kmalloc(sizeof(struct dp_entry), GFP_ATOMIC);
244                 if (!new_dp) {
245                         pr_err("Not enough memory\n");
246                         return -1;      /* TODO - must do retry */
247                 }
248                 new_dp->pid = found_pid;
249                 spin_lock(&dp_list_lock);
250                 list_add_tail(&new_dp->list, &pmon_data.dp_list);
251                 spin_unlock(&dp_list_lock);
252
253                 schedule_work(&pmon_data.pmon_work);
254         }
255
256         return 0;
257 }
258
259 static int process_mon_do(struct notifier_block *self, unsigned long cmd,
260                           void *t)
261 {
262         struct thread_info *thread;
263
264         switch (cmd) {
265         case THREAD_NOTIFY_FLUSH:
266         case THREAD_NOTIFY_SWITCH:
267                 break;
268         case THREAD_NOTIFY_EXIT:
269                 thread = (struct thread_info *)t;
270                 check_pernament_process(thread->task->pid, thread->task->comm);
271                 break;
272         }
273
274         return NOTIFY_DONE;
275 }
276
277 static struct notifier_block process_mon_nb = {
278         .notifier_call = process_mon_do,
279 };
280
281 static ssize_t mp_show(char *buf, enum mp_entry_type type)
282 {
283         int len = 0;
284         struct mp_entry *mp;
285
286         if (!pmon_data.initialized)
287                 return -1;
288
289         spin_lock(&mp_list_lock);
290         list_for_each_entry(mp, &pmon_data.mp_list, list) {
291                 if (mp->type == type) {
292                         len += snprintf(buf + len, PAGE_SIZE, "%d ", mp->pid);
293                 }
294         }
295         spin_unlock(&mp_list_lock);
296
297         len += snprintf(buf + len, PAGE_SIZE, "\n");
298
299         return len;
300 }
301
302 static ssize_t mp_vip_show(struct class *class, struct class_attribute *attr,
303                            char *buf)
304 {
305         return mp_show(buf, MP_VIP);
306 }
307
308 static ssize_t mp_pnp_show(struct class *class, struct class_attribute *attr,
309                            char *buf)
310 {
311         return mp_show(buf, MP_PERMANENT);
312 }
313
314 static CLASS_ATTR(rm_pmon, S_IWUGO, NULL, mp_remove);
315 static CLASS_ATTR(mp_vip, 0644, mp_vip_show, mp_vip_store);
316 static CLASS_ATTR(mp_pnp, 0644, mp_pnp_show, mp_pnp_store);
317
318 struct file_operations pmon_fops = {
319         .open = pmon_open,
320         .release = pmon_release,
321         .read = pmon_read,
322         .poll = pmon_poll,
323 };
324
325 static int __init process_mon_init(void)
326 {
327         int err = 0;
328
329         pmon_data.major = register_chrdev(0, PMON_DEVICE, &pmon_fops);
330         if (pmon_data.major < 0) {
331                 pr_err("Unable to get major number for pmon dev\n");
332                 err = -EBUSY;
333                 goto error_create_chr_dev;
334         }
335
336         pmon_data.cls = class_create(THIS_MODULE, PMON_DEVICE);
337         if (IS_ERR(pmon_data.cls)) {
338                 pr_err("class create err\n");
339                 err = PTR_ERR(pmon_data.cls);
340                 goto error_class_create;
341         }
342
343         pmon_data.dev = device_create(pmon_data.cls, NULL,
344                                       MKDEV(pmon_data.major, 0), NULL,
345                                       PMON_DEVICE);
346
347         if (IS_ERR(pmon_data.dev)) {
348                 pr_err("device create err\n");
349                 err = PTR_ERR(pmon_data.dev);
350                 goto error_create_class_dev;
351         }
352
353         err = class_create_file(pmon_data.cls, &class_attr_rm_pmon);
354         if (err) {
355                 pr_err("%s: couldn't create meminfo.\n", __func__);
356                 goto error_create_class_file_pmoninfo;
357         }
358
359         err = class_create_file(pmon_data.cls, &class_attr_mp_vip);
360         if (err) {
361                 pr_err("%s: couldn't create meminfo.\n", __func__);
362                 goto error_create_class_file_mp_vip;
363         }
364         err = class_create_file(pmon_data.cls, &class_attr_mp_pnp);
365         if (err) {
366                 pr_err("%s: couldn't create meminfo.\n", __func__);
367                 goto error_create_class_file_mp_pnp;
368         }
369
370         INIT_LIST_HEAD(&pmon_data.mp_list);
371         INIT_LIST_HEAD(&pmon_data.dp_list);
372
373         INIT_WORK(&pmon_data.pmon_work, pmon_work_thread);
374         thread_register_notifier(&process_mon_nb);
375         pmon_data.initialized = 1;
376
377         return 0;
378
379 error_create_class_file_mp_pnp:
380         class_remove_file(pmon_data.cls, &class_attr_mp_vip);
381 error_create_class_file_mp_vip:
382         class_remove_file(pmon_data.cls, &class_attr_rm_pmon);
383 error_create_class_file_pmoninfo:
384         device_del(pmon_data.dev);
385 error_create_class_dev:
386         class_destroy(pmon_data.cls);
387 error_class_create:
388         unregister_chrdev(pmon_data.major, PMON_DEVICE);
389 error_create_chr_dev:
390         return err;
391 }
392
393 static void __exit process_mon_exit(void)
394 {
395         thread_unregister_notifier(&process_mon_nb);
396 }
397
398 module_init(process_mon_init);
399 module_exit(process_mon_exit);
400
401 MODULE_AUTHOR("baik");
402 MODULE_DESCRIPTION("SLP Process Monitoring driver");
403 MODULE_LICENSE("GPL");