オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Contents of /trunk/1.8.x/ccs-patch/security/ccsecurity/gc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3911 - (show annotations) (download) (as text)
Sun Aug 22 12:18:01 2010 UTC (13 years, 9 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 20093 byte(s)
Add Unix domain socket restriction support
1 /*
2 * security/ccsecurity/gc.c
3 *
4 * Copyright (C) 2005-2010 NTT DATA CORPORATION
5 *
6 * Version: 1.8.0-pre 2010/08/01
7 *
8 * This file is applicable to both 2.4.30 and 2.6.11 and later.
9 * See README.ccs for ChangeLog.
10 *
11 */
12
13 #include <linux/version.h>
14 #include "internal.h"
15 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
16 #include <linux/kthread.h>
17 #endif
18
19 /* Structure for garbage collection. */
20 struct ccs_gc {
21 struct list_head list;
22 int type; /* = one of values in "enum ccs_policy_id" */
23 struct list_head *element;
24 };
25 /* List of entries to be deleted. */
26 static LIST_HEAD(ccs_gc_list);
27 /* Length of list. */
28 static int ccs_gc_list_len;
29
30 /**
31 * ccs_add_to_gc - Add an entry to to be deleted list.
32 *
33 * @type: Type of this entry.
34 * @element: Pointer to "struct list_head".
35 *
36 * Returns true on success, false otherwise.
37 *
38 * Caller holds ccs_policy_lock mutex.
39 *
40 * Adding an entry needs kmalloc(). Thus, if we try to add thousands of
41 * entries at once, it will take too long time. Thus, do not add more than 128
42 * entries per a scan. But to be able to handle worst case where all entries
43 * are in-use, we accept one more entry per a scan.
44 *
45 * If we use singly linked list using "struct list_head"->prev (which is
46 * LIST_POISON2), we can avoid kmalloc().
47 */
48 static bool ccs_add_to_gc(const int type, struct list_head *element)
49 {
50 struct ccs_gc *entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
51 if (!entry)
52 return false;
53 entry->type = type;
54 entry->element = element;
55 list_add(&entry->list, &ccs_gc_list);
56 list_del_rcu(element);
57 return ccs_gc_list_len++ < 128;
58 }
59
60 /**
61 * ccs_del_file_pattern - Delete members in "struct ccs_pattern".
62 *
63 * @element: Pointer to "struct list_head".
64 *
65 * Returns size of @element (for later kfree()).
66 */
67 static inline size_t ccs_del_file_pattern(struct list_head *element)
68 {
69 struct ccs_pattern *ptr =
70 container_of(element, typeof(*ptr), head.list);
71 ccs_put_name(ptr->pattern);
72 return sizeof(*ptr);
73 }
74
75 /**
76 * ccs_del_transition_control - Delete members in "struct ccs_transition_control".
77 *
78 * @element: Pointer to "struct list_head".
79 *
80 * Returns size of @element (for later kfree()).
81 */
82 static inline size_t ccs_del_transition_control(struct list_head *element)
83 {
84 struct ccs_transition_control *ptr =
85 container_of(element, typeof(*ptr), head.list);
86 ccs_put_name(ptr->domainname);
87 ccs_put_name(ptr->program);
88 return sizeof(*ptr);
89 }
90
91 /**
92 * ccs_del_aggregator - Delete members in "struct ccs_aggregator".
93 *
94 * @element: Pointer to "struct list_head".
95 *
96 * Returns size of @element (for later kfree()).
97 */
98 static inline size_t ccs_del_aggregator(struct list_head *element)
99 {
100 struct ccs_aggregator *ptr =
101 container_of(element, typeof(*ptr), head.list);
102 ccs_put_name(ptr->original_name);
103 ccs_put_name(ptr->aggregated_name);
104 return sizeof(*ptr);
105 }
106
107 /**
108 * ccs_del_manager - Delete members in "struct ccs_manager".
109 *
110 * @element: Pointer to "struct list_head".
111 *
112 * Returns size of @element (for later kfree()).
113 */
114 static inline size_t ccs_del_manager(struct list_head *element)
115 {
116 struct ccs_manager *ptr =
117 container_of(element, typeof(*ptr), head.list);
118 ccs_put_name(ptr->manager);
119 return sizeof(*ptr);
120 }
121
122 /* For compatibility with older kernels. */
123 #ifndef for_each_process
124 #define for_each_process for_each_task
125 #endif
126
127 /**
128 * ccs_used_by_task - Check whether the given pointer is referenced by a task.
129 *
130 * @domain: Pointer to "struct ccs_domain_info".
131 *
132 * Returns true if @domain is in use, false otherwise.
133 */
134 static bool ccs_used_by_task(struct ccs_domain_info *domain)
135 {
136 bool in_use = false;
137 /*
138 * Don't delete this domain if somebody is doing execve().
139 *
140 * Since ccs_finish_execve() first reverts ccs_domain_info and then
141 * updates ccs_flags , we need smp_mb() to make sure that GC first
142 * checks ccs_flags and then checks ccs_domain_info .
143 */
144 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
145 struct task_struct *g;
146 struct task_struct *t;
147 ccs_tasklist_lock();
148 do_each_thread(g, t) {
149 if (!(t->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
150 smp_mb(); /* Avoid out of order execution. */
151 if (t->ccs_domain_info != domain)
152 continue;
153 }
154 in_use = true;
155 goto out;
156 } while_each_thread(g, t);
157 out:
158 ccs_tasklist_unlock();
159 #else
160 struct task_struct *p;
161 ccs_tasklist_lock();
162 for_each_process(p) {
163 if (!(p->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
164 smp_mb(); /* Avoid out of order execution. */
165 if (p->ccs_domain_info != domain)
166 continue;
167 }
168 in_use = true;
169 break;
170 }
171 ccs_tasklist_unlock();
172 #endif
173 return in_use;
174 }
175
176 /**
177 * ccs_del_acl - Delete members in "struct ccs_acl_info".
178 *
179 * @element: Pointer to "struct list_head".
180 *
181 * Returns size of @element (for later kfree()).
182 */
183 static size_t ccs_del_acl(struct list_head *element)
184 {
185 size_t size;
186 struct ccs_acl_info *acl = container_of(element, typeof(*acl), list);
187 ccs_put_condition(acl->cond);
188 switch (acl->type) {
189 case CCS_TYPE_PATH_ACL:
190 {
191 struct ccs_path_acl *entry;
192 size = sizeof(*entry);
193 entry = container_of(acl, typeof(*entry), head);
194 ccs_put_name_union(&entry->name);
195 }
196 break;
197 case CCS_TYPE_PATH2_ACL:
198 {
199 struct ccs_path2_acl *entry;
200 size = sizeof(*entry);
201 entry = container_of(acl, typeof(*entry), head);
202 ccs_put_name_union(&entry->name1);
203 ccs_put_name_union(&entry->name2);
204 }
205 break;
206 case CCS_TYPE_PATH_NUMBER_ACL:
207 {
208 struct ccs_path_number_acl *entry;
209 size = sizeof(*entry);
210 entry = container_of(acl, typeof(*entry), head);
211 ccs_put_name_union(&entry->name);
212 ccs_put_number_union(&entry->number);
213 }
214 break;
215 case CCS_TYPE_MKDEV_ACL:
216 {
217 struct ccs_mkdev_acl *entry;
218 size = sizeof(*entry);
219 entry = container_of(acl, typeof(*entry), head);
220 ccs_put_name_union(&entry->name);
221 ccs_put_number_union(&entry->mode);
222 ccs_put_number_union(&entry->major);
223 ccs_put_number_union(&entry->minor);
224 }
225 break;
226 case CCS_TYPE_MOUNT_ACL:
227 {
228 struct ccs_mount_acl *entry;
229 size = sizeof(*entry);
230 entry = container_of(acl, typeof(*entry), head);
231 ccs_put_name_union(&entry->dev_name);
232 ccs_put_name_union(&entry->dir_name);
233 ccs_put_name_union(&entry->fs_type);
234 ccs_put_number_union(&entry->flags);
235 }
236 break;
237 case CCS_TYPE_INET_ACL:
238 {
239 struct ccs_inet_acl *entry;
240 size = sizeof(*entry);
241 entry = container_of(acl, typeof(*entry), head);
242 switch (entry->address_type) {
243 case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:
244 ccs_put_group(entry->address.group);
245 break;
246 case CCS_IP_ADDRESS_TYPE_IPv6:
247 ccs_put_ipv6_address(entry->address.ipv6.min);
248 ccs_put_ipv6_address(entry->address.ipv6.max);
249 break;
250 }
251 ccs_put_number_union(&entry->port);
252 }
253 break;
254 case CCS_TYPE_UNIX_ACL:
255 {
256 struct ccs_unix_acl *entry;
257 size = sizeof(*entry);
258 entry = container_of(acl, typeof(*entry), head);
259 ccs_put_name_union(&entry->name);
260 }
261 break;
262 case CCS_TYPE_ENV_ACL:
263 {
264 struct ccs_env_acl *entry;
265 size = sizeof(*entry);
266 entry = container_of(acl, typeof(*entry), head);
267 ccs_put_name(entry->env);
268 }
269 break;
270 case CCS_TYPE_CAPABILITY_ACL:
271 {
272 struct ccs_capability_acl *entry;
273 size = sizeof(*entry);
274 entry = container_of(acl, typeof(*entry), head);
275 }
276 break;
277 case CCS_TYPE_SIGNAL_ACL:
278 {
279 struct ccs_signal_acl *entry;
280 size = sizeof(*entry);
281 entry = container_of(acl, typeof(*entry), head);
282 ccs_put_name(entry->domainname);
283 }
284 break;
285 case CCS_TYPE_EXECUTE_HANDLER:
286 case CCS_TYPE_DENIED_EXECUTE_HANDLER:
287 {
288 struct ccs_execute_handler *entry;
289 size = sizeof(*entry);
290 entry = container_of(acl, typeof(*entry), head);
291 ccs_put_name(entry->handler);
292 }
293 break;
294 default:
295 size = 0;
296 break;
297 }
298 return size;
299 }
300
301 /**
302 * ccs_del_domain - Delete members in "struct ccs_domain_info".
303 *
304 * @element: Pointer to "struct list_head".
305 *
306 * Returns size of @element (for later kfree()) on success, 0 otherwise.
307 */
308 static inline size_t ccs_del_domain(struct list_head *element)
309 {
310 struct ccs_domain_info *domain =
311 container_of(element, typeof(*domain), list);
312 struct ccs_acl_info *acl;
313 struct ccs_acl_info *tmp;
314 /*
315 * We need to recheck domain at this point.
316 *
317 * (1) Reader starts SRCU section upon execve().
318 * (2) Reader traverses ccs_domain_list and finds this domain.
319 * (3) Writer marks this domain as deleted.
320 * (4) Garbage collector removes this domain from ccs_domain_list
321 * because this domain is marked as deleted and used by nobody.
322 * (5) Reader saves reference to this domain into
323 * "struct task_struct"->ccs_domain_info .
324 * (6) Reader finishes execve() operation and starts using this domain.
325 * (7) Garbage collector waits for SRCU synchronization.
326 * (8) Garbage collector kfree() this domain.
327 *
328 * By rechecking whether this domain is used by somebody or not at (8),
329 * we can solve this race problem.
330 */
331 if (ccs_used_by_task(domain))
332 return 0;
333 list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
334 size_t size = ccs_del_acl(&acl->list);
335 ccs_memory_free(acl, size);
336 }
337 ccs_put_name(domain->domainname);
338 return sizeof(*domain);
339 }
340
341 /**
342 * ccs_del_path_group - Delete members in "struct ccs_path_group".
343 *
344 * @element: Pointer to "struct list_head".
345 *
346 * Returns size of @element (for later kfree()).
347 */
348 static inline size_t ccs_del_path_group(struct list_head *element)
349 {
350 struct ccs_path_group *member =
351 container_of(element, typeof(*member), head.list);
352 ccs_put_name(member->member_name);
353 return sizeof(*member);
354 }
355
356 /**
357 * ccs_del_group - Delete "struct ccs_group".
358 *
359 * @element: Pointer to "struct list_head".
360 *
361 * Returns size of @element (for later kfree()).
362 */
363 static inline size_t ccs_del_group(struct list_head *element)
364 {
365 struct ccs_group *group =
366 container_of(element, typeof(*group), head.list);
367 ccs_put_name(group->group_name);
368 return sizeof(*group);
369 }
370
371 /**
372 * ccs_del_address_group - Delete members in "struct ccs_address_group".
373 *
374 * @element: Pointer to "struct list_head".
375 *
376 * Returns size of @element (for later kfree()).
377 */
378 static inline size_t ccs_del_address_group(struct list_head *element)
379 {
380 struct ccs_address_group *member =
381 container_of(element, typeof(*member), head.list);
382 if (member->is_ipv6) {
383 ccs_put_ipv6_address(member->min.ipv6);
384 ccs_put_ipv6_address(member->max.ipv6);
385 }
386 return sizeof(*member);
387 }
388
389 /**
390 * ccs_del_number_group - Delete members in "struct ccs_number_group".
391 *
392 * @element: Pointer to "struct list_head".
393 *
394 * Returns size of @element (for later kfree()).
395 */
396 static inline size_t ccs_del_number_group(struct list_head *element)
397 {
398 struct ccs_number_group *member =
399 container_of(element, typeof(*member), head.list);
400 return sizeof(*member);
401 }
402
403 /**
404 * ccs_del_reservedport - Delete members in "struct ccs_reserved".
405 *
406 * @element: Pointer to "struct list_head".
407 *
408 * Returns size of @element (for later kfree()).
409 */
410 static inline size_t ccs_del_reservedport(struct list_head *element)
411 {
412 struct ccs_reserved *ptr =
413 container_of(element, typeof(*ptr), head.list);
414 return sizeof(*ptr);
415 }
416
417 /**
418 * ccs_del_ipv6_address - Delete members in "struct ccs_ipv6addr".
419 *
420 * @element: Pointer to "struct list_head".
421 *
422 * Returns size of @element (for later kfree()).
423 */
424 static inline size_t ccs_del_ipv6_address(struct list_head *element)
425 {
426 struct ccs_ipv6addr *ptr =
427 container_of(element, typeof(*ptr), head.list);
428 return sizeof(*ptr);
429 }
430
431 /**
432 * ccs_del_condition - Delete members in "struct ccs_condition".
433 *
434 * @element: Pointer to "struct list_head".
435 *
436 * Returns size of condition (for later kfree()).
437 */
438 size_t ccs_del_condition(struct list_head *element)
439 {
440 struct ccs_condition *cond = container_of(element, typeof(*cond),
441 head.list);
442 const u16 condc = cond->condc;
443 const u16 numbers_count = cond->numbers_count;
444 const u16 names_count = cond->names_count;
445 const u16 argc = cond->argc;
446 const u16 envc = cond->envc;
447 unsigned int i;
448 const struct ccs_condition_element *condp
449 = (const struct ccs_condition_element *) (cond + 1);
450 struct ccs_number_union *numbers_p
451 = (struct ccs_number_union *) (condp + condc);
452 struct ccs_name_union *names_p
453 = (struct ccs_name_union *) (numbers_p + numbers_count);
454 const struct ccs_argv *argv
455 = (const struct ccs_argv *) (names_p + names_count);
456 const struct ccs_envp *envp
457 = (const struct ccs_envp *) (argv + argc);
458 for (i = 0; i < numbers_count; i++)
459 ccs_put_number_union(numbers_p++);
460 for (i = 0; i < names_count; i++)
461 ccs_put_name_union(names_p++);
462 for (i = 0; i < argc; argv++, i++)
463 ccs_put_name(argv->value);
464 for (i = 0; i < envc; envp++, i++) {
465 ccs_put_name(envp->name);
466 ccs_put_name(envp->value);
467 }
468 return cond->size;
469 }
470
471 /**
472 * ccs_del_name - Delete members in "struct ccs_name".
473 *
474 * @element: Pointer to "struct list_head".
475 *
476 * Returns size of @element (for later kfree()).
477 */
478 static inline size_t ccs_del_name(struct list_head *element)
479 {
480 const struct ccs_name *ptr =
481 container_of(element, typeof(*ptr), head.list);
482 return ptr->size;
483 }
484
485 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
486 /* Lock for syscall users. */
487 struct srcu_struct ccs_ss;
488 #endif
489
490 /*
491 * Lock for /proc/ccs/ users.
492 *
493 * Currently, we hold SRCU lock upon open() and release upon close().
494 * Thus, kernel complains about returning to userspace with SRCU lock held.
495 * Therefore, non-SRCU lock is used for suppressing the kernel's complain
496 * messages. Modifying to hold/release SRCU lock upon each read()/write() is
497 * to-do list.
498 *
499 * Also used for syscall users for 2.6.18 and earlier kernels because
500 * they don't have SRCU support.
501 */
502 static struct {
503 int counter_idx;
504 int counter[2];
505 } ccs_counter;
506 /* Lock for protecting counter. */
507 static DEFINE_SPINLOCK(ccs_counter_lock);
508
509 /**
510 * ccs_lock - Hold non-SRCU lock.
511 *
512 * Returns index number which has to be passed to ccs_unlock().
513 */
514 int ccs_lock(void)
515 {
516 int idx;
517 spin_lock(&ccs_counter_lock);
518 idx = ccs_counter.counter_idx;
519 ccs_counter.counter[idx]++;
520 spin_unlock(&ccs_counter_lock);
521 return idx;
522 }
523
524 /**
525 * ccs_unlock - Release non-SRCU lock.
526 *
527 * @idx: Index number returned by ccs_lock().
528 */
529 void ccs_unlock(const int idx)
530 {
531 spin_lock(&ccs_counter_lock);
532 ccs_counter.counter[idx]--;
533 spin_unlock(&ccs_counter_lock);
534 }
535
536 /**
537 * ccs_synchronize_counter - Wait for SRCU grace period.
538 */
539 static void ccs_synchronize_counter(void)
540 {
541 int idx;
542 int v;
543 spin_lock(&ccs_counter_lock);
544 idx = ccs_counter.counter_idx;
545 ccs_counter.counter_idx ^= 1;
546 v = ccs_counter.counter[idx];
547 spin_unlock(&ccs_counter_lock);
548 while (v) {
549 ssleep(1);
550 spin_lock(&ccs_counter_lock);
551 v = ccs_counter.counter[idx];
552 spin_unlock(&ccs_counter_lock);
553 }
554 }
555
556 static bool ccs_collect_member(struct list_head *member_list, int id)
557 {
558 struct ccs_acl_head *member;
559 list_for_each_entry(member, member_list, list) {
560 if (!member->is_deleted)
561 continue;
562 if (!ccs_add_to_gc(id, &member->list))
563 return false;
564 }
565 return true;
566 }
567
568 static bool ccs_collect_acl(struct ccs_domain_info *domain)
569 {
570 struct ccs_acl_info *acl;
571 list_for_each_entry(acl, &domain->acl_info_list, list) {
572 if (!acl->is_deleted)
573 continue;
574 if (!ccs_add_to_gc(CCS_ID_ACL, &acl->list))
575 return false;
576 }
577 return true;
578 }
579
580 /**
581 * ccs_collect_entry - Scan lists for deleted elements.
582 */
583 static void ccs_collect_entry(void)
584 {
585 int i;
586 int idx;
587 if (mutex_lock_interruptible(&ccs_policy_lock))
588 return;
589 idx = ccs_read_lock();
590 for (i = 0; i < CCS_MAX_POLICY; i++)
591 if (!ccs_collect_member(&ccs_policy_list[i], i))
592 goto unlock;
593 for (i = 0; i < CCS_MAX_ACL_GROUPS; i++)
594 if (!ccs_collect_acl(&ccs_acl_group[i]))
595 goto unlock;
596 {
597 struct ccs_domain_info *domain;
598 list_for_each_entry(domain, &ccs_domain_list, list) {
599 if (!ccs_collect_acl(domain))
600 goto unlock;
601 if (!domain->is_deleted ||
602 ccs_used_by_task(domain))
603 continue;
604 if (!ccs_add_to_gc(CCS_ID_DOMAIN, &domain->list))
605 goto unlock;
606 }
607 }
608 for (i = 0; i < CCS_MAX_GROUP; i++) {
609 struct list_head *list = &ccs_group_list[i];
610 int id;
611 struct ccs_group *group;
612 switch (i) {
613 case 0:
614 id = CCS_ID_PATH_GROUP;
615 break;
616 case 1:
617 id = CCS_ID_NUMBER_GROUP;
618 break;
619 default:
620 id = CCS_ID_ADDRESS_GROUP;
621 break;
622 }
623 list_for_each_entry(group, list, head.list) {
624 if (!ccs_collect_member(&group->member_list, id))
625 goto unlock;
626 if (!list_empty(&group->member_list) ||
627 atomic_read(&group->head.users))
628 continue;
629 if (!ccs_add_to_gc(CCS_ID_GROUP, &group->head.list))
630 goto unlock;
631 }
632 }
633 for (i = 0; i < CCS_MAX_LIST + CCS_MAX_HASH; i++) {
634 struct list_head *list = i < CCS_MAX_LIST ?
635 &ccs_shared_list[i] : &ccs_name_list[i - CCS_MAX_LIST];
636 int id;
637 struct ccs_shared_acl_head *ptr;
638 switch (i) {
639 case 0:
640 id = CCS_ID_CONDITION;
641 break;
642 case 1:
643 id = CCS_ID_IPV6_ADDRESS;
644 break;
645 default:
646 id = CCS_ID_NAME;
647 break;
648 }
649 list_for_each_entry(ptr, list, list) {
650 if (atomic_read(&ptr->users))
651 continue;
652 if (!ccs_add_to_gc(id, &ptr->list))
653 goto unlock;
654 }
655 }
656 unlock:
657 ccs_read_unlock(idx);
658 mutex_unlock(&ccs_policy_lock);
659 }
660
661 /**
662 * ccs_kfree_entry - Delete entries in ccs_gc_list .
663 *
664 * Returns true if some entries were kfree()d, false otherwise.
665 */
666 static bool ccs_kfree_entry(void)
667 {
668 struct ccs_gc *p;
669 struct ccs_gc *tmp;
670 bool result = false;
671 list_for_each_entry_safe(p, tmp, &ccs_gc_list, list) {
672 size_t size = 0;
673 struct list_head * const element = p->element;
674 switch (p->type) {
675 case CCS_ID_TRANSITION_CONTROL:
676 size = ccs_del_transition_control(element);
677 break;
678 case CCS_ID_PATTERN:
679 size = ccs_del_file_pattern(element);
680 break;
681 case CCS_ID_MANAGER:
682 size = ccs_del_manager(element);
683 break;
684 case CCS_ID_AGGREGATOR:
685 size = ccs_del_aggregator(element);
686 break;
687 case CCS_ID_GROUP:
688 size = ccs_del_group(element);
689 break;
690 case CCS_ID_PATH_GROUP:
691 size = ccs_del_path_group(element);
692 break;
693 case CCS_ID_ADDRESS_GROUP:
694 size = ccs_del_address_group(element);
695 break;
696 case CCS_ID_NUMBER_GROUP:
697 size = ccs_del_number_group(element);
698 break;
699 case CCS_ID_RESERVEDPORT:
700 size = ccs_del_reservedport(element);
701 break;
702 case CCS_ID_IPV6_ADDRESS:
703 size = ccs_del_ipv6_address(element);
704 break;
705 case CCS_ID_CONDITION:
706 size = ccs_del_condition(element);
707 break;
708 case CCS_ID_NAME:
709 size = ccs_del_name(element);
710 break;
711 case CCS_ID_ACL:
712 size = ccs_del_acl(element);
713 break;
714 case CCS_ID_DOMAIN:
715 size = ccs_del_domain(element);
716 if (!size)
717 continue;
718 break;
719 }
720 ccs_memory_free(element, size);
721 list_del(&p->list);
722 kfree(p);
723 ccs_gc_list_len--;
724 result = true;
725 }
726 return result;
727 }
728
729 /**
730 * ccs_gc_thread - Garbage collector thread function.
731 *
732 * In case OOM-killer choose this thread for termination, we create this thread
733 * as a short live thread whenever /proc/ccs/ interface was close()d.
734 *
735 * Returns 0.
736 */
737 static int ccs_gc_thread(void *unused)
738 {
739 static DEFINE_MUTEX(ccs_gc_mutex);
740 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
741 daemonize("GC for CCS");
742 #else
743 daemonize();
744 reparent_to_init();
745 #if defined(TASK_DEAD)
746 {
747 struct task_struct *task = current;
748 spin_lock_irq(&task->sighand->siglock);
749 siginitsetinv(&task->blocked, 0);
750 recalc_sigpending();
751 spin_unlock_irq(&task->sighand->siglock);
752 }
753 #else
754 {
755 struct task_struct *task = current;
756 spin_lock_irq(&task->sigmask_lock);
757 siginitsetinv(&task->blocked, 0);
758 recalc_sigpending(task);
759 spin_unlock_irq(&task->sigmask_lock);
760 }
761 #endif
762 snprintf(current->comm, sizeof(current->comm) - 1, "GC for CCS");
763 #endif
764 if (mutex_trylock(&ccs_gc_mutex)) {
765 do {
766 ccs_collect_entry();
767 if (list_empty(&ccs_gc_list))
768 break;
769 ccs_synchronize_counter();
770 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
771 synchronize_srcu(&ccs_ss);
772 #endif
773 } while (ccs_kfree_entry());
774 mutex_unlock(&ccs_gc_mutex);
775 }
776 return 0;
777 }
778
779 /**
780 * ccs_run_gc - Start garbage collector thread.
781 */
782 void ccs_run_gc(void)
783 {
784 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
785 struct task_struct *task = kthread_create(ccs_gc_thread, NULL,
786 "GC for CCS");
787 if (!IS_ERR(task))
788 wake_up_process(task);
789 #else
790 kernel_thread(ccs_gc_thread, NULL, 0);
791 #endif
792 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26