diff options
author | Eric Paris <eparis@redhat.com> | 2009-02-12 14:51:04 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-02-13 17:23:48 -0500 |
commit | 26036651c562609d1f52d181f9d2cccbf89929b1 (patch) | |
tree | db68ab98d574d6763f562ac87cc7810385496f22 /security/selinux/avc.c | |
parent | edf3d1aecd0d608acbd561b0c527e1d41abcb657 (diff) |
SELinux: convert the avc cache hash list to an hlist
We do not need O(1) access to the tail of the avc cache lists and so we are
wasting lots of space using struct list_head instead of struct hlist_head.
This patch converts the avc cache to use hlists in which there is a single
pointer from the head which saves us about 4k of global memory.
Resulted in about a 1.5% decrease in time spent in avc_has_perm_noaudit based
on oprofile sampling of tbench. Although likely within the noise....
Signed-off-by: Eric Paris <eparis@redhat.com>
Reviewed-by: Paul Moore <paul.moore@hp.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/avc.c')
-rw-r--r-- | security/selinux/avc.c | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 9dd5c506a826..7f9b5fac8779 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -92,12 +92,12 @@ struct avc_entry { | |||
92 | 92 | ||
93 | struct avc_node { | 93 | struct avc_node { |
94 | struct avc_entry ae; | 94 | struct avc_entry ae; |
95 | struct list_head list; /* anchored in avc_cache->slots[i] */ | 95 | struct hlist_node list; /* anchored in avc_cache->slots[i] */ |
96 | struct rcu_head rhead; | 96 | struct rcu_head rhead; |
97 | }; | 97 | }; |
98 | 98 | ||
99 | struct avc_cache { | 99 | struct avc_cache { |
100 | struct list_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ | 100 | struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ |
101 | spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ | 101 | spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ |
102 | atomic_t lru_hint; /* LRU hint for reclaim scan */ | 102 | atomic_t lru_hint; /* LRU hint for reclaim scan */ |
103 | atomic_t active_nodes; | 103 | atomic_t active_nodes; |
@@ -233,7 +233,7 @@ void __init avc_init(void) | |||
233 | int i; | 233 | int i; |
234 | 234 | ||
235 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { | 235 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
236 | INIT_LIST_HEAD(&avc_cache.slots[i]); | 236 | INIT_HLIST_HEAD(&avc_cache.slots[i]); |
237 | spin_lock_init(&avc_cache.slots_lock[i]); | 237 | spin_lock_init(&avc_cache.slots_lock[i]); |
238 | } | 238 | } |
239 | atomic_set(&avc_cache.active_nodes, 0); | 239 | atomic_set(&avc_cache.active_nodes, 0); |
@@ -249,7 +249,7 @@ int avc_get_hash_stats(char *page) | |||
249 | { | 249 | { |
250 | int i, chain_len, max_chain_len, slots_used; | 250 | int i, chain_len, max_chain_len, slots_used; |
251 | struct avc_node *node; | 251 | struct avc_node *node; |
252 | struct list_head *head; | 252 | struct hlist_head *head; |
253 | 253 | ||
254 | rcu_read_lock(); | 254 | rcu_read_lock(); |
255 | 255 | ||
@@ -257,10 +257,12 @@ int avc_get_hash_stats(char *page) | |||
257 | max_chain_len = 0; | 257 | max_chain_len = 0; |
258 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { | 258 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
259 | head = &avc_cache.slots[i]; | 259 | head = &avc_cache.slots[i]; |
260 | if (!list_empty(head)) { | 260 | if (!hlist_empty(head)) { |
261 | struct hlist_node *next; | ||
262 | |||
261 | slots_used++; | 263 | slots_used++; |
262 | chain_len = 0; | 264 | chain_len = 0; |
263 | list_for_each_entry_rcu(node, head, list) | 265 | hlist_for_each_entry_rcu(node, next, head, list) |
264 | chain_len++; | 266 | chain_len++; |
265 | if (chain_len > max_chain_len) | 267 | if (chain_len > max_chain_len) |
266 | max_chain_len = chain_len; | 268 | max_chain_len = chain_len; |
@@ -284,7 +286,7 @@ static void avc_node_free(struct rcu_head *rhead) | |||
284 | 286 | ||
285 | static void avc_node_delete(struct avc_node *node) | 287 | static void avc_node_delete(struct avc_node *node) |
286 | { | 288 | { |
287 | list_del_rcu(&node->list); | 289 | hlist_del_rcu(&node->list); |
288 | call_rcu(&node->rhead, avc_node_free); | 290 | call_rcu(&node->rhead, avc_node_free); |
289 | atomic_dec(&avc_cache.active_nodes); | 291 | atomic_dec(&avc_cache.active_nodes); |
290 | } | 292 | } |
@@ -298,7 +300,7 @@ static void avc_node_kill(struct avc_node *node) | |||
298 | 300 | ||
299 | static void avc_node_replace(struct avc_node *new, struct avc_node *old) | 301 | static void avc_node_replace(struct avc_node *new, struct avc_node *old) |
300 | { | 302 | { |
301 | list_replace_rcu(&old->list, &new->list); | 303 | hlist_replace_rcu(&old->list, &new->list); |
302 | call_rcu(&old->rhead, avc_node_free); | 304 | call_rcu(&old->rhead, avc_node_free); |
303 | atomic_dec(&avc_cache.active_nodes); | 305 | atomic_dec(&avc_cache.active_nodes); |
304 | } | 306 | } |
@@ -308,7 +310,8 @@ static inline int avc_reclaim_node(void) | |||
308 | struct avc_node *node; | 310 | struct avc_node *node; |
309 | int hvalue, try, ecx; | 311 | int hvalue, try, ecx; |
310 | unsigned long flags; | 312 | unsigned long flags; |
311 | struct list_head *head; | 313 | struct hlist_head *head; |
314 | struct hlist_node *next; | ||
312 | spinlock_t *lock; | 315 | spinlock_t *lock; |
313 | 316 | ||
314 | for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { | 317 | for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { |
@@ -320,7 +323,7 @@ static inline int avc_reclaim_node(void) | |||
320 | continue; | 323 | continue; |
321 | 324 | ||
322 | rcu_read_lock(); | 325 | rcu_read_lock(); |
323 | list_for_each_entry(node, head, list) { | 326 | hlist_for_each_entry(node, next, head, list) { |
324 | avc_node_delete(node); | 327 | avc_node_delete(node); |
325 | avc_cache_stats_incr(reclaims); | 328 | avc_cache_stats_incr(reclaims); |
326 | ecx++; | 329 | ecx++; |
@@ -346,7 +349,7 @@ static struct avc_node *avc_alloc_node(void) | |||
346 | goto out; | 349 | goto out; |
347 | 350 | ||
348 | INIT_RCU_HEAD(&node->rhead); | 351 | INIT_RCU_HEAD(&node->rhead); |
349 | INIT_LIST_HEAD(&node->list); | 352 | INIT_HLIST_NODE(&node->list); |
350 | avc_cache_stats_incr(allocations); | 353 | avc_cache_stats_incr(allocations); |
351 | 354 | ||
352 | if (atomic_inc_return(&avc_cache.active_nodes) > avc_cache_threshold) | 355 | if (atomic_inc_return(&avc_cache.active_nodes) > avc_cache_threshold) |
@@ -368,11 +371,12 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass) | |||
368 | { | 371 | { |
369 | struct avc_node *node, *ret = NULL; | 372 | struct avc_node *node, *ret = NULL; |
370 | int hvalue; | 373 | int hvalue; |
371 | struct list_head *head; | 374 | struct hlist_head *head; |
375 | struct hlist_node *next; | ||
372 | 376 | ||
373 | hvalue = avc_hash(ssid, tsid, tclass); | 377 | hvalue = avc_hash(ssid, tsid, tclass); |
374 | head = &avc_cache.slots[hvalue]; | 378 | head = &avc_cache.slots[hvalue]; |
375 | list_for_each_entry_rcu(node, head, list) { | 379 | hlist_for_each_entry_rcu(node, next, head, list) { |
376 | if (ssid == node->ae.ssid && | 380 | if (ssid == node->ae.ssid && |
377 | tclass == node->ae.tclass && | 381 | tclass == node->ae.tclass && |
378 | tsid == node->ae.tsid) { | 382 | tsid == node->ae.tsid) { |
@@ -461,7 +465,8 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec | |||
461 | 465 | ||
462 | node = avc_alloc_node(); | 466 | node = avc_alloc_node(); |
463 | if (node) { | 467 | if (node) { |
464 | struct list_head *head; | 468 | struct hlist_head *head; |
469 | struct hlist_node *next; | ||
465 | spinlock_t *lock; | 470 | spinlock_t *lock; |
466 | 471 | ||
467 | hvalue = avc_hash(ssid, tsid, tclass); | 472 | hvalue = avc_hash(ssid, tsid, tclass); |
@@ -471,7 +476,7 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec | |||
471 | lock = &avc_cache.slots_lock[hvalue]; | 476 | lock = &avc_cache.slots_lock[hvalue]; |
472 | 477 | ||
473 | spin_lock_irqsave(lock, flag); | 478 | spin_lock_irqsave(lock, flag); |
474 | list_for_each_entry(pos, head, list) { | 479 | hlist_for_each_entry(pos, next, head, list) { |
475 | if (pos->ae.ssid == ssid && | 480 | if (pos->ae.ssid == ssid && |
476 | pos->ae.tsid == tsid && | 481 | pos->ae.tsid == tsid && |
477 | pos->ae.tclass == tclass) { | 482 | pos->ae.tclass == tclass) { |
@@ -479,7 +484,7 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec | |||
479 | goto found; | 484 | goto found; |
480 | } | 485 | } |
481 | } | 486 | } |
482 | list_add_rcu(&node->list, head); | 487 | hlist_add_head_rcu(&node->list, head); |
483 | found: | 488 | found: |
484 | spin_unlock_irqrestore(lock, flag); | 489 | spin_unlock_irqrestore(lock, flag); |
485 | } | 490 | } |
@@ -750,7 +755,8 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, | |||
750 | int hvalue, rc = 0; | 755 | int hvalue, rc = 0; |
751 | unsigned long flag; | 756 | unsigned long flag; |
752 | struct avc_node *pos, *node, *orig = NULL; | 757 | struct avc_node *pos, *node, *orig = NULL; |
753 | struct list_head *head; | 758 | struct hlist_head *head; |
759 | struct hlist_node *next; | ||
754 | spinlock_t *lock; | 760 | spinlock_t *lock; |
755 | 761 | ||
756 | node = avc_alloc_node(); | 762 | node = avc_alloc_node(); |
@@ -767,7 +773,7 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, | |||
767 | 773 | ||
768 | spin_lock_irqsave(lock, flag); | 774 | spin_lock_irqsave(lock, flag); |
769 | 775 | ||
770 | list_for_each_entry(pos, head, list) { | 776 | hlist_for_each_entry(pos, next, head, list) { |
771 | if (ssid == pos->ae.ssid && | 777 | if (ssid == pos->ae.ssid && |
772 | tsid == pos->ae.tsid && | 778 | tsid == pos->ae.tsid && |
773 | tclass == pos->ae.tclass && | 779 | tclass == pos->ae.tclass && |
@@ -827,7 +833,8 @@ int avc_ss_reset(u32 seqno) | |||
827 | int i, rc = 0, tmprc; | 833 | int i, rc = 0, tmprc; |
828 | unsigned long flag; | 834 | unsigned long flag; |
829 | struct avc_node *node; | 835 | struct avc_node *node; |
830 | struct list_head *head; | 836 | struct hlist_head *head; |
837 | struct hlist_node *next; | ||
831 | spinlock_t *lock; | 838 | spinlock_t *lock; |
832 | 839 | ||
833 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { | 840 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
@@ -840,7 +847,7 @@ int avc_ss_reset(u32 seqno) | |||
840 | * prevent RCU grace periods from ending. | 847 | * prevent RCU grace periods from ending. |
841 | */ | 848 | */ |
842 | rcu_read_lock(); | 849 | rcu_read_lock(); |
843 | list_for_each_entry(node, head, list) | 850 | hlist_for_each_entry(node, next, head, list) |
844 | avc_node_delete(node); | 851 | avc_node_delete(node); |
845 | rcu_read_unlock(); | 852 | rcu_read_unlock(); |
846 | spin_unlock_irqrestore(lock, flag); | 853 | spin_unlock_irqrestore(lock, flag); |