aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/avtab.c
diff options
context:
space:
mode:
authorYuichi Nakamura <ynakam@hitachisoft.jp>2007-08-23 22:55:11 -0400
committerJames Morris <jmorris@namei.org>2007-10-16 18:59:30 -0400
commit3232c110b56bd01c5f0fdfd16b4d695f2e05b0a9 (patch)
treeb369f8dc55e9d27bbd0b8b4b6843c0736d61b005 /security/selinux/ss/avtab.c
parent821f3eff7cdb9d6c7076effabd46c96c322daed1 (diff)
SELinux: tune avtab to reduce memory usage
This patch reduces memory usage of SELinux by tuning avtab. Number of hash slots in avtab was 32768. Unused slots used memory when number of rules is fewer. This patch decides number of hash slots dynamically based on number of rules. (chain length)^2 is also printed out in avtab_hash_eval to see standard deviation of avtab hash table. Signed-off-by: Yuichi Nakamura<ynakam@hitachisoft.jp> Acked-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/ss/avtab.c')
-rw-r--r--security/selinux/ss/avtab.c91
1 files changed, 65 insertions, 26 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 85705eb289e..7551af1f789 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -12,24 +12,25 @@
12 * This program is free software; you can redistribute it and/or modify 12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by 13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, version 2. 14 * the Free Software Foundation, version 2.
15 *
16 * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
17 * Tuned number of hash slots for avtab to reduce memory usage
15 */ 18 */
16 19
17#include <linux/kernel.h> 20#include <linux/kernel.h>
18#include <linux/slab.h> 21#include <linux/slab.h>
19#include <linux/vmalloc.h>
20#include <linux/errno.h> 22#include <linux/errno.h>
21
22#include "avtab.h" 23#include "avtab.h"
23#include "policydb.h" 24#include "policydb.h"
24 25
25#define AVTAB_HASH(keyp) \
26((keyp->target_class + \
27 (keyp->target_type << 2) + \
28 (keyp->source_type << 9)) & \
29 AVTAB_HASH_MASK)
30
31static struct kmem_cache *avtab_node_cachep; 26static struct kmem_cache *avtab_node_cachep;
32 27
28static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
29{
30 return ((keyp->target_class + (keyp->target_type << 2) +
31 (keyp->source_type << 9)) & mask);
32}
33
33static struct avtab_node* 34static struct avtab_node*
34avtab_insert_node(struct avtab *h, int hvalue, 35avtab_insert_node(struct avtab *h, int hvalue,
35 struct avtab_node * prev, struct avtab_node * cur, 36 struct avtab_node * prev, struct avtab_node * cur,
@@ -59,10 +60,10 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
59 struct avtab_node *prev, *cur, *newnode; 60 struct avtab_node *prev, *cur, *newnode;
60 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 61 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
61 62
62 if (!h) 63 if (!h || !h->htable)
63 return -EINVAL; 64 return -EINVAL;
64 65
65 hvalue = AVTAB_HASH(key); 66 hvalue = avtab_hash(key, h->mask);
66 for (prev = NULL, cur = h->htable[hvalue]; 67 for (prev = NULL, cur = h->htable[hvalue];
67 cur; 68 cur;
68 prev = cur, cur = cur->next) { 69 prev = cur, cur = cur->next) {
@@ -100,9 +101,9 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da
100 struct avtab_node *prev, *cur, *newnode; 101 struct avtab_node *prev, *cur, *newnode;
101 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 102 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
102 103
103 if (!h) 104 if (!h || !h->htable)
104 return NULL; 105 return NULL;
105 hvalue = AVTAB_HASH(key); 106 hvalue = avtab_hash(key, h->mask);
106 for (prev = NULL, cur = h->htable[hvalue]; 107 for (prev = NULL, cur = h->htable[hvalue];
107 cur; 108 cur;
108 prev = cur, cur = cur->next) { 109 prev = cur, cur = cur->next) {
@@ -132,10 +133,10 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
132 struct avtab_node *cur; 133 struct avtab_node *cur;
133 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 134 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
134 135
135 if (!h) 136 if (!h || !h->htable)
136 return NULL; 137 return NULL;
137 138
138 hvalue = AVTAB_HASH(key); 139 hvalue = avtab_hash(key, h->mask);
139 for (cur = h->htable[hvalue]; cur; cur = cur->next) { 140 for (cur = h->htable[hvalue]; cur; cur = cur->next) {
140 if (key->source_type == cur->key.source_type && 141 if (key->source_type == cur->key.source_type &&
141 key->target_type == cur->key.target_type && 142 key->target_type == cur->key.target_type &&
@@ -167,10 +168,10 @@ avtab_search_node(struct avtab *h, struct avtab_key *key)
167 struct avtab_node *cur; 168 struct avtab_node *cur;
168 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 169 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
169 170
170 if (!h) 171 if (!h || !h->htable)
171 return NULL; 172 return NULL;
172 173
173 hvalue = AVTAB_HASH(key); 174 hvalue = avtab_hash(key, h->mask);
174 for (cur = h->htable[hvalue]; cur; cur = cur->next) { 175 for (cur = h->htable[hvalue]; cur; cur = cur->next) {
175 if (key->source_type == cur->key.source_type && 176 if (key->source_type == cur->key.source_type &&
176 key->target_type == cur->key.target_type && 177 key->target_type == cur->key.target_type &&
@@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h)
228 if (!h || !h->htable) 229 if (!h || !h->htable)
229 return; 230 return;
230 231
231 for (i = 0; i < AVTAB_SIZE; i++) { 232 for (i = 0; i < h->nslot; i++) {
232 cur = h->htable[i]; 233 cur = h->htable[i];
233 while (cur != NULL) { 234 while (cur != NULL) {
234 temp = cur; 235 temp = cur;
@@ -237,32 +238,63 @@ void avtab_destroy(struct avtab *h)
237 } 238 }
238 h->htable[i] = NULL; 239 h->htable[i] = NULL;
239 } 240 }
240 vfree(h->htable); 241 kfree(h->htable);
241 h->htable = NULL; 242 h->htable = NULL;
243 h->nslot = 0;
244 h->mask = 0;
242} 245}
243 246
244
245int avtab_init(struct avtab *h) 247int avtab_init(struct avtab *h)
246{ 248{
247 int i; 249 h->htable = NULL;
250 h->nel = 0;
251 return 0;
252}
253
254int avtab_alloc(struct avtab *h, u32 nrules)
255{
256 u16 mask = 0;
257 u32 shift = 0;
258 u32 work = nrules;
259 u32 nslot = 0;
260
261 if (nrules == 0)
262 goto avtab_alloc_out;
248 263
249 h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE); 264 while (work) {
265 work = work >> 1;
266 shift++;
267 }
268 if (shift > 2)
269 shift = shift - 2;
270 nslot = 1 << shift;
271 if (nslot > MAX_AVTAB_SIZE)
272 nslot = MAX_AVTAB_SIZE;
273 mask = nslot - 1;
274
275 h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
250 if (!h->htable) 276 if (!h->htable)
251 return -ENOMEM; 277 return -ENOMEM;
252 for (i = 0; i < AVTAB_SIZE; i++) 278
253 h->htable[i] = NULL; 279 avtab_alloc_out:
254 h->nel = 0; 280 h->nel = 0;
281 h->nslot = nslot;
282 h->mask = mask;
283 printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
284 "Num of rules:%d\n", h->nslot, nrules);
255 return 0; 285 return 0;
256} 286}
257 287
258void avtab_hash_eval(struct avtab *h, char *tag) 288void avtab_hash_eval(struct avtab *h, char *tag)
259{ 289{
260 int i, chain_len, slots_used, max_chain_len; 290 int i, chain_len, slots_used, max_chain_len;
291 unsigned long long chain2_len_sum;
261 struct avtab_node *cur; 292 struct avtab_node *cur;
262 293
263 slots_used = 0; 294 slots_used = 0;
264 max_chain_len = 0; 295 max_chain_len = 0;
265 for (i = 0; i < AVTAB_SIZE; i++) { 296 chain2_len_sum = 0;
297 for (i = 0; i < h->nslot; i++) {
266 cur = h->htable[i]; 298 cur = h->htable[i];
267 if (cur) { 299 if (cur) {
268 slots_used++; 300 slots_used++;
@@ -274,12 +306,14 @@ void avtab_hash_eval(struct avtab *h, char *tag)
274 306
275 if (chain_len > max_chain_len) 307 if (chain_len > max_chain_len)
276 max_chain_len = chain_len; 308 max_chain_len = chain_len;
309 chain2_len_sum += chain_len * chain_len;
277 } 310 }
278 } 311 }
279 312
280 printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " 313 printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
281 "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE, 314 "chain length %d sum of chain length^2 %Lu\n",
282 max_chain_len); 315 tag, h->nel, slots_used, h->nslot, max_chain_len,
316 chain2_len_sum);
283} 317}
284 318
285static uint16_t spec_order[] = { 319static uint16_t spec_order[] = {
@@ -419,6 +453,11 @@ int avtab_read(struct avtab *a, void *fp, u32 vers)
419 rc = -EINVAL; 453 rc = -EINVAL;
420 goto bad; 454 goto bad;
421 } 455 }
456
457 rc = avtab_alloc(a, nel);
458 if (rc)
459 goto bad;
460
422 for (i = 0; i < nel; i++) { 461 for (i = 0; i < nel; i++) {
423 rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL); 462 rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
424 if (rc) { 463 if (rc) {