1 |
/* |
2 |
* security/ccsecurity/gc.c |
3 |
* |
4 |
* Copyright (C) 2005-2009 NTT DATA CORPORATION |
5 |
* |
6 |
* Version: 1.7.0-pre 2009/08/08 |
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 |
enum ccs_gc_id { |
20 |
CCS_ID_RESERVEDPORT, |
21 |
CCS_ID_ADDRESS_GROUP, |
22 |
CCS_ID_ADDRESS_GROUP_MEMBER, |
23 |
CCS_ID_PATH_GROUP, |
24 |
CCS_ID_PATH_GROUP_MEMBER, |
25 |
CCS_ID_NUMBER_GROUP, |
26 |
CCS_ID_NUMBER_GROUP_MEMBER, |
27 |
CCS_ID_GLOBAL_ENV, |
28 |
CCS_ID_AGGREGATOR, |
29 |
CCS_ID_DOMAIN_INITIALIZER, |
30 |
CCS_ID_DOMAIN_KEEPER, |
31 |
CCS_ID_GLOBALLY_READABLE, |
32 |
CCS_ID_PATTERN, |
33 |
CCS_ID_NO_REWRITE, |
34 |
CCS_ID_MANAGER, |
35 |
CCS_ID_ACL, |
36 |
CCS_ID_DOMAIN |
37 |
}; |
38 |
|
39 |
struct ccs_gc_entry { |
40 |
struct list_head list; |
41 |
int type; |
42 |
void *element; |
43 |
}; |
44 |
|
45 |
/* Caller holds ccs_policy_lock mutex. */ |
46 |
static bool ccs_add_to_gc(const int type, void *element, struct list_head *head) |
47 |
{ |
48 |
struct ccs_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
49 |
if (!entry) |
50 |
return false; |
51 |
entry->type = type; |
52 |
entry->element = element; |
53 |
list_add(&entry->list, head); |
54 |
return true; |
55 |
} |
56 |
|
57 |
static size_t ccs_del_allow_read(struct ccs_globally_readable_file_entry *ptr) |
58 |
{ |
59 |
ccs_put_name(ptr->filename); |
60 |
return sizeof(*ptr); |
61 |
} |
62 |
|
63 |
static size_t ccs_del_allow_env(struct ccs_globally_usable_env_entry *ptr) |
64 |
{ |
65 |
ccs_put_name(ptr->env); |
66 |
return sizeof(*ptr); |
67 |
} |
68 |
|
69 |
static size_t ccs_del_file_pattern(struct ccs_pattern_entry *ptr) |
70 |
{ |
71 |
ccs_put_name(ptr->pattern); |
72 |
return sizeof(*ptr); |
73 |
} |
74 |
|
75 |
static size_t ccs_del_no_rewrite(struct ccs_no_rewrite_entry *ptr) |
76 |
{ |
77 |
ccs_put_name(ptr->pattern); |
78 |
return sizeof(*ptr); |
79 |
} |
80 |
|
81 |
static size_t ccs_del_domain_initializer(struct ccs_domain_initializer_entry * |
82 |
ptr) |
83 |
{ |
84 |
ccs_put_name(ptr->domainname); |
85 |
ccs_put_name(ptr->program); |
86 |
return sizeof(*ptr); |
87 |
} |
88 |
|
89 |
static size_t ccs_del_domain_keeper(struct ccs_domain_keeper_entry *ptr) |
90 |
{ |
91 |
ccs_put_name(ptr->domainname); |
92 |
ccs_put_name(ptr->program); |
93 |
return sizeof(*ptr); |
94 |
} |
95 |
|
96 |
static size_t ccs_del_aggregator(struct ccs_aggregator_entry *ptr) |
97 |
{ |
98 |
ccs_put_name(ptr->original_name); |
99 |
ccs_put_name(ptr->aggregated_name); |
100 |
return sizeof(*ptr); |
101 |
} |
102 |
|
103 |
static size_t ccs_del_manager(struct ccs_policy_manager_entry *ptr) |
104 |
{ |
105 |
ccs_put_name(ptr->manager); |
106 |
return sizeof(*ptr); |
107 |
} |
108 |
|
109 |
/* For compatibility with older kernels. */ |
110 |
#ifndef for_each_process |
111 |
#define for_each_process for_each_task |
112 |
#endif |
113 |
|
114 |
/** |
115 |
* ccs_used_by_task - Check whether the given pointer is referenced by a task. |
116 |
* |
117 |
* @domain: Pointer to "struct ccs_domain_info". |
118 |
* |
119 |
* Returns true if @ptr is in use, false otherwise. |
120 |
*/ |
121 |
static bool ccs_used_by_task(struct ccs_domain_info *domain) |
122 |
{ |
123 |
bool in_use = false; |
124 |
struct task_struct *p; |
125 |
/***** CRITICAL SECTION START *****/ |
126 |
read_lock(&tasklist_lock); |
127 |
for_each_process(p) { |
128 |
if (p->ccs_domain_info != domain) |
129 |
continue; |
130 |
in_use = true; |
131 |
break; |
132 |
} |
133 |
read_unlock(&tasklist_lock); |
134 |
/***** CRITICAL SECTION END *****/ |
135 |
return in_use; |
136 |
} |
137 |
|
138 |
static size_t ccs_del_acl(struct ccs_acl_info *acl) |
139 |
{ |
140 |
size_t size; |
141 |
ccs_put_condition(acl->cond); |
142 |
switch (ccs_acl_type1(acl)) { |
143 |
case CCS_TYPE_SINGLE_PATH_ACL: |
144 |
{ |
145 |
struct ccs_single_path_acl_record *entry; |
146 |
size = sizeof(*entry); |
147 |
entry = container_of(acl, typeof(*entry), head); |
148 |
ccs_put_name_union(&entry->name); |
149 |
} |
150 |
break; |
151 |
case CCS_TYPE_MKDEV_ACL: |
152 |
{ |
153 |
struct ccs_mkdev_acl_record *entry; |
154 |
size = sizeof(*entry); |
155 |
entry = container_of(acl, typeof(*entry), head); |
156 |
ccs_put_name_union(&entry->name); |
157 |
ccs_put_number_union(&entry->major); |
158 |
ccs_put_number_union(&entry->minor); |
159 |
} |
160 |
break; |
161 |
case CCS_TYPE_DOUBLE_PATH_ACL: |
162 |
{ |
163 |
struct ccs_double_path_acl_record *entry; |
164 |
size = sizeof(*entry); |
165 |
entry = container_of(acl, typeof(*entry), head); |
166 |
ccs_put_name_union(&entry->name1); |
167 |
ccs_put_name_union(&entry->name2); |
168 |
} |
169 |
break; |
170 |
case CCS_TYPE_IP_NETWORK_ACL: |
171 |
{ |
172 |
struct ccs_ip_network_acl_record *entry; |
173 |
size = sizeof(*entry); |
174 |
entry = container_of(acl, typeof(*entry), head); |
175 |
switch (entry->record_type) { |
176 |
case CCS_IP_RECORD_TYPE_ADDRESS_GROUP: |
177 |
ccs_put_address_group(entry->address.group); |
178 |
break; |
179 |
case CCS_IP_RECORD_TYPE_IPv6: |
180 |
ccs_put_ipv6_address(entry->address.ipv6.min); |
181 |
ccs_put_ipv6_address(entry->address.ipv6.max); |
182 |
break; |
183 |
} |
184 |
ccs_put_number_union(&entry->port); |
185 |
} |
186 |
break; |
187 |
case CCS_TYPE_PATH_NUMBER_ACL: |
188 |
{ |
189 |
struct ccs_path_number_acl_record *entry; |
190 |
size = sizeof(*entry); |
191 |
entry = container_of(acl, typeof(*entry), head); |
192 |
ccs_put_name_union(&entry->name); |
193 |
ccs_put_number_union(&entry->number); |
194 |
} |
195 |
break; |
196 |
case CCS_TYPE_ENV_ACL: |
197 |
{ |
198 |
struct ccs_env_acl_record *entry; |
199 |
size = sizeof(*entry); |
200 |
entry = container_of(acl, typeof(*entry), head); |
201 |
ccs_put_name(entry->env); |
202 |
} |
203 |
break; |
204 |
case CCS_TYPE_CAPABILITY_ACL: |
205 |
{ |
206 |
struct ccs_capability_acl_record *entry; |
207 |
size = sizeof(*entry); |
208 |
entry = container_of(acl, typeof(*entry), head); |
209 |
} |
210 |
break; |
211 |
case CCS_TYPE_SIGNAL_ACL: |
212 |
{ |
213 |
struct ccs_signal_acl_record *entry; |
214 |
size = sizeof(*entry); |
215 |
entry = container_of(acl, typeof(*entry), head); |
216 |
ccs_put_name(entry->domainname); |
217 |
} |
218 |
break; |
219 |
case CCS_TYPE_EXECUTE_HANDLER: |
220 |
case CCS_TYPE_DENIED_EXECUTE_HANDLER: |
221 |
{ |
222 |
struct ccs_execute_handler_record *entry; |
223 |
size = sizeof(*entry); |
224 |
entry = container_of(acl, typeof(*entry), head); |
225 |
ccs_put_name(entry->handler); |
226 |
} |
227 |
break; |
228 |
case CCS_TYPE_MOUNT_ACL: |
229 |
{ |
230 |
struct ccs_mount_acl_record *entry; |
231 |
size = sizeof(*entry); |
232 |
entry = container_of(acl, typeof(*entry), head); |
233 |
ccs_put_name_union(&entry->dev_name); |
234 |
ccs_put_name_union(&entry->dir_name); |
235 |
ccs_put_name_union(&entry->fs_type); |
236 |
ccs_put_number_union(&entry->flags); |
237 |
} |
238 |
break; |
239 |
case CCS_TYPE_UMOUNT_ACL: |
240 |
{ |
241 |
struct ccs_umount_acl_record *entry; |
242 |
size = sizeof(*entry); |
243 |
entry = container_of(acl, typeof(*entry), head); |
244 |
ccs_put_name_union(&entry->dir); |
245 |
} |
246 |
break; |
247 |
case CCS_TYPE_CHROOT_ACL: |
248 |
{ |
249 |
struct ccs_chroot_acl_record *entry; |
250 |
size = sizeof(*entry); |
251 |
entry = container_of(acl, typeof(*entry), head); |
252 |
ccs_put_name_union(&entry->dir); |
253 |
} |
254 |
break; |
255 |
case CCS_TYPE_PIVOT_ROOT_ACL: |
256 |
{ |
257 |
struct ccs_pivot_root_acl_record *entry; |
258 |
size = sizeof(*entry); |
259 |
entry = container_of(acl, typeof(*entry), head); |
260 |
ccs_put_name_union(&entry->old_root); |
261 |
ccs_put_name_union(&entry->new_root); |
262 |
} |
263 |
break; |
264 |
default: |
265 |
size = 0; |
266 |
printk(KERN_WARNING "Unknown type\n"); |
267 |
break; |
268 |
} |
269 |
return size; |
270 |
} |
271 |
|
272 |
static size_t ccs_del_domain(struct ccs_domain_info *domain) |
273 |
{ |
274 |
struct ccs_acl_info *acl; |
275 |
struct ccs_acl_info *tmp; |
276 |
if (ccs_used_by_task(domain)) |
277 |
return 0; |
278 |
list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { |
279 |
size_t size = ccs_del_acl(acl); |
280 |
ccs_memory_free(acl, size); |
281 |
} |
282 |
ccs_put_name(domain->domainname); |
283 |
return sizeof(*domain); |
284 |
} |
285 |
|
286 |
static size_t ccs_del_path_group_member(struct ccs_path_group_member *member) |
287 |
{ |
288 |
ccs_put_name(member->member_name); |
289 |
return sizeof(*member); |
290 |
} |
291 |
|
292 |
static size_t ccs_del_path_group(struct ccs_path_group *group) |
293 |
{ |
294 |
ccs_put_name(group->group_name); |
295 |
return sizeof(*group); |
296 |
} |
297 |
|
298 |
static size_t ccs_del_address_group_member |
299 |
(struct ccs_address_group_member *member) |
300 |
{ |
301 |
if (member->is_ipv6) { |
302 |
ccs_put_ipv6_address(member->min.ipv6); |
303 |
ccs_put_ipv6_address(member->max.ipv6); |
304 |
} |
305 |
return sizeof(*member); |
306 |
} |
307 |
|
308 |
static size_t ccs_del_address_group(struct ccs_address_group_entry *group) |
309 |
{ |
310 |
ccs_put_name(group->group_name); |
311 |
return sizeof(*group); |
312 |
} |
313 |
|
314 |
static size_t ccs_del_number_group_member |
315 |
(struct ccs_number_group_member *member) |
316 |
{ |
317 |
return sizeof(*member); |
318 |
} |
319 |
|
320 |
static size_t ccs_del_number_group(struct ccs_number_group *group) |
321 |
{ |
322 |
ccs_put_name(group->group_name); |
323 |
return sizeof(*group); |
324 |
} |
325 |
|
326 |
static size_t ccs_del_reservedport(struct ccs_reserved_entry *ptr) |
327 |
{ |
328 |
return sizeof(*ptr); |
329 |
} |
330 |
|
331 |
static int ccs_gc_thread(void *unused) |
332 |
{ |
333 |
static DEFINE_MUTEX(ccs_gc_mutex); |
334 |
static LIST_HEAD(ccs_gc_queue); |
335 |
if (!mutex_trylock(&ccs_gc_mutex)) |
336 |
goto out; |
337 |
mutex_lock(&ccs_policy_lock); |
338 |
{ |
339 |
struct ccs_globally_readable_file_entry *ptr; |
340 |
list_for_each_entry_rcu(ptr, &ccs_globally_readable_list, |
341 |
list) { |
342 |
if (!ptr->is_deleted) |
343 |
continue; |
344 |
if (ccs_add_to_gc(CCS_ID_GLOBALLY_READABLE, ptr, |
345 |
&ccs_gc_queue)) |
346 |
list_del_rcu(&ptr->list); |
347 |
else |
348 |
break; |
349 |
} |
350 |
} |
351 |
{ |
352 |
struct ccs_globally_usable_env_entry *ptr; |
353 |
list_for_each_entry_rcu(ptr, &ccs_globally_usable_env_list, |
354 |
list) { |
355 |
if (!ptr->is_deleted) |
356 |
continue; |
357 |
if (ccs_add_to_gc(CCS_ID_GLOBAL_ENV, ptr, |
358 |
&ccs_gc_queue)) |
359 |
list_del_rcu(&ptr->list); |
360 |
else |
361 |
break; |
362 |
} |
363 |
} |
364 |
{ |
365 |
struct ccs_pattern_entry *ptr; |
366 |
list_for_each_entry_rcu(ptr, &ccs_pattern_list, list) { |
367 |
if (!ptr->is_deleted) |
368 |
continue; |
369 |
if (ccs_add_to_gc(CCS_ID_PATTERN, ptr, |
370 |
&ccs_gc_queue)) |
371 |
list_del_rcu(&ptr->list); |
372 |
else |
373 |
break; |
374 |
} |
375 |
} |
376 |
{ |
377 |
struct ccs_no_rewrite_entry *ptr; |
378 |
list_for_each_entry_rcu(ptr, &ccs_no_rewrite_list, list) { |
379 |
if (!ptr->is_deleted) |
380 |
continue; |
381 |
if (ccs_add_to_gc(CCS_ID_NO_REWRITE, ptr, |
382 |
&ccs_gc_queue)) |
383 |
list_del_rcu(&ptr->list); |
384 |
else |
385 |
break; |
386 |
} |
387 |
} |
388 |
{ |
389 |
struct ccs_domain_initializer_entry *ptr; |
390 |
list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, |
391 |
list) { |
392 |
if (!ptr->is_deleted) |
393 |
continue; |
394 |
if (ccs_add_to_gc(CCS_ID_DOMAIN_INITIALIZER, |
395 |
ptr, &ccs_gc_queue)) |
396 |
list_del_rcu(&ptr->list); |
397 |
else |
398 |
break; |
399 |
} |
400 |
} |
401 |
{ |
402 |
struct ccs_domain_keeper_entry *ptr; |
403 |
list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) { |
404 |
if (!ptr->is_deleted) |
405 |
continue; |
406 |
if (ccs_add_to_gc(CCS_ID_DOMAIN_KEEPER, ptr, |
407 |
&ccs_gc_queue)) |
408 |
list_del_rcu(&ptr->list); |
409 |
else |
410 |
break; |
411 |
} |
412 |
} |
413 |
{ |
414 |
struct ccs_policy_manager_entry *ptr; |
415 |
list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) { |
416 |
if (!ptr->is_deleted) |
417 |
continue; |
418 |
if (ccs_add_to_gc(CCS_ID_MANAGER, ptr, &ccs_gc_queue)) |
419 |
list_del_rcu(&ptr->list); |
420 |
else |
421 |
break; |
422 |
} |
423 |
} |
424 |
{ |
425 |
struct ccs_aggregator_entry *ptr; |
426 |
list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) { |
427 |
if (!ptr->is_deleted) |
428 |
continue; |
429 |
if (ccs_add_to_gc(CCS_ID_AGGREGATOR, ptr, |
430 |
&ccs_gc_queue)) |
431 |
list_del_rcu(&ptr->list); |
432 |
else |
433 |
break; |
434 |
} |
435 |
} |
436 |
{ |
437 |
struct ccs_domain_info *domain; |
438 |
list_for_each_entry_rcu(domain, &ccs_domain_list, list) { |
439 |
struct ccs_acl_info *acl; |
440 |
list_for_each_entry_rcu(acl, &domain->acl_info_list, |
441 |
list) { |
442 |
if (!(acl->type & CCS_ACL_DELETED)) |
443 |
continue; |
444 |
if (ccs_add_to_gc(CCS_ID_ACL, acl, |
445 |
&ccs_gc_queue)) |
446 |
list_del_rcu(&acl->list); |
447 |
else |
448 |
break; |
449 |
} |
450 |
if (!domain->is_deleted || |
451 |
ccs_used_by_task(domain)) |
452 |
continue; |
453 |
if (ccs_add_to_gc(CCS_ID_DOMAIN, domain, &ccs_gc_queue)) |
454 |
list_del_rcu(&domain->list); |
455 |
else |
456 |
break; |
457 |
} |
458 |
} |
459 |
{ |
460 |
struct ccs_path_group *group; |
461 |
list_for_each_entry_rcu(group, &ccs_path_group_list, list) { |
462 |
struct ccs_path_group_member *member; |
463 |
list_for_each_entry_rcu(member, |
464 |
&group->path_group_member_list, |
465 |
list) { |
466 |
if (!member->is_deleted) |
467 |
continue; |
468 |
if (ccs_add_to_gc(CCS_ID_PATH_GROUP_MEMBER, |
469 |
member, &ccs_gc_queue)) |
470 |
list_del_rcu(&member->list); |
471 |
else |
472 |
break; |
473 |
} |
474 |
if (!list_empty(&group->path_group_member_list) || |
475 |
atomic_read(&group->users)) |
476 |
continue; |
477 |
if (ccs_add_to_gc(CCS_ID_PATH_GROUP, group, |
478 |
&ccs_gc_queue)) |
479 |
list_del_rcu(&group->list); |
480 |
else |
481 |
break; |
482 |
} |
483 |
} |
484 |
{ |
485 |
struct ccs_address_group_entry *group; |
486 |
list_for_each_entry_rcu(group, &ccs_address_group_list, list) { |
487 |
struct ccs_address_group_member *member; |
488 |
list_for_each_entry_rcu(member, |
489 |
&group->address_group_member_list, |
490 |
list) { |
491 |
if (!member->is_deleted) |
492 |
break; |
493 |
if (ccs_add_to_gc(CCS_ID_ADDRESS_GROUP_MEMBER, |
494 |
member, &ccs_gc_queue)) |
495 |
list_del_rcu(&member->list); |
496 |
else |
497 |
break; |
498 |
} |
499 |
if (!list_empty(&group->address_group_member_list) || |
500 |
atomic_read(&group->users)) |
501 |
continue; |
502 |
if (ccs_add_to_gc(CCS_ID_ADDRESS_GROUP, group, |
503 |
&ccs_gc_queue)) |
504 |
list_del_rcu(&group->list); |
505 |
else |
506 |
break; |
507 |
} |
508 |
} |
509 |
{ |
510 |
struct ccs_number_group *group; |
511 |
list_for_each_entry_rcu(group, &ccs_number_group_list, list) { |
512 |
struct ccs_number_group_member *member; |
513 |
list_for_each_entry_rcu(member, |
514 |
&group-> |
515 |
number_group_member_list, |
516 |
list) { |
517 |
if (!member->is_deleted) |
518 |
continue; |
519 |
if (ccs_add_to_gc(CCS_ID_NUMBER_GROUP_MEMBER, |
520 |
member, &ccs_gc_queue)) |
521 |
list_del_rcu(&member->list); |
522 |
else |
523 |
break; |
524 |
} |
525 |
if (!list_empty(&group->number_group_member_list) || |
526 |
atomic_read(&group->users)) |
527 |
continue; |
528 |
if (ccs_add_to_gc(CCS_ID_NUMBER_GROUP, group, |
529 |
&ccs_gc_queue)) |
530 |
list_del_rcu(&group->list); |
531 |
else |
532 |
break; |
533 |
} |
534 |
} |
535 |
{ |
536 |
struct ccs_reserved_entry *ptr; |
537 |
list_for_each_entry_rcu(ptr, &ccs_reservedport_list, list) { |
538 |
if (!ptr->is_deleted) |
539 |
continue; |
540 |
if (ccs_add_to_gc(CCS_ID_RESERVEDPORT, ptr, |
541 |
&ccs_gc_queue)) |
542 |
list_del_rcu(&ptr->list); |
543 |
else |
544 |
break; |
545 |
} |
546 |
} |
547 |
mutex_unlock(&ccs_policy_lock); |
548 |
if (list_empty(&ccs_gc_queue)) |
549 |
goto done; |
550 |
synchronize_srcu(&ccs_ss); |
551 |
{ |
552 |
struct ccs_gc_entry *p; |
553 |
struct ccs_gc_entry *tmp; |
554 |
size_t size = 0; |
555 |
list_for_each_entry_safe(p, tmp, &ccs_gc_queue, list) { |
556 |
switch (p->type) { |
557 |
case CCS_ID_DOMAIN_INITIALIZER: |
558 |
size = ccs_del_domain_initializer(p->element); |
559 |
break; |
560 |
case CCS_ID_DOMAIN_KEEPER: |
561 |
size = ccs_del_domain_keeper(p->element); |
562 |
break; |
563 |
case CCS_ID_GLOBALLY_READABLE: |
564 |
size = ccs_del_allow_read(p->element); |
565 |
break; |
566 |
case CCS_ID_PATTERN: |
567 |
size = ccs_del_file_pattern(p->element); |
568 |
break; |
569 |
case CCS_ID_NO_REWRITE: |
570 |
size = ccs_del_no_rewrite(p->element); |
571 |
break; |
572 |
case CCS_ID_MANAGER: |
573 |
size = ccs_del_manager(p->element); |
574 |
break; |
575 |
case CCS_ID_GLOBAL_ENV: |
576 |
size = ccs_del_allow_env(p->element); |
577 |
break; |
578 |
case CCS_ID_AGGREGATOR: |
579 |
size = ccs_del_aggregator(p->element); |
580 |
break; |
581 |
case CCS_ID_PATH_GROUP_MEMBER: |
582 |
size = ccs_del_path_group_member(p->element); |
583 |
break; |
584 |
case CCS_ID_PATH_GROUP: |
585 |
size = ccs_del_path_group(p->element); |
586 |
break; |
587 |
case CCS_ID_ADDRESS_GROUP_MEMBER: |
588 |
size = ccs_del_address_group_member(p->element); |
589 |
break; |
590 |
case CCS_ID_ADDRESS_GROUP: |
591 |
size = ccs_del_address_group(p->element); |
592 |
break; |
593 |
case CCS_ID_NUMBER_GROUP_MEMBER: |
594 |
size = ccs_del_number_group_member(p->element); |
595 |
break; |
596 |
case CCS_ID_NUMBER_GROUP: |
597 |
size = ccs_del_number_group(p->element); |
598 |
break; |
599 |
case CCS_ID_RESERVEDPORT: |
600 |
size = ccs_del_reservedport(p->element); |
601 |
break; |
602 |
case CCS_ID_ACL: |
603 |
size = ccs_del_acl(p->element); |
604 |
break; |
605 |
case CCS_ID_DOMAIN: |
606 |
size = ccs_del_domain(p->element); |
607 |
if (!size) |
608 |
continue; |
609 |
break; |
610 |
default: |
611 |
size = 0; |
612 |
printk(KERN_WARNING "Unknown type\n"); |
613 |
break; |
614 |
} |
615 |
ccs_memory_free(p->element, size); |
616 |
list_del(&p->list); |
617 |
kfree(p); |
618 |
} |
619 |
} |
620 |
done: |
621 |
mutex_unlock(&ccs_gc_mutex); |
622 |
out: |
623 |
do_exit(0); |
624 |
} |
625 |
|
626 |
void ccs_run_gc(void) |
627 |
{ |
628 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) |
629 |
struct task_struct *task = kthread_create(ccs_gc_thread, NULL, |
630 |
"GC for CCS"); |
631 |
if (!IS_ERR(task)) |
632 |
wake_up_process(task); |
633 |
#else |
634 |
kernel_thread(ccs_gc_thread, NULL, 0); |
635 |
#endif |
636 |
} |
637 |
|
638 |
#ifndef _LINUX_SRCU_H |
639 |
|
640 |
static DEFINE_SPINLOCK(ccs_counter_lock); |
641 |
|
642 |
int srcu_read_lock(struct srcu_struct *sp) |
643 |
{ |
644 |
int idx; |
645 |
spin_lock(&ccs_counter_lock); |
646 |
idx = sp->counter_idx; |
647 |
sp->counter[idx]++; |
648 |
spin_unlock(&ccs_counter_lock); |
649 |
return idx; |
650 |
} |
651 |
|
652 |
void srcu_read_unlock(struct srcu_struct *sp, const int idx) |
653 |
{ |
654 |
spin_lock(&ccs_counter_lock); |
655 |
sp->counter[idx]--; |
656 |
spin_unlock(&ccs_counter_lock); |
657 |
} |
658 |
|
659 |
void synchronize_srcu(struct srcu_struct *sp) |
660 |
{ |
661 |
int idx; |
662 |
int v; |
663 |
spin_lock(&ccs_counter_lock); |
664 |
idx = sp->counter_idx; |
665 |
sp->counter_idx ^= 1; |
666 |
v = sp->counter[idx]; |
667 |
spin_unlock(&ccs_counter_lock); |
668 |
while (v) { |
669 |
ssleep(1); |
670 |
spin_lock(&ccs_counter_lock); |
671 |
v = sp->counter[idx]; |
672 |
spin_unlock(&ccs_counter_lock); |
673 |
} |
674 |
} |
675 |
|
676 |
#endif |