aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--security/selinux/ss/avtab.c91
-rw-r--r--security/selinux/ss/avtab.h16
-rw-r--r--security/selinux/ss/conditional.c4
-rw-r--r--security/selinux/ss/policydb.c7
4 files changed, 82 insertions, 36 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 85705eb289e0..7551af1f7899 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) {
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index 0a90d939af93..d8edf8ca56d1 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -16,6 +16,9 @@
16 * This program is free software; you can redistribute it and/or modify 16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, version 2. 18 * the Free Software Foundation, version 2.
19 *
20 * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
21 * Tuned number of hash slots for avtab to reduce memory usage
19 */ 22 */
20#ifndef _SS_AVTAB_H_ 23#ifndef _SS_AVTAB_H_
21#define _SS_AVTAB_H_ 24#define _SS_AVTAB_H_
@@ -50,9 +53,13 @@ struct avtab_node {
50struct avtab { 53struct avtab {
51 struct avtab_node **htable; 54 struct avtab_node **htable;
52 u32 nel; /* number of elements */ 55 u32 nel; /* number of elements */
56 u32 nslot; /* number of hash slots */
57 u16 mask; /* mask to compute hash func */
58
53}; 59};
54 60
55int avtab_init(struct avtab *); 61int avtab_init(struct avtab *);
62int avtab_alloc(struct avtab *, u32);
56struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k); 63struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
57void avtab_destroy(struct avtab *h); 64void avtab_destroy(struct avtab *h);
58void avtab_hash_eval(struct avtab *h, char *tag); 65void avtab_hash_eval(struct avtab *h, char *tag);
@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified
74void avtab_cache_init(void); 81void avtab_cache_init(void);
75void avtab_cache_destroy(void); 82void avtab_cache_destroy(void);
76 83
77#define AVTAB_HASH_BITS 15 84#define MAX_AVTAB_HASH_BITS 13
78#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) 85#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
79#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) 86#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
80 87#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
81#define AVTAB_SIZE AVTAB_HASH_BUCKETS
82 88
83#endif /* _SS_AVTAB_H_ */ 89#endif /* _SS_AVTAB_H_ */
84 90
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index d2737edba541..45b93a827c80 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, void *fp)
456 456
457 len = le32_to_cpu(buf[0]); 457 len = le32_to_cpu(buf[0]);
458 458
459 rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
460 if (rc)
461 goto err;
462
459 for (i = 0; i < len; i++) { 463 for (i = 0; i < len; i++) {
460 node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); 464 node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
461 if (!node) 465 if (!node)
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index f05f97a2bc3a..5ecbad7d8b9f 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -177,18 +177,15 @@ static int policydb_init(struct policydb *p)
177 177
178 rc = roles_init(p); 178 rc = roles_init(p);
179 if (rc) 179 if (rc)
180 goto out_free_avtab; 180 goto out_free_symtab;
181 181
182 rc = cond_policydb_init(p); 182 rc = cond_policydb_init(p);
183 if (rc) 183 if (rc)
184 goto out_free_avtab; 184 goto out_free_symtab;
185 185
186out: 186out:
187 return rc; 187 return rc;
188 188
189out_free_avtab:
190 avtab_destroy(&p->te_avtab);
191
192out_free_symtab: 189out_free_symtab:
193 for (i = 0; i < SYM_NUM; i++) 190 for (i = 0; i < SYM_NUM; i++)
194 hashtab_destroy(p->symtab[i].table); 191 hashtab_destroy(p->symtab[i].table);