TOMOYO: Simplify garbage collector.
[linux-2.6-block.git] / security / tomoyo / gc.c
CommitLineData
847b173e
TH
1/*
2 * security/tomoyo/gc.c
3 *
0f2a55d5 4 * Copyright (C) 2005-2011 NTT DATA CORPORATION
847b173e
TH
5 */
6
7#include "common.h"
8#include <linux/kthread.h>
5a0e3ad6 9#include <linux/slab.h>
847b173e 10
2e503bbb
TH
11/* The list for "struct tomoyo_io_buffer". */
12static LIST_HEAD(tomoyo_io_buffer_list);
13/* Lock for protecting tomoyo_io_buffer_list. */
14static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
15
2e503bbb
TH
16/**
17 * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.
18 *
19 * @element: Pointer to "struct list_head".
20 *
21 * Returns true if @element is used by /sys/kernel/security/tomoyo/ users,
22 * false otherwise.
23 */
24static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element)
25{
26 struct tomoyo_io_buffer *head;
27 bool in_use = false;
28
29 spin_lock(&tomoyo_io_buffer_list_lock);
30 list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
31 head->users++;
32 spin_unlock(&tomoyo_io_buffer_list_lock);
f9732ea1 33 mutex_lock(&head->io_sem);
2e503bbb
TH
34 if (head->r.domain == element || head->r.group == element ||
35 head->r.acl == element || &head->w.domain->list == element)
36 in_use = true;
37 mutex_unlock(&head->io_sem);
2e503bbb
TH
38 spin_lock(&tomoyo_io_buffer_list_lock);
39 head->users--;
40 if (in_use)
41 break;
42 }
43 spin_unlock(&tomoyo_io_buffer_list_lock);
44 return in_use;
45}
46
47/**
48 * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not.
49 *
50 * @string: String to check.
2e503bbb
TH
51 *
52 * Returns true if @string is used by /sys/kernel/security/tomoyo/ users,
53 * false otherwise.
54 */
f9732ea1 55static bool tomoyo_name_used_by_io_buffer(const char *string)
2e503bbb
TH
56{
57 struct tomoyo_io_buffer *head;
f9732ea1 58 const size_t size = strlen(string) + 1;
2e503bbb
TH
59 bool in_use = false;
60
61 spin_lock(&tomoyo_io_buffer_list_lock);
62 list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
63 int i;
64 head->users++;
65 spin_unlock(&tomoyo_io_buffer_list_lock);
f9732ea1 66 mutex_lock(&head->io_sem);
2e503bbb
TH
67 for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) {
68 const char *w = head->r.w[i];
69 if (w < string || w > string + size)
70 continue;
71 in_use = true;
72 break;
73 }
74 mutex_unlock(&head->io_sem);
2e503bbb
TH
75 spin_lock(&tomoyo_io_buffer_list_lock);
76 head->users--;
77 if (in_use)
78 break;
79 }
80 spin_unlock(&tomoyo_io_buffer_list_lock);
81 return in_use;
82}
83
0df7e8b8
TH
84/**
85 * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".
86 *
87 * @element: Pointer to "struct list_head".
88 *
89 * Returns nothing.
90 */
f9732ea1 91static inline void tomoyo_del_transition_control(struct list_head *element)
847b173e 92{
5448ec4f 93 struct tomoyo_transition_control *ptr =
e79acf0e 94 container_of(element, typeof(*ptr), head.list);
847b173e
TH
95 tomoyo_put_name(ptr->domainname);
96 tomoyo_put_name(ptr->program);
97}
98
0df7e8b8
TH
99/**
100 * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator".
101 *
102 * @element: Pointer to "struct list_head".
103 *
104 * Returns nothing.
105 */
f9732ea1 106static inline void tomoyo_del_aggregator(struct list_head *element)
1084307c 107{
e2bf6907 108 struct tomoyo_aggregator *ptr =
e79acf0e 109 container_of(element, typeof(*ptr), head.list);
1084307c
TH
110 tomoyo_put_name(ptr->original_name);
111 tomoyo_put_name(ptr->aggregated_name);
112}
113
0df7e8b8
TH
114/**
115 * tomoyo_del_manager - Delete members in "struct tomoyo_manager".
116 *
117 * @element: Pointer to "struct list_head".
118 *
119 * Returns nothing.
120 */
f9732ea1 121static inline void tomoyo_del_manager(struct list_head *element)
847b173e 122{
e2bf6907 123 struct tomoyo_manager *ptr =
e79acf0e 124 container_of(element, typeof(*ptr), head.list);
847b173e
TH
125 tomoyo_put_name(ptr->manager);
126}
127
0df7e8b8
TH
128/**
129 * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info".
130 *
131 * @element: Pointer to "struct list_head".
132 *
133 * Returns nothing.
134 */
e79acf0e 135static void tomoyo_del_acl(struct list_head *element)
847b173e 136{
e79acf0e
TH
137 struct tomoyo_acl_info *acl =
138 container_of(element, typeof(*acl), list);
2066a361 139 tomoyo_put_condition(acl->cond);
847b173e 140 switch (acl->type) {
7ef61233 141 case TOMOYO_TYPE_PATH_ACL:
847b173e 142 {
7ef61233 143 struct tomoyo_path_acl *entry
847b173e 144 = container_of(acl, typeof(*entry), head);
7762fbff 145 tomoyo_put_name_union(&entry->name);
847b173e
TH
146 }
147 break;
7ef61233 148 case TOMOYO_TYPE_PATH2_ACL:
847b173e 149 {
7ef61233 150 struct tomoyo_path2_acl *entry
847b173e 151 = container_of(acl, typeof(*entry), head);
7762fbff
TH
152 tomoyo_put_name_union(&entry->name1);
153 tomoyo_put_name_union(&entry->name2);
847b173e
TH
154 }
155 break;
a1f9bb6a
TH
156 case TOMOYO_TYPE_PATH_NUMBER_ACL:
157 {
158 struct tomoyo_path_number_acl *entry
159 = container_of(acl, typeof(*entry), head);
160 tomoyo_put_name_union(&entry->name);
161 tomoyo_put_number_union(&entry->number);
162 }
163 break;
75093152 164 case TOMOYO_TYPE_MKDEV_ACL:
a1f9bb6a 165 {
75093152 166 struct tomoyo_mkdev_acl *entry
a1f9bb6a
TH
167 = container_of(acl, typeof(*entry), head);
168 tomoyo_put_name_union(&entry->name);
169 tomoyo_put_number_union(&entry->mode);
170 tomoyo_put_number_union(&entry->major);
171 tomoyo_put_number_union(&entry->minor);
172 }
173 break;
2106ccd9
TH
174 case TOMOYO_TYPE_MOUNT_ACL:
175 {
176 struct tomoyo_mount_acl *entry
177 = container_of(acl, typeof(*entry), head);
178 tomoyo_put_name_union(&entry->dev_name);
179 tomoyo_put_name_union(&entry->dir_name);
180 tomoyo_put_name_union(&entry->fs_type);
181 tomoyo_put_number_union(&entry->flags);
182 }
183 break;
d58e0da8
TH
184 case TOMOYO_TYPE_ENV_ACL:
185 {
186 struct tomoyo_env_acl *entry =
187 container_of(acl, typeof(*entry), head);
188
189 tomoyo_put_name(entry->env);
190 }
191 break;
059d84db
TH
192 case TOMOYO_TYPE_INET_ACL:
193 {
194 struct tomoyo_inet_acl *entry =
195 container_of(acl, typeof(*entry), head);
196
197 tomoyo_put_group(entry->address.group);
198 tomoyo_put_number_union(&entry->port);
199 }
200 break;
201 case TOMOYO_TYPE_UNIX_ACL:
202 {
203 struct tomoyo_unix_acl *entry =
204 container_of(acl, typeof(*entry), head);
205
206 tomoyo_put_name_union(&entry->name);
207 }
208 break;
847b173e
TH
209 }
210}
211
2e503bbb
TH
212/**
213 * tomoyo_del_domain - Delete members in "struct tomoyo_domain_info".
214 *
215 * @element: Pointer to "struct list_head".
216 *
f9732ea1 217 * Returns nothing.
2e503bbb 218 */
f9732ea1 219static inline void tomoyo_del_domain(struct list_head *element)
847b173e 220{
e79acf0e
TH
221 struct tomoyo_domain_info *domain =
222 container_of(element, typeof(*domain), list);
847b173e
TH
223 struct tomoyo_acl_info *acl;
224 struct tomoyo_acl_info *tmp;
225 /*
f9732ea1
TH
226 * Since this domain is referenced from neither
227 * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete
228 * elements without checking for is_deleted flag.
847b173e 229 */
847b173e 230 list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
e79acf0e 231 tomoyo_del_acl(&acl->list);
847b173e
TH
232 tomoyo_memory_free(acl);
233 }
234 tomoyo_put_name(domain->domainname);
847b173e
TH
235}
236
2066a361
TH
237/**
238 * tomoyo_del_condition - Delete members in "struct tomoyo_condition".
239 *
240 * @element: Pointer to "struct list_head".
241 *
242 * Returns nothing.
243 */
244void tomoyo_del_condition(struct list_head *element)
245{
246 struct tomoyo_condition *cond = container_of(element, typeof(*cond),
247 head.list);
248 const u16 condc = cond->condc;
249 const u16 numbers_count = cond->numbers_count;
2ca9bf45 250 const u16 names_count = cond->names_count;
5b636857
TH
251 const u16 argc = cond->argc;
252 const u16 envc = cond->envc;
2066a361
TH
253 unsigned int i;
254 const struct tomoyo_condition_element *condp
255 = (const struct tomoyo_condition_element *) (cond + 1);
256 struct tomoyo_number_union *numbers_p
257 = (struct tomoyo_number_union *) (condp + condc);
2ca9bf45
TH
258 struct tomoyo_name_union *names_p
259 = (struct tomoyo_name_union *) (numbers_p + numbers_count);
5b636857
TH
260 const struct tomoyo_argv *argv
261 = (const struct tomoyo_argv *) (names_p + names_count);
262 const struct tomoyo_envp *envp
263 = (const struct tomoyo_envp *) (argv + argc);
2066a361
TH
264 for (i = 0; i < numbers_count; i++)
265 tomoyo_put_number_union(numbers_p++);
2ca9bf45
TH
266 for (i = 0; i < names_count; i++)
267 tomoyo_put_name_union(names_p++);
5b636857
TH
268 for (i = 0; i < argc; argv++, i++)
269 tomoyo_put_name(argv->value);
270 for (i = 0; i < envc; envp++, i++) {
271 tomoyo_put_name(envp->name);
272 tomoyo_put_name(envp->value);
273 }
2066a361 274}
847b173e 275
0df7e8b8
TH
276/**
277 * tomoyo_del_name - Delete members in "struct tomoyo_name".
278 *
279 * @element: Pointer to "struct list_head".
280 *
281 * Returns nothing.
282 */
f9732ea1 283static inline void tomoyo_del_name(struct list_head *element)
847b173e 284{
f9732ea1 285 /* Nothing to do. */
847b173e
TH
286}
287
0df7e8b8
TH
288/**
289 * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group".
290 *
291 * @element: Pointer to "struct list_head".
292 *
293 * Returns nothing.
294 */
f9732ea1 295static inline void tomoyo_del_path_group(struct list_head *element)
7762fbff 296{
a98aa4de 297 struct tomoyo_path_group *member =
e79acf0e 298 container_of(element, typeof(*member), head.list);
7762fbff
TH
299 tomoyo_put_name(member->member_name);
300}
301
0df7e8b8
TH
302/**
303 * tomoyo_del_group - Delete "struct tomoyo_group".
304 *
305 * @element: Pointer to "struct list_head".
306 *
307 * Returns nothing.
308 */
f9732ea1 309static inline void tomoyo_del_group(struct list_head *element)
7762fbff 310{
a98aa4de 311 struct tomoyo_group *group =
0df7e8b8 312 container_of(element, typeof(*group), head.list);
7762fbff
TH
313 tomoyo_put_name(group->group_name);
314}
315
059d84db
TH
316/**
317 * tomoyo_del_address_group - Delete members in "struct tomoyo_address_group".
318 *
319 * @element: Pointer to "struct list_head".
320 *
321 * Returns nothing.
322 */
323static inline void tomoyo_del_address_group(struct list_head *element)
324{
325 /* Nothing to do. */
326}
327
0df7e8b8
TH
328/**
329 * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group".
330 *
331 * @element: Pointer to "struct list_head".
332 *
333 * Returns nothing.
334 */
f9732ea1 335static inline void tomoyo_del_number_group(struct list_head *element)
4c3e9e2d 336{
f9732ea1
TH
337 /* Nothing to do. */
338}
339
340/**
341 * tomoyo_try_to_gc - Try to kfree() an entry.
342 *
343 * @type: One of values in "enum tomoyo_policy_id".
344 * @element: Pointer to "struct list_head".
345 *
346 * Returns nothing.
347 *
348 * Caller holds tomoyo_policy_lock mutex.
349 */
350static void tomoyo_try_to_gc(const enum tomoyo_policy_id type,
351 struct list_head *element)
352{
353 /*
354 * __list_del_entry() guarantees that the list element became no longer
355 * reachable from the list which the element was originally on (e.g.
356 * tomoyo_domain_list). Also, synchronize_srcu() guarantees that the
357 * list element became no longer referenced by syscall users.
358 */
359 __list_del_entry(element);
360 mutex_unlock(&tomoyo_policy_lock);
361 synchronize_srcu(&tomoyo_ss);
362 /*
363 * However, there are two users which may still be using the list
364 * element. We need to defer until both users forget this element.
365 *
366 * Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl}
367 * and "struct tomoyo_io_buffer"->w.domain forget this element.
368 */
369 if (tomoyo_struct_used_by_io_buffer(element))
370 goto reinject;
371 switch (type) {
372 case TOMOYO_ID_TRANSITION_CONTROL:
373 tomoyo_del_transition_control(element);
374 break;
375 case TOMOYO_ID_MANAGER:
376 tomoyo_del_manager(element);
377 break;
378 case TOMOYO_ID_AGGREGATOR:
379 tomoyo_del_aggregator(element);
380 break;
381 case TOMOYO_ID_GROUP:
382 tomoyo_del_group(element);
383 break;
384 case TOMOYO_ID_PATH_GROUP:
385 tomoyo_del_path_group(element);
386 break;
387 case TOMOYO_ID_ADDRESS_GROUP:
388 tomoyo_del_address_group(element);
389 break;
390 case TOMOYO_ID_NUMBER_GROUP:
391 tomoyo_del_number_group(element);
392 break;
393 case TOMOYO_ID_CONDITION:
394 tomoyo_del_condition(element);
395 break;
396 case TOMOYO_ID_NAME:
397 /*
398 * Don't kfree() until all "struct tomoyo_io_buffer"->r.w[]
399 * forget this element.
400 */
401 if (tomoyo_name_used_by_io_buffer
402 (container_of(element, typeof(struct tomoyo_name),
403 head.list)->entry.name))
404 goto reinject;
405 tomoyo_del_name(element);
406 break;
407 case TOMOYO_ID_ACL:
408 tomoyo_del_acl(element);
409 break;
410 case TOMOYO_ID_DOMAIN:
411 /*
412 * Don't kfree() until all "struct cred"->security forget this
413 * element.
414 */
415 if (atomic_read(&container_of
416 (element, typeof(struct tomoyo_domain_info),
417 list)->users))
418 goto reinject;
419 tomoyo_del_domain(element);
420 break;
421 case TOMOYO_MAX_POLICY:
422 break;
423 }
424 mutex_lock(&tomoyo_policy_lock);
425 tomoyo_memory_free(element);
426 return;
427reinject:
428 /*
429 * We can safely reinject this element here bacause
430 * (1) Appending list elements and removing list elements are protected
431 * by tomoyo_policy_lock mutex.
432 * (2) Only this function removes list elements and this function is
433 * exclusively executed by tomoyo_gc_mutex mutex.
434 * are true.
435 */
436 mutex_lock(&tomoyo_policy_lock);
437 list_add_rcu(element, element->prev);
4c3e9e2d
TH
438}
439
0df7e8b8
TH
440/**
441 * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head".
442 *
443 * @id: One of values in "enum tomoyo_policy_id".
444 * @member_list: Pointer to "struct list_head".
445 *
f9732ea1 446 * Returns nothing.
0df7e8b8 447 */
f9732ea1 448static void tomoyo_collect_member(const enum tomoyo_policy_id id,
0df7e8b8 449 struct list_head *member_list)
d2f8b234
TH
450{
451 struct tomoyo_acl_head *member;
f9732ea1
TH
452 struct tomoyo_acl_head *tmp;
453 list_for_each_entry_safe(member, tmp, member_list, list) {
d2f8b234
TH
454 if (!member->is_deleted)
455 continue;
f9732ea1
TH
456 member->is_deleted = TOMOYO_GC_IN_PROGRESS;
457 tomoyo_try_to_gc(id, &member->list);
d2f8b234 458 }
d2f8b234
TH
459}
460
32997144
TH
461/**
462 * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info".
463 *
464 * @list: Pointer to "struct list_head".
465 *
f9732ea1 466 * Returns nothing.
32997144 467 */
f9732ea1 468static void tomoyo_collect_acl(struct list_head *list)
d2f8b234
TH
469{
470 struct tomoyo_acl_info *acl;
f9732ea1
TH
471 struct tomoyo_acl_info *tmp;
472 list_for_each_entry_safe(acl, tmp, list, list) {
d2f8b234
TH
473 if (!acl->is_deleted)
474 continue;
f9732ea1
TH
475 acl->is_deleted = TOMOYO_GC_IN_PROGRESS;
476 tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list);
d2f8b234 477 }
d2f8b234
TH
478}
479
0df7e8b8 480/**
f9732ea1 481 * tomoyo_collect_entry - Try to kfree() deleted elements.
0df7e8b8
TH
482 *
483 * Returns nothing.
484 */
847b173e
TH
485static void tomoyo_collect_entry(void)
486{
d2f8b234 487 int i;
bd03a3e4
TH
488 enum tomoyo_policy_id id;
489 struct tomoyo_policy_namespace *ns;
f9732ea1 490 mutex_lock(&tomoyo_policy_lock);
847b173e
TH
491 {
492 struct tomoyo_domain_info *domain;
f9732ea1
TH
493 struct tomoyo_domain_info *tmp;
494 list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list,
495 list) {
496 tomoyo_collect_acl(&domain->acl_info_list);
847b173e
TH
497 if (!domain->is_deleted || atomic_read(&domain->users))
498 continue;
f9732ea1 499 tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list);
847b173e
TH
500 }
501 }
f9732ea1 502 list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
bd03a3e4 503 for (id = 0; id < TOMOYO_MAX_POLICY; id++)
f9732ea1 504 tomoyo_collect_member(id, &ns->policy_list[id]);
bd03a3e4 505 for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
f9732ea1
TH
506 tomoyo_collect_acl(&ns->acl_group[i]);
507 }
508 {
509 struct tomoyo_shared_acl_head *ptr;
510 struct tomoyo_shared_acl_head *tmp;
511 list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list,
512 list) {
513 if (atomic_read(&ptr->users) > 0)
514 continue;
515 atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
516 tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list);
517 }
518 }
519 list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
bd03a3e4
TH
520 for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
521 struct list_head *list = &ns->group_list[i];
522 struct tomoyo_group *group;
f9732ea1 523 struct tomoyo_group *tmp;
bd03a3e4
TH
524 switch (i) {
525 case 0:
526 id = TOMOYO_ID_PATH_GROUP;
527 break;
059d84db 528 case 1:
bd03a3e4
TH
529 id = TOMOYO_ID_NUMBER_GROUP;
530 break;
059d84db
TH
531 default:
532 id = TOMOYO_ID_ADDRESS_GROUP;
533 break;
bd03a3e4 534 }
f9732ea1
TH
535 list_for_each_entry_safe(group, tmp, list, head.list) {
536 tomoyo_collect_member(id, &group->member_list);
bd03a3e4 537 if (!list_empty(&group->member_list) ||
f9732ea1 538 atomic_read(&group->head.users) > 0)
bd03a3e4 539 continue;
f9732ea1
TH
540 atomic_set(&group->head.users,
541 TOMOYO_GC_IN_PROGRESS);
542 tomoyo_try_to_gc(TOMOYO_ID_GROUP,
543 &group->head.list);
bd03a3e4 544 }
847b173e
TH
545 }
546 }
f9732ea1
TH
547 for (i = 0; i < TOMOYO_MAX_HASH; i++) {
548 struct list_head *list = &tomoyo_name_list[i];
bd03a3e4 549 struct tomoyo_shared_acl_head *ptr;
f9732ea1
TH
550 struct tomoyo_shared_acl_head *tmp;
551 list_for_each_entry_safe(ptr, tmp, list, list) {
552 if (atomic_read(&ptr->users) > 0)
4c3e9e2d 553 continue;
f9732ea1
TH
554 atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
555 tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list);
4c3e9e2d
TH
556 }
557 }
29282381 558 mutex_unlock(&tomoyo_policy_lock);
847b173e
TH
559}
560
0df7e8b8
TH
561/**
562 * tomoyo_gc_thread - Garbage collector thread function.
563 *
564 * @unused: Unused.
565 *
0df7e8b8
TH
566 * Returns 0.
567 */
847b173e
TH
568static int tomoyo_gc_thread(void *unused)
569{
2e503bbb
TH
570 /* Garbage collector thread is exclusive. */
571 static DEFINE_MUTEX(tomoyo_gc_mutex);
572 if (!mutex_trylock(&tomoyo_gc_mutex))
573 goto out;
f9732ea1 574 tomoyo_collect_entry();
2e503bbb
TH
575 {
576 struct tomoyo_io_buffer *head;
577 struct tomoyo_io_buffer *tmp;
578
579 spin_lock(&tomoyo_io_buffer_list_lock);
580 list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list,
581 list) {
582 if (head->users)
583 continue;
584 list_del(&head->list);
585 kfree(head->read_buf);
586 kfree(head->write_buf);
587 kfree(head);
847b173e 588 }
2e503bbb 589 spin_unlock(&tomoyo_io_buffer_list_lock);
847b173e 590 }
2e503bbb
TH
591 mutex_unlock(&tomoyo_gc_mutex);
592out:
593 /* This acts as do_exit(0). */
594 return 0;
847b173e
TH
595}
596
2e503bbb
TH
597/**
598 * tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users.
599 *
600 * @head: Pointer to "struct tomoyo_io_buffer".
601 * @is_register: True if register, false if unregister.
602 *
603 * Returns nothing.
604 */
605void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register)
847b173e 606{
2e503bbb
TH
607 bool is_write = false;
608
609 spin_lock(&tomoyo_io_buffer_list_lock);
610 if (is_register) {
611 head->users = 1;
612 list_add(&head->list, &tomoyo_io_buffer_list);
613 } else {
614 is_write = head->write_buf != NULL;
615 if (!--head->users) {
616 list_del(&head->list);
617 kfree(head->read_buf);
618 kfree(head->write_buf);
619 kfree(head);
620 }
621 }
622 spin_unlock(&tomoyo_io_buffer_list_lock);
623 if (is_write) {
624 struct task_struct *task = kthread_create(tomoyo_gc_thread,
625 NULL,
626 "GC for TOMOYO");
627 if (!IS_ERR(task))
628 wake_up_process(task);
629 }
847b173e 630}