* [patch] Tuning avtab to reduce memory usage
@ 2007-08-21 4:29 Yuichi Nakamura
2007-08-21 13:47 ` Stephen Smalley
` (2 more replies)
0 siblings, 3 replies; 52+ messages in thread
From: Yuichi Nakamura @ 2007-08-21 4:29 UTC (permalink / raw)
To: selinux; +Cc: ynakam, Stephen Smalley, busybox, James Morris, Eric Paris,
kaigai
Hi.
I would like to propose patch that reduce memory usage of avtab again.
It reduces number of hash slots of avtab.
Previous patch was discussed in past threads.
http://marc.info/?t=118517459600001&r=1&w=2
http://marc.info/?t=118526972800008&r=1&w=2
http://marc.info/?t=118647810000001&r=1&w=2
0. Background
* In avtab_init:
h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
Number of hash table size is AVTAB_SIZE.
* In avtab.h
#define AVTAB_HASH_BITS 15
#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
#define AVTAB_SIZE AVTAB_HASH_BUCKETS
AVTAB_SIZE is 2^15 = 32768
So 32768 entries are allocated for avtab,
and 2 avtabs are used in policydb:
struct avtab te_avtab;
struct avtab te_cond_avtab;
If te rules are fewer than 32768,
unused entries are using memory.
In embedded devices, the rules tend to be fewer.
In my test system(SH architecture board), it is less than 10000 rules.
We want to save memory for embedded devices.
1. Explanation of patch
It decides number of hash slots dynamically based on number of rules.
There was 3 points I had to consider, according to previous discussion.
1) Tuning hash function
I tried to tune hash function(AVTAB_HASH) for avtab.
But I found it is better not to change hash function.
I compared 3 hash functions, default, jhash, hash_long.
default is default AVTAB_HASH.
jhash is function defined in linux/jhash.h.
hash_long is defined in linux/hash.h, I used it like following.
(int)(hash_long(((unsigned long)keyp->target_class)+
(((unsigned long)keyp->target_type)<<2)+
(((unsigned long)keyp->source_type)<<9) , bits))
According to benchmark result in 3.2(1)(2),
chain length of jhash/hash_long are better.
However, performance is worse.
So, I think it is better not to change hash function for avtab.
2) Number of dynamically allocated hash slots
I decided to allocate <number of rules>/4 hash slots.
Because performance remains almost the same,
see benchmark result in 3.2(2).
3) Max number of hash slots
There is max number of hash slots.
It was 32768 in previous patch.
I found we can reduce it to 8192.
Performance had not got worse, see benchmark result in 3.1(1).
I also replaced vmalloc with kmalloc to allocate hash slots.
2. Memory usage
I measured memory usage by /proc/memstat before/after tuning.
* Memory usage: SELinux before loading policy.
2720k is used.
* Memory usage: SELinux after loading policy(about 8000 rules) before patch
+1116k increase
* Memory usage: SELinux after loading poilcy(about 8000 rules) after patch.
configured AVTAB_HASH_BITS as "13"
+780k increase
-> improved 336k
3. Benchmark
3.1 Explanation of benchmark
To measure performance,
I measured time to call security_compute_av varying number of hash slots
and hash functions.
I measured time 10000 security_compute_av call from system boot,
using below code.
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd)
{
struct avc_node *node;
struct avc_entry entry, *p_ae;
int rc = 0;
u32 denied;
+ unsigned long long t0,t1;
+ unsigned long long t2=0;
+ static unsigned long long t3=0;
+ static int count = 0;
+ static int flag = 1;
+ static int max = 10000;
+ int i = 0;
rcu_read_lock();
+ if (flag && ss_initialized) {
+ t0 = sched_clock();
+ security_compute_av(ssid,tsid,tclass, requested, &entry.avd);
+ t1 = sched_clock();
+ t2 = t1 - t0;
+ t3 += t2;
+ count ++;
+ }
+ if (flag && (count == max)) {
+ flag = 0;
+ printk("SELinux:security_compute_av execution time:%Lu\n", t3);
+
+ }
security_compute_av is located at the entry of avc_has_perm_no_audit.
And nano second to call 10000 security_compute_av function is printed out.
3.2 Benchmark Result
1) Benchmark for full strict policy, x86 system
This benchmark is to see performance for PC system with full SELinux feature.
** Environment
* Policy: selinux-policy-strict-2.4.6-80.fc6
166741 unconditional rules
* Kernel: linux-2.6.22
* CPU: Pentium 4 2.26 GHz
* RAM: 1GB
In this environment, max number of hash slot is allocated.
** Result
* number of hash slots: 32768
longest chain length time to call security compute_av
Default hash 34 0.87(s)
jhash 21 1.10(s)
hash_long 17 0.99(s)
* hash slot: 8192
longest chain length time to call security compute_av
Default hash 97 1.00(s)
jhash 41 1.92(s)
hash_long 43 1.42(s)
* hash slot: 4096
longest chain length time to call security compute_av
Default hash 182 1.14(s)
jhash 41 3.33(s)
hash_long 43 2.19(s)
2) Benchmark for small policy, embedded system
This benchmark is to see performance for small system.
I made small refpolicy, and run on embedded CPU.
** Environment
* Policy: serefpolicy-2.4.6, build with targeted
8188 unconditional rules
* Kernel: linux-2.6.22
* CPU: SH-4(SH 7751R) 240Mhz
* RAM: 64M
** Result
* Number of slot(8192) = num of rules
longest chain length time to call security compute_av
Default hash 13 9.67(s)
hash_long 8 9.78(s)
* Number of slot(4096) = num of rules/2
longest chain length time to call security compute_av
Default hash 21 9.65(s)
hash_long 10 9.85(s)
* Number of slot(2048) = num of rules/4
longest chain length time to call security compute_av
Default hash 35 9.68(s)
hash_long 13 9.99(s)
* Number of slot(1024) = num of rules/8
longest chain length time to call security compute_av
Default hash 64 9.78(s)
hash_long 19 10.25(s)
Next is a patch.
Signed-Off-By: Yuichi Nakamura <ynakam@hitachisoft.jp>
----
avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--------------
avtab.h | 13 +++++++-----
conditional.c | 6 +++++
policydb.c | 9 ++------
4 files changed, 64 insertions(+), 25 deletions(-)
diff -ur security/selinux.notuning/ss/avtab.c security/selinux/ss/avtab.c
--- security/selinux.notuning/ss/avtab.c 2007-08-05 14:30:24.000000000 +0900
+++ security/selinux/ss/avtab.c 2007-08-21 10:15:09.000000000 +0900
@@ -16,17 +16,16 @@
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/errno.h>
#include "avtab.h"
#include "policydb.h"
-#define AVTAB_HASH(keyp) \
+#define AVTAB_HASH(keyp,mask) \
((keyp->target_class + \
(keyp->target_type << 2) + \
(keyp->source_type << 9)) & \
- AVTAB_HASH_MASK)
+ mask)
static struct kmem_cache *avtab_node_cachep;
@@ -62,7 +61,7 @@
if (!h)
return -EINVAL;
- hvalue = AVTAB_HASH(key);
+ hvalue = AVTAB_HASH(key,h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
@@ -102,7 +101,7 @@
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = AVTAB_HASH(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
@@ -135,7 +134,7 @@
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = AVTAB_HASH(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -170,7 +169,7 @@
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = AVTAB_HASH(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -228,7 +227,7 @@
if (!h || !h->htable)
return;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
while (cur != NULL) {
temp = cur;
@@ -237,21 +236,48 @@
}
h->htable[i] = NULL;
}
- vfree(h->htable);
+ kfree(h->htable);
h->htable = NULL;
+ h->nslot = 0;
+ h->mask = 0;
}
-
int avtab_init(struct avtab *h)
{
+ h->htable = NULL;
+ h->nel = 0;
+ return 0;
+}
+
+int avtab_alloc(struct avtab *h, int nrules) {
int i;
+ u16 mask;
+ u32 shift = 0;
+ u32 work = nrules;
+ u32 nslot;
+
+ while(work) {
+ work = work>>1;
+ shift++;
+ }
+ if (shift > 2) {
+ shift = shift - 2;
+ }
+ nslot = 1 << shift;
+ if (nslot > MAX_AVTAB_SIZE) {
+ nslot = MAX_AVTAB_SIZE;
+ }
+ mask = nslot - 1;
- h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
+ h->htable = kmalloc(sizeof(*(h->htable)) * nslot, GFP_KERNEL);
if (!h->htable)
return -ENOMEM;
- for (i = 0; i < AVTAB_SIZE; i++)
+ for (i = 0; i < nslot; i++)
h->htable[i] = NULL;
h->nel = 0;
+ h->nslot = nslot;
+ h->mask = mask;
+ printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n", h->nslot, nrules);
return 0;
}
@@ -262,7 +288,7 @@
slots_used = 0;
max_chain_len = 0;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
if (cur) {
slots_used++;
@@ -278,7 +304,7 @@
}
printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
- "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
+ "chain length %d\n", tag, h->nel, slots_used, h->nslot,
max_chain_len);
}
@@ -419,6 +445,13 @@
rc = -EINVAL;
goto bad;
}
+
+ rc = avtab_alloc(a, nel);
+ if (rc) {
+ rc = -ENOMEM;
+ goto bad;
+ }
+
for (i = 0; i < nel; i++) {
rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
if (rc) {
diff -ur security/selinux.notuning/ss/avtab.h security/selinux/ss/avtab.h
--- security/selinux.notuning/ss/avtab.h 2007-08-05 14:30:24.000000000 +0900
+++ security/selinux/ss/avtab.h 2007-08-21 09:56:51.000000000 +0900
@@ -50,9 +50,13 @@
struct avtab {
struct avtab_node **htable;
u32 nel; /* number of elements */
+ u32 nslot; /* number of hash slots */
+ u16 mask; /* mask to compute hash func */
+
};
int avtab_init(struct avtab *);
+int avtab_alloc(struct avtab *, int);
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
void avtab_destroy(struct avtab *h);
void avtab_hash_eval(struct avtab *h, char *tag);
@@ -74,11 +78,10 @@
void avtab_cache_init(void);
void avtab_cache_destroy(void);
-#define AVTAB_HASH_BITS 15
-#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
-#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
-
-#define AVTAB_SIZE AVTAB_HASH_BUCKETS
+#define MAX_AVTAB_HASH_BITS 13
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
#endif /* _SS_AVTAB_H_ */
diff -ur security/selinux.notuning/ss/conditional.c security/selinux/ss/conditional.c
--- security/selinux.notuning/ss/conditional.c 2007-08-05 14:30:24.000000000 +0900
+++ security/selinux/ss/conditional.c 2007-08-21 09:56:26.000000000 +0900
@@ -455,6 +455,12 @@
return -1;
len = le32_to_cpu(buf[0]);
+
+ rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
+ if (rc) {
+ rc = -ENOMEM;
+ goto err;
+ }
for (i = 0; i < len; i++) {
node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
diff -ur security/selinux.notuning/ss/policydb.c security/selinux/ss/policydb.c
--- security/selinux.notuning/ss/policydb.c 2007-08-05 14:30:24.000000000 +0900
+++ security/selinux/ss/policydb.c 2007-08-21 11:50:38.000000000 +0900
@@ -172,22 +172,19 @@
rc = avtab_init(&p->te_avtab);
if (rc)
- goto out_free_symtab;
+ goto out_free_symtab;
rc = roles_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
rc = cond_policydb_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
out:
return rc;
-out_free_avtab:
- avtab_destroy(&p->te_avtab);
-
out_free_symtab:
for (i = 0; i < SYM_NUM; i++)
hashtab_destroy(p->symtab[i].table);
Regards,
--
Yuichi Nakamura
Hitachi Software Engineering Co., Ltd.
Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/
SELinux Policy Editor: http://seedit.sourceforge.net/
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 4:29 [patch] Tuning avtab to reduce memory usage Yuichi Nakamura
@ 2007-08-21 13:47 ` Stephen Smalley
2007-08-21 14:19 ` Yuichi Nakamura
2007-08-21 15:11 ` Paul Moore
2007-08-21 14:00 ` [patch] Tuning avtab to reduce memory usage James Morris
2007-08-21 19:43 ` J. Tang
2 siblings, 2 replies; 52+ messages in thread
From: Stephen Smalley @ 2007-08-21 13:47 UTC (permalink / raw)
To: Yuichi Nakamura; +Cc: selinux, busybox, James Morris, Eric Paris, Kaigai Kohei
On Tue, 2007-08-21 at 13:29 +0900, Yuichi Nakamura wrote:
> Hi.
>
> I would like to propose patch that reduce memory usage of avtab again.
> It reduces number of hash slots of avtab.
> Previous patch was discussed in past threads.
> http://marc.info/?t=118517459600001&r=1&w=2
> http://marc.info/?t=118526972800008&r=1&w=2
> http://marc.info/?t=118647810000001&r=1&w=2
>
> 0. Background
> * In avtab_init:
> h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
> Number of hash table size is AVTAB_SIZE.
>
> * In avtab.h
> #define AVTAB_HASH_BITS 15
> #define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
> #define AVTAB_SIZE AVTAB_HASH_BUCKETS
>
> AVTAB_SIZE is 2^15 = 32768
>
> So 32768 entries are allocated for avtab,
> and 2 avtabs are used in policydb:
> struct avtab te_avtab;
> struct avtab te_cond_avtab;
>
> If te rules are fewer than 32768,
> unused entries are using memory.
>
> In embedded devices, the rules tend to be fewer.
> In my test system(SH architecture board), it is less than 10000 rules.
> We want to save memory for embedded devices.
>
> 1. Explanation of patch
> It decides number of hash slots dynamically based on number of rules.
> There was 3 points I had to consider, according to previous discussion.
> 1) Tuning hash function
> I tried to tune hash function(AVTAB_HASH) for avtab.
> But I found it is better not to change hash function.
>
> I compared 3 hash functions, default, jhash, hash_long.
> default is default AVTAB_HASH.
> jhash is function defined in linux/jhash.h.
> hash_long is defined in linux/hash.h, I used it like following.
> (int)(hash_long(((unsigned long)keyp->target_class)+
> (((unsigned long)keyp->target_type)<<2)+
> (((unsigned long)keyp->source_type)<<9) , bits))
> According to benchmark result in 3.2(1)(2),
> chain length of jhash/hash_long are better.
> However, performance is worse.
> So, I think it is better not to change hash function for avtab.
>
> 2) Number of dynamically allocated hash slots
> I decided to allocate <number of rules>/4 hash slots.
> Because performance remains almost the same,
> see benchmark result in 3.2(2).
>
> 3) Max number of hash slots
> There is max number of hash slots.
> It was 32768 in previous patch.
> I found we can reduce it to 8192.
> Performance had not got worse, see benchmark result in 3.1(1).
> I also replaced vmalloc with kmalloc to allocate hash slots.
>
>
> 2. Memory usage
> I measured memory usage by /proc/memstat before/after tuning.
>
> * Memory usage: SELinux before loading policy.
> 2720k is used.
>
> * Memory usage: SELinux after loading policy(about 8000 rules) before patch
> +1116k increase
>
> * Memory usage: SELinux after loading poilcy(about 8000 rules) after patch.
> configured AVTAB_HASH_BITS as "13"
> +780k increase
> -> improved 336k
>
>
> 3. Benchmark
> 3.1 Explanation of benchmark
> To measure performance,
> I measured time to call security_compute_av varying number of hash slots
> and hash functions.
> I measured time 10000 security_compute_av call from system boot,
> using below code.
>
> int avc_has_perm_noaudit(u32 ssid, u32 tsid,
> u16 tclass, u32 requested,
> struct av_decision *avd)
> {
> struct avc_node *node;
> struct avc_entry entry, *p_ae;
> int rc = 0;
> u32 denied;
> + unsigned long long t0,t1;
> + unsigned long long t2=0;
> + static unsigned long long t3=0;
> + static int count = 0;
> + static int flag = 1;
> + static int max = 10000;
> + int i = 0;
>
>
> rcu_read_lock();
> + if (flag && ss_initialized) {
> + t0 = sched_clock();
> + security_compute_av(ssid,tsid,tclass, requested, &entry.avd);
> + t1 = sched_clock();
> + t2 = t1 - t0;
> + t3 += t2;
> + count ++;
> + }
> + if (flag && (count == max)) {
> + flag = 0;
> + printk("SELinux:security_compute_av execution time:%Lu\n", t3);
> +
> + }
>
> security_compute_av is located at the entry of avc_has_perm_no_audit.
> And nano second to call 10000 security_compute_av function is printed out.
>
>
> 3.2 Benchmark Result
> 1) Benchmark for full strict policy, x86 system
> This benchmark is to see performance for PC system with full SELinux feature.
> ** Environment
> * Policy: selinux-policy-strict-2.4.6-80.fc6
> 166741 unconditional rules
> * Kernel: linux-2.6.22
> * CPU: Pentium 4 2.26 GHz
> * RAM: 1GB
> In this environment, max number of hash slot is allocated.
>
> ** Result
> * number of hash slots: 32768
> longest chain length time to call security compute_av
> Default hash 34 0.87(s)
> jhash 21 1.10(s)
> hash_long 17 0.99(s)
>
> * hash slot: 8192
> longest chain length time to call security compute_av
> Default hash 97 1.00(s)
> jhash 41 1.92(s)
> hash_long 43 1.42(s)
>
> * hash slot: 4096
> longest chain length time to call security compute_av
> Default hash 182 1.14(s)
> jhash 41 3.33(s)
> hash_long 43 2.19(s)
>
>
> 2) Benchmark for small policy, embedded system
> This benchmark is to see performance for small system.
> I made small refpolicy, and run on embedded CPU.
>
> ** Environment
> * Policy: serefpolicy-2.4.6, build with targeted
> 8188 unconditional rules
> * Kernel: linux-2.6.22
> * CPU: SH-4(SH 7751R) 240Mhz
> * RAM: 64M
>
> ** Result
> * Number of slot(8192) = num of rules
> longest chain length time to call security compute_av
> Default hash 13 9.67(s)
> hash_long 8 9.78(s)
>
> * Number of slot(4096) = num of rules/2
> longest chain length time to call security compute_av
> Default hash 21 9.65(s)
> hash_long 10 9.85(s)
>
> * Number of slot(2048) = num of rules/4
> longest chain length time to call security compute_av
> Default hash 35 9.68(s)
> hash_long 13 9.99(s)
>
> * Number of slot(1024) = num of rules/8
> longest chain length time to call security compute_av
> Default hash 64 9.78(s)
> hash_long 19 10.25(s)
The divergence in times between strict/large policy vs. targeted/small
policy seems curious.
Is it because targeted/small policy makes more use of type attributes,
making the nested ebitmap_for_each_bit loops much longer?
We likely should look at optimizing the ebitmap code, or replacing it
with the native kernel bitmaps (include/linux/bitmap.h, lib/bitmap.c).
For example, ebitmap_next could possibly use find_next_bit().
>
> Next is a patch.
> Signed-Off-By: Yuichi Nakamura <ynakam@hitachisoft.jp>
Looks ok, but a few coding style issues. Run ./scripts/checkpatch.pl on
it and fix all issues please. And make it apply with patch -p1 (and use
diffstat -p1 to generate the diffstat).
> ----
> avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--------------
> avtab.h | 13 +++++++-----
> conditional.c | 6 +++++
> policydb.c | 9 ++------
> 4 files changed, 64 insertions(+), 25 deletions(-)
> diff -ur security/selinux.notuning/ss/avtab.c security/selinux/ss/avtab.c
> --- security/selinux.notuning/ss/avtab.c 2007-08-05 14:30:24.000000000 +0900
> +++ security/selinux/ss/avtab.c 2007-08-21 10:15:09.000000000 +0900
> @@ -16,17 +16,16 @@
>
> #include <linux/kernel.h>
> #include <linux/slab.h>
> -#include <linux/vmalloc.h>
> #include <linux/errno.h>
>
> #include "avtab.h"
> #include "policydb.h"
>
> -#define AVTAB_HASH(keyp) \
> +#define AVTAB_HASH(keyp,mask) \
> ((keyp->target_class + \
> (keyp->target_type << 2) + \
> (keyp->source_type << 9)) & \
> - AVTAB_HASH_MASK)
> + mask)
>
> static struct kmem_cache *avtab_node_cachep;
>
> @@ -62,7 +61,7 @@
> if (!h)
> return -EINVAL;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = AVTAB_HASH(key,h->mask);
> for (prev = NULL, cur = h->htable[hvalue];
> cur;
> prev = cur, cur = cur->next) {
> @@ -102,7 +101,7 @@
>
> if (!h)
> return NULL;
> - hvalue = AVTAB_HASH(key);
> + hvalue = AVTAB_HASH(key, h->mask);
> for (prev = NULL, cur = h->htable[hvalue];
> cur;
> prev = cur, cur = cur->next) {
> @@ -135,7 +134,7 @@
> if (!h)
> return NULL;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = AVTAB_HASH(key, h->mask);
> for (cur = h->htable[hvalue]; cur; cur = cur->next) {
> if (key->source_type == cur->key.source_type &&
> key->target_type == cur->key.target_type &&
> @@ -170,7 +169,7 @@
> if (!h)
> return NULL;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = AVTAB_HASH(key, h->mask);
> for (cur = h->htable[hvalue]; cur; cur = cur->next) {
> if (key->source_type == cur->key.source_type &&
> key->target_type == cur->key.target_type &&
> @@ -228,7 +227,7 @@
> if (!h || !h->htable)
> return;
>
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < h->nslot; i++) {
> cur = h->htable[i];
> while (cur != NULL) {
> temp = cur;
> @@ -237,21 +236,48 @@
> }
> h->htable[i] = NULL;
> }
> - vfree(h->htable);
> + kfree(h->htable);
> h->htable = NULL;
> + h->nslot = 0;
> + h->mask = 0;
> }
>
> -
> int avtab_init(struct avtab *h)
> {
> + h->htable = NULL;
> + h->nel = 0;
> + return 0;
> +}
> +
> +int avtab_alloc(struct avtab *h, int nrules) {
> int i;
> + u16 mask;
> + u32 shift = 0;
> + u32 work = nrules;
> + u32 nslot;
> +
> + while(work) {
> + work = work>>1;
> + shift++;
> + }
> + if (shift > 2) {
> + shift = shift - 2;
> + }
> + nslot = 1 << shift;
> + if (nslot > MAX_AVTAB_SIZE) {
> + nslot = MAX_AVTAB_SIZE;
> + }
> + mask = nslot - 1;
>
> - h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
> + h->htable = kmalloc(sizeof(*(h->htable)) * nslot, GFP_KERNEL);
> if (!h->htable)
> return -ENOMEM;
> - for (i = 0; i < AVTAB_SIZE; i++)
> + for (i = 0; i < nslot; i++)
> h->htable[i] = NULL;
> h->nel = 0;
> + h->nslot = nslot;
> + h->mask = mask;
> + printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n", h->nslot, nrules);
> return 0;
> }
>
> @@ -262,7 +288,7 @@
>
> slots_used = 0;
> max_chain_len = 0;
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < h->nslot; i++) {
> cur = h->htable[i];
> if (cur) {
> slots_used++;
> @@ -278,7 +304,7 @@
> }
>
> printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
> - "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
> + "chain length %d\n", tag, h->nel, slots_used, h->nslot,
> max_chain_len);
> }
>
> @@ -419,6 +445,13 @@
> rc = -EINVAL;
> goto bad;
> }
> +
> + rc = avtab_alloc(a, nel);
> + if (rc) {
> + rc = -ENOMEM;
> + goto bad;
> + }
> +
> for (i = 0; i < nel; i++) {
> rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
> if (rc) {
> diff -ur security/selinux.notuning/ss/avtab.h security/selinux/ss/avtab.h
> --- security/selinux.notuning/ss/avtab.h 2007-08-05 14:30:24.000000000 +0900
> +++ security/selinux/ss/avtab.h 2007-08-21 09:56:51.000000000 +0900
> @@ -50,9 +50,13 @@
> struct avtab {
> struct avtab_node **htable;
> u32 nel; /* number of elements */
> + u32 nslot; /* number of hash slots */
> + u16 mask; /* mask to compute hash func */
> +
> };
>
> int avtab_init(struct avtab *);
> +int avtab_alloc(struct avtab *, int);
> struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
> void avtab_destroy(struct avtab *h);
> void avtab_hash_eval(struct avtab *h, char *tag);
> @@ -74,11 +78,10 @@
> void avtab_cache_init(void);
> void avtab_cache_destroy(void);
>
> -#define AVTAB_HASH_BITS 15
> -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
> -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
> -
> -#define AVTAB_SIZE AVTAB_HASH_BUCKETS
> +#define MAX_AVTAB_HASH_BITS 13
> +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
> +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
> +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
>
> #endif /* _SS_AVTAB_H_ */
>
> diff -ur security/selinux.notuning/ss/conditional.c security/selinux/ss/conditional.c
> --- security/selinux.notuning/ss/conditional.c 2007-08-05 14:30:24.000000000 +0900
> +++ security/selinux/ss/conditional.c 2007-08-21 09:56:26.000000000 +0900
> @@ -455,6 +455,12 @@
> return -1;
>
> len = le32_to_cpu(buf[0]);
> +
> + rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
> + if (rc) {
> + rc = -ENOMEM;
> + goto err;
> + }
>
> for (i = 0; i < len; i++) {
> node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
> diff -ur security/selinux.notuning/ss/policydb.c security/selinux/ss/policydb.c
> --- security/selinux.notuning/ss/policydb.c 2007-08-05 14:30:24.000000000 +0900
> +++ security/selinux/ss/policydb.c 2007-08-21 11:50:38.000000000 +0900
> @@ -172,22 +172,19 @@
>
> rc = avtab_init(&p->te_avtab);
> if (rc)
> - goto out_free_symtab;
> + goto out_free_symtab;
>
> rc = roles_init(p);
> if (rc)
> - goto out_free_avtab;
> + goto out_free_symtab;
>
> rc = cond_policydb_init(p);
> if (rc)
> - goto out_free_avtab;
> + goto out_free_symtab;
>
> out:
> return rc;
>
> -out_free_avtab:
> - avtab_destroy(&p->te_avtab);
> -
> out_free_symtab:
> for (i = 0; i < SYM_NUM; i++)
> hashtab_destroy(p->symtab[i].table);
>
>
> Regards,
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 4:29 [patch] Tuning avtab to reduce memory usage Yuichi Nakamura
2007-08-21 13:47 ` Stephen Smalley
@ 2007-08-21 14:00 ` James Morris
2007-08-22 2:55 ` Yuichi Nakamura
2007-08-21 19:43 ` J. Tang
2 siblings, 1 reply; 52+ messages in thread
From: James Morris @ 2007-08-21 14:00 UTC (permalink / raw)
To: Yuichi Nakamura; +Cc: selinux, Stephen Smalley, busybox, Eric Paris, kaigai
On Tue, 21 Aug 2007, Yuichi Nakamura wrote:
> Hi.
>
> I would like to propose patch that reduce memory usage of avtab again.
This looks good, although there are some coding style and other issues
which need to be fixed. Also see Documentation/SubmittingPatches and
Documentation/CodingStyle in the kernel tree.
>
> Next is a patch.
> Signed-Off-By: Yuichi Nakamura <ynakam@hitachisoft.jp>
> ----
Needs to be 3 --- otherwise scripts will break.
> avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--------------
> avtab.h | 13 +++++++-----
> conditional.c | 6 +++++
> policydb.c | 9 ++------
> 4 files changed, 64 insertions(+), 25 deletions(-)
diffstat -p1
>
> diff -ur security/selinux.notuning/ss/avtab.c security/selinux/ss/avtab.c
diff -purN
> + hvalue = AVTAB_HASH(key,h->mask);
Add a space after the comma.
Also, AVTAB_HASH should be converted to a static inline.
> + while(work) {
Space after while.
> + if (shift > 2) {
> + shift = shift - 2;
> + }
No need for braces for a one-line statement.
> + nslot = 1 << shift;
> + if (nslot > MAX_AVTAB_SIZE) {
> + nslot = MAX_AVTAB_SIZE;
> + }
Ditto.
> - h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
> + h->htable = kmalloc(sizeof(*(h->htable)) * nslot, GFP_KERNEL);
Use kcalloc(), then consider the effect of the memory zeroing & how much
further code can be removed.
> + printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n", h->nslot, nrules);
This line is too long.
> + rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
> + if (rc) {
> + rc = -ENOMEM;
Why are you resetting rc to the same value?
> - goto out_free_symtab;
> + goto out_free_symtab;
Looks like you added a trailing tab.
- James
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 13:47 ` Stephen Smalley
@ 2007-08-21 14:19 ` Yuichi Nakamura
2007-08-21 15:11 ` Paul Moore
1 sibling, 0 replies; 52+ messages in thread
From: Yuichi Nakamura @ 2007-08-21 14:19 UTC (permalink / raw)
To: Stephen Smalley
Cc: himainu-ynakam, ynakam, selinux, busybox, jmorris, eparis, kaigai
On Tue, 21 Aug 2007 09:47:38 -0400
Stephen Smalley wrote:
> On Tue, 2007-08-21 at 13:29 +0900, Yuichi Nakamura wrote:
<snip>
>
> The divergence in times between strict/large policy vs. targeted/small
> policy seems curious.
>
> Is it because targeted/small policy makes more use of type attributes,
> making the nested ebitmap_for_each_bit loops much longer?
I think so.
Targeted policy uses more attributes.
For example,
Number of attribute for kernel_t, init_t, initrc_t is:
strict policy -> 8, 8, 16
small refpolicy(build as targeted)-> 24,24,32
> We likely should look at optimizing the ebitmap code, or replacing it
> with the native kernel bitmaps (include/linux/bitmap.h, lib/bitmap.c).
> For example, ebitmap_next could possibly use find_next_bit().
I want to look after this patch is done..
>
> >
> > Next is a patch.
> > Signed-Off-By: Yuichi Nakamura <ynakam@hitachisoft.jp>
>
> Looks ok, but a few coding style issues. Run ./scripts/checkpatch.pl on
> it and fix all issues please. And make it apply with patch -p1 (and use
> diffstat -p1 to generate the diffstat).
Thanks, about them I will work tomorrow :)
> > > ----
> > avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--------------
> > avtab.h | 13 +++++++-----
> > conditional.c | 6 +++++
> > policydb.c | 9 ++------
> > 4 files changed, 64 insertions(+), 25 deletions(-)
>
> > diff -ur security/selinux.notuning/ss/avtab.c security/selinux/ss/avtab.c
> > --- security/selinux.notuning/ss/avtab.c 2007-08-05 14:30:24.000000000 +0900
> > +++ security/selinux/ss/avtab.c 2007-08-21 10:15:09.000000000 +0900
> > @@ -16,17 +16,16 @@
> >
> > #include <linux/kernel.h>
> > #include <linux/slab.h>
> > -#include <linux/vmalloc.h>
> > #include <linux/errno.h>
> >
> > #include "avtab.h"
> > #include "policydb.h"
> >
> > -#define AVTAB_HASH(keyp) \
> > +#define AVTAB_HASH(keyp,mask) \
> > ((keyp->target_class + \
> > (keyp->target_type << 2) + \
> > (keyp->source_type << 9)) & \
> > - AVTAB_HASH_MASK)
> > + mask)
> >
> > static struct kmem_cache *avtab_node_cachep;
> >
> > @@ -62,7 +61,7 @@
> > if (!h)
> > return -EINVAL;
> >
> > - hvalue = AVTAB_HASH(key);
> > + hvalue = AVTAB_HASH(key,h->mask);
> > for (prev = NULL, cur = h->htable[hvalue];
> > cur;
> > prev = cur, cur = cur->next) {
> > @@ -102,7 +101,7 @@
> >
> > if (!h)
> > return NULL;
> > - hvalue = AVTAB_HASH(key);
> > + hvalue = AVTAB_HASH(key, h->mask);
> > for (prev = NULL, cur = h->htable[hvalue];
> > cur;
> > prev = cur, cur = cur->next) {
> > @@ -135,7 +134,7 @@
> > if (!h)
> > return NULL;
> >
> > - hvalue = AVTAB_HASH(key);
> > + hvalue = AVTAB_HASH(key, h->mask);
> > for (cur = h->htable[hvalue]; cur; cur = cur->next) {
> > if (key->source_type == cur->key.source_type &&
> > key->target_type == cur->key.target_type &&
> > @@ -170,7 +169,7 @@
> > if (!h)
> > return NULL;
> >
> > - hvalue = AVTAB_HASH(key);
> > + hvalue = AVTAB_HASH(key, h->mask);
> > for (cur = h->htable[hvalue]; cur; cur = cur->next) {
> > if (key->source_type == cur->key.source_type &&
> > key->target_type == cur->key.target_type &&
> > @@ -228,7 +227,7 @@
> > if (!h || !h->htable)
> > return;
> >
> > - for (i = 0; i < AVTAB_SIZE; i++) {
> > + for (i = 0; i < h->nslot; i++) {
> > cur = h->htable[i];
> > while (cur != NULL) {
> > temp = cur;
> > @@ -237,21 +236,48 @@
> > }
> > h->htable[i] = NULL;
> > }
> > - vfree(h->htable);
> > + kfree(h->htable);
> > h->htable = NULL;
> > + h->nslot = 0;
> > + h->mask = 0;
> > }
> >
> > -
> > int avtab_init(struct avtab *h)
> > {
> > + h->htable = NULL;
> > + h->nel = 0;
> > + return 0;
> > +}
> > +
> > +int avtab_alloc(struct avtab *h, int nrules) {
> > int i;
> > + u16 mask;
> > + u32 shift = 0;
> > + u32 work = nrules;
> > + u32 nslot;
> > +
> > + while(work) {
> > + work = work>>1;
> > + shift++;
> > + }
> > + if (shift > 2) {
> > + shift = shift - 2;
> > + }
> > + nslot = 1 << shift;
> > + if (nslot > MAX_AVTAB_SIZE) {
> > + nslot = MAX_AVTAB_SIZE;
> > + }
> > + mask = nslot - 1;
> >
> > - h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
> > + h->htable = kmalloc(sizeof(*(h->htable)) * nslot, GFP_KERNEL);
> > if (!h->htable)
> > return -ENOMEM;
> > - for (i = 0; i < AVTAB_SIZE; i++)
> > + for (i = 0; i < nslot; i++)
> > h->htable[i] = NULL;
> > h->nel = 0;
> > + h->nslot = nslot;
> > + h->mask = mask;
> > + printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n", h->nslot, nrules);
> > return 0;
> > }
> >
> > @@ -262,7 +288,7 @@
> >
> > slots_used = 0;
> > max_chain_len = 0;
> > - for (i = 0; i < AVTAB_SIZE; i++) {
> > + for (i = 0; i < h->nslot; i++) {
> > cur = h->htable[i];
> > if (cur) {
> > slots_used++;
> > @@ -278,7 +304,7 @@
> > }
> >
> > printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
> > - "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
> > + "chain length %d\n", tag, h->nel, slots_used, h->nslot,
> > max_chain_len);
> > }
> >
> > @@ -419,6 +445,13 @@
> > rc = -EINVAL;
> > goto bad;
> > }
> > +
> > + rc = avtab_alloc(a, nel);
> > + if (rc) {
> > + rc = -ENOMEM;
> > + goto bad;
> > + }
> > +
> > for (i = 0; i < nel; i++) {
> > rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
> > if (rc) {
> > diff -ur security/selinux.notuning/ss/avtab.h security/selinux/ss/avtab.h
> > --- security/selinux.notuning/ss/avtab.h 2007-08-05 14:30:24.000000000 +0900
> > +++ security/selinux/ss/avtab.h 2007-08-21 09:56:51.000000000 +0900
> > @@ -50,9 +50,13 @@
> > struct avtab {
> > struct avtab_node **htable;
> > u32 nel; /* number of elements */
> > + u32 nslot; /* number of hash slots */
> > + u16 mask; /* mask to compute hash func */
> > +
> > };
> >
> > int avtab_init(struct avtab *);
> > +int avtab_alloc(struct avtab *, int);
> > struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
> > void avtab_destroy(struct avtab *h);
> > void avtab_hash_eval(struct avtab *h, char *tag);
> > @@ -74,11 +78,10 @@
> > void avtab_cache_init(void);
> > void avtab_cache_destroy(void);
> >
> > -#define AVTAB_HASH_BITS 15
> > -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
> > -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
> > -
> > -#define AVTAB_SIZE AVTAB_HASH_BUCKETS
> > +#define MAX_AVTAB_HASH_BITS 13
> > +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
> > +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
> > +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
> >
> > #endif /* _SS_AVTAB_H_ */
> >
> > diff -ur security/selinux.notuning/ss/conditional.c security/selinux/ss/conditional.c
> > --- security/selinux.notuning/ss/conditional.c 2007-08-05 14:30:24.000000000 +0900
> > +++ security/selinux/ss/conditional.c 2007-08-21 09:56:26.000000000 +0900
> > @@ -455,6 +455,12 @@
> > return -1;
> >
> > len = le32_to_cpu(buf[0]);
> > +
> > + rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
> > + if (rc) {
> > + rc = -ENOMEM;
> > + goto err;
> > + }
> >
> > for (i = 0; i < len; i++) {
> > node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
> > diff -ur security/selinux.notuning/ss/policydb.c security/selinux/ss/policydb.c
> > --- security/selinux.notuning/ss/policydb.c 2007-08-05 14:30:24.000000000 +0900
> > +++ security/selinux/ss/policydb.c 2007-08-21 11:50:38.000000000 +0900
> > @@ -172,22 +172,19 @@
> >
> > rc = avtab_init(&p->te_avtab);
> > if (rc)
> > - goto out_free_symtab;
> > + goto out_free_symtab;
> >
> > rc = roles_init(p);
> > if (rc)
> > - goto out_free_avtab;
> > + goto out_free_symtab;
> >
> > rc = cond_policydb_init(p);
> > if (rc)
> > - goto out_free_avtab;
> > + goto out_free_symtab;
> >
> > out:
> > return rc;
> >
> > -out_free_avtab:
> > - avtab_destroy(&p->te_avtab);
> > -
> > out_free_symtab:
> > for (i = 0; i < SYM_NUM; i++)
> > hashtab_destroy(p->symtab[i].table);
> >
> >
> > Regards,
> --
> Stephen Smalley
> National Security Agency
>
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 13:47 ` Stephen Smalley
2007-08-21 14:19 ` Yuichi Nakamura
@ 2007-08-21 15:11 ` Paul Moore
2007-08-21 16:37 ` Stephen Smalley
1 sibling, 1 reply; 52+ messages in thread
From: Paul Moore @ 2007-08-21 15:11 UTC (permalink / raw)
To: Stephen Smalley
Cc: Yuichi Nakamura, selinux, James Morris, Eric Paris, Kaigai Kohei
On Tuesday, August 21 2007 9:47:38 am Stephen Smalley wrote:
> We likely should look at optimizing the ebitmap code, or replacing it
> with the native kernel bitmaps (include/linux/bitmap.h, lib/bitmap.c).
> For example, ebitmap_next could possibly use find_next_bit().
[Removed the busybox list because I'm sure they don't care]
Would the fact that the MLS category bitmaps grow to 1024 bits be a concern
with using a single contiguous bitmap instead of the sparse bitmap the
ebitmap currently uses? Granted, in the worst case of c0.c1023 the kernel
bitmap would most certainly be better but I wonder what the common case is
(and if the MLS compartments even factor into the discussion) and which type
is better suited to handle this case.
--
paul moore
linux security @ hp
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 15:11 ` Paul Moore
@ 2007-08-21 16:37 ` Stephen Smalley
2007-08-21 16:55 ` Paul Moore
0 siblings, 1 reply; 52+ messages in thread
From: Stephen Smalley @ 2007-08-21 16:37 UTC (permalink / raw)
To: Paul Moore
Cc: Yuichi Nakamura, selinux, James Morris, Eric Paris, Kaigai Kohei
On Tue, 2007-08-21 at 11:11 -0400, Paul Moore wrote:
> On Tuesday, August 21 2007 9:47:38 am Stephen Smalley wrote:
> > We likely should look at optimizing the ebitmap code, or replacing it
> > with the native kernel bitmaps (include/linux/bitmap.h, lib/bitmap.c).
> > For example, ebitmap_next could possibly use find_next_bit().
>
> [Removed the busybox list because I'm sure they don't care]
>
> Would the fact that the MLS category bitmaps grow to 1024 bits be a concern
> with using a single contiguous bitmap instead of the sparse bitmap the
> ebitmap currently uses? Granted, in the worst case of c0.c1023 the kernel
> bitmap would most certainly be better but I wonder what the common case is
> (and if the MLS compartments even factor into the discussion) and which type
> is better suited to handle this case.
Even if we retain the ebitmap type as a sparse bitmap, I think we can do
some optimization of its internals, possibly leveraging things like
find_next_bit(), to speed up the loops that were introduced when we
optimized the avtab memory layout by pushing attributes down into the
kernel policy (policy.20).
Trying Yuichi's simple instrumentation of security_compute_av, I see a
huge difference in security_compute_av times between policy.19 and
policy.20. We knew it would slow security_compute_av down (standard
tradeoff between runtime performance and memory use), but the thinking
at the time was that it wouldn't matter because of the AVC. But we do
have to bound our worst case latency.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 16:37 ` Stephen Smalley
@ 2007-08-21 16:55 ` Paul Moore
2007-08-22 9:25 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: Paul Moore @ 2007-08-21 16:55 UTC (permalink / raw)
To: Stephen Smalley
Cc: Yuichi Nakamura, selinux, James Morris, Eric Paris, Kaigai Kohei
On Tuesday, August 21 2007 12:37:49 pm Stephen Smalley wrote:
> On Tue, 2007-08-21 at 11:11 -0400, Paul Moore wrote:
> > On Tuesday, August 21 2007 9:47:38 am Stephen Smalley wrote:
> > > We likely should look at optimizing the ebitmap code, or replacing it
> > > with the native kernel bitmaps (include/linux/bitmap.h, lib/bitmap.c).
> > > For example, ebitmap_next could possibly use find_next_bit().
> >
> > [Removed the busybox list because I'm sure they don't care]
> >
> > Would the fact that the MLS category bitmaps grow to 1024 bits be a
> > concern with using a single contiguous bitmap instead of the sparse
> > bitmap the ebitmap currently uses? Granted, in the worst case of
> > c0.c1023 the kernel bitmap would most certainly be better but I wonder
> > what the common case is (and if the MLS compartments even factor into the
> > discussion) and which type is better suited to handle this case.
>
> Even if we retain the ebitmap type as a sparse bitmap, I think we can do
> some optimization of its internals, possibly leveraging things like
> find_next_bit(), to speed up the loops that were introduced when we
> optimized the avtab memory layout by pushing attributes down into the
> kernel policy (policy.20).
>
> Trying Yuichi's simple instrumentation of security_compute_av, I see a
> huge difference in security_compute_av times between policy.19 and
> policy.20. We knew it would slow security_compute_av down (standard
> tradeoff between runtime performance and memory use), but the thinking
> at the time was that it wouldn't matter because of the AVC. But we do
> have to bound our worst case latency.
I understand, I was just slightly concerned about losing the sparse bitmap
feature which I have a hunch is beneficial in the MLS compartment case.
Although I will readily admit I have no data to support this claim, I just
wanted to throw it out as something to consider.
--
paul moore
linux security @ hp
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 4:29 [patch] Tuning avtab to reduce memory usage Yuichi Nakamura
2007-08-21 13:47 ` Stephen Smalley
2007-08-21 14:00 ` [patch] Tuning avtab to reduce memory usage James Morris
@ 2007-08-21 19:43 ` J. Tang
2007-08-22 3:11 ` Yuichi Nakamura
2 siblings, 1 reply; 52+ messages in thread
From: J. Tang @ 2007-08-21 19:43 UTC (permalink / raw)
To: Yuichi Nakamura, selinux
On Tue, 2007-08-21 at 13:29 +0900, Yuichi Nakamura wrote:
> I compared 3 hash functions, default, jhash, hash_long.
> default is default AVTAB_HASH.
> jhash is function defined in linux/jhash.h.
> hash_long is defined in linux/hash.h, I used it like following.
> (int)(hash_long(((unsigned long)keyp->target_class)+
> (((unsigned long)keyp->target_type)<<2)+
> (((unsigned long)keyp->source_type)<<9) , bits))
A number of months ago, the SETools team also recognized the limitations
of the current avtab hash function. Beginning with SETools 3.3 release,
we use a different hashing routine that is better suited for refpolicy
analysis. The following analysis may be of interest to those adjusting
the kernel avtab.
0. Background
The existing AV table in the kernel uses a 15-bit hash key, constructed
as:[0]
#define AVTAB_HASH(keyp) \
((keyp->target_class + \
(keyp->target_type << 2) + \
(keyp->source_type << 9)) & \
AVTAB_HASH_MASK)
We identified these problems with this hashing function:
a. The majority of rules in refpolicy involve the object classes
process (value 2), file (6), and dir (7). Thus at least three bits are
needed to best express the target class.
b. Refpolicy has roughly 2000 distinct types and attributes. Only 7
bits are preserved for source_type.
To our surprise, we discovered that for a particular policy with several
hundred thousand rules, some buckets were empty, while others were
nearly 200.[1] We measured the effectiveness of the hash table by way
of calculating the standard deviation in bucket lengths; it was 65.8227.
1. Change in avtab size
Our first optimization was to increase the hash table size to 16 bits.
As expected, this roughly halved the access time and bucket lengths.
With this change, we discovered that some buckets were still unused; the
longest chain, however, was still excessively long at 101. The standard
deviation halved to 33.0038.
2. Alternative Hashing Function
In combination with the increase in hash table size, we devised this
hashing function:[2]
#define AVTAB_HASH(keyp) \
((((keyp->source_type & 0xff) << 8) | (keyp->target_type & 0xff)) ^ \
(keyp->target_class & 0xf) ^ \
AVTAB_HASH_MASK)
This routine keeps the lower eight bits of the source and target types,
as well as the lower four bits of the target class. The algorithm
itself is very fast due to bitwise logic.[3]
2. Evaluation
With this new hashing function, our calculated standard deviation
dropped significantly, to 10.6086. With the aforementioned policy, the
shortest chain was now 8, the longest slightly more at 112. This
implies that the algorithm has better distribution than the original
avtab algorithm. As expected, runtime was cut considerably, without
further increasing the memory footprint of the avtab.
3. Applicability to Current Discussion
The SETools hashing algorithm is designed for a 16-bit hash. It could
be applied to other bucket sizes by modding it against an appopriate
prime number.
When choosing the hashing algorithm for the avtab, we recommend that the
types of data be also considered. If it is known that policies will
have thousands of types, the hashing function should reflect that
information. Likewise, if most rules are clustered around a few object
classes, those class values need to become better discriminators.[4]
The hashing algorithm changes are independent of changes to the bitmap
and can be implemented regardless of other patches.
[0] From Linux kernel 2.6.22.1 source, security/selinux/ss/avtab.c,
lines 25-29.
[1] The precise policy used can be provided, if requiested.
[2] We actually hash conditional rules into the same avtab as
unconditional rules; for brevity conditionals are not shown.
[3] On the x86 architecture, bitwise operations take a single cycle to
complete.
[4] Another improvement would be to have an avalanche effect in the
algorithm.
--
Jason Tang / jtang@tresys.com
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 14:00 ` [patch] Tuning avtab to reduce memory usage James Morris
@ 2007-08-22 2:55 ` Yuichi Nakamura
2007-08-22 3:42 ` KaiGai Kohei
` (2 more replies)
0 siblings, 3 replies; 52+ messages in thread
From: Yuichi Nakamura @ 2007-08-22 2:55 UTC (permalink / raw)
To: James Morris
Cc: ynakam, selinux, Stephen Smalley, busybox, Eric Paris, kaigai
On Tue, 21 Aug 2007 07:00:56 -0700 (PDT)
James Morris wrote:
> On Tue, 21 Aug 2007, Yuichi Nakamura wrote:
>
> > Hi.
> >
> > I would like to propose patch that reduce memory usage of avtab again.
>
> This looks good, although there are some coding style and other issues
> which need to be fixed. Also see Documentation/SubmittingPatches and
> Documentation/CodingStyle in the kernel tree.
Thanks for review !
> >
> > Next is a patch.
> > Signed-Off-By: Yuichi Nakamura <ynakam@hitachisoft.jp>
> > ----
>
> Needs to be 3 --- otherwise scripts will break.
Fixed.
>
> > avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--------------
> > avtab.h | 13 +++++++-----
> > conditional.c | 6 +++++
> > policydb.c | 9 ++------
> > 4 files changed, 64 insertions(+), 25 deletions(-)
>
> diffstat -p1
Fixed.
>
> >
> > diff -ur security/selinux.notuning/ss/avtab.c security/selinux/ss/avtab.c
>
> diff -purN
Fixed.
>
> > + hvalue = AVTAB_HASH(key,h->mask);
>
> Add a space after the comma.
Fixed.
>
> Also, AVTAB_HASH should be converted to a static inline.
>
> > + while(work) {
>
> Space after while.
>
> > + if (shift > 2) {
> > + shift = shift - 2;
> > + }
>
> No need for braces for a one-line statement.
Fixed
>
> > + nslot = 1 << shift;
> > + if (nslot > MAX_AVTAB_SIZE) {
> > + nslot = MAX_AVTAB_SIZE;
> > + }
>
> Ditto.
Fixed.
>
> > - h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
> > + h->htable = kmalloc(sizeof(*(h->htable)) * nslot, GFP_KERNEL);
>
> Use kcalloc(), then consider the effect of the memory zeroing & how much
> further code can be removed.
Fixed.
And removed loop that clears h->htable.
> > + printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n", h->nslot, nrules);
>
> This line is too long.
Fixed.
> > + rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
> > + if (rc) {
> > + rc = -ENOMEM;
>
> Why are you resetting rc to the same value?
Removed rc=-ENOMEM.
>
> > - goto out_free_symtab;
> > + goto out_free_symtab;
>
> Looks like you added a trailing tab.
Fixed.
>
>
>
> - James
> --
> James Morris
> <jmorris@namei.org>
And I've fixed avtab_hash_eval(struct avtab *h, char *tag),
to print out sum of chain length^2 to calculate the standard deviation.
Following is an updated patch.
Signed-off-by: Yuichi Nakamura <ynakam@hitachisoft.jp>
---
security/selinux/ss/avtab.c | 71 ++++++++++++++++++++++++++++----------
security/selinux/ss/avtab.h | 16 +++++---
security/selinux/ss/conditional.c | 5 ++
security/selinux/ss/policydb.c | 7 +--
4 files changed, 72 insertions(+), 27 deletions(-)
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
--- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-22 11:42:21.000000000 +0900
@@ -12,21 +12,23 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
+ *
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
*/
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/errno.h>
#include "avtab.h"
#include "policydb.h"
-#define AVTAB_HASH(keyp) \
+#define AVTAB_HASH(keyp, mask) \
((keyp->target_class + \
(keyp->target_type << 2) + \
(keyp->source_type << 9)) & \
- AVTAB_HASH_MASK)
+ mask)
static struct kmem_cache *avtab_node_cachep;
@@ -62,7 +64,7 @@ static int avtab_insert(struct avtab *h,
if (!h)
return -EINVAL;
- hvalue = AVTAB_HASH(key);
+ hvalue = AVTAB_HASH(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
@@ -102,7 +104,7 @@ avtab_insert_nonunique(struct avtab * h,
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = AVTAB_HASH(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
@@ -135,7 +137,7 @@ struct avtab_datum *avtab_search(struct
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = AVTAB_HASH(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -170,7 +172,7 @@ avtab_search_node(struct avtab *h, struc
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = AVTAB_HASH(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -228,7 +230,7 @@ void avtab_destroy(struct avtab *h)
if (!h || !h->htable)
return;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
while (cur != NULL) {
temp = cur;
@@ -237,32 +239,58 @@ void avtab_destroy(struct avtab *h)
}
h->htable[i] = NULL;
}
- vfree(h->htable);
+ kfree(h->htable);
h->htable = NULL;
+ h->nslot = 0;
+ h->mask = 0;
}
-
int avtab_init(struct avtab *h)
{
- int i;
+ h->htable = NULL;
+ h->nel = 0;
+ return 0;
+}
- h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
+int avtab_alloc(struct avtab *h, int nrules)
+{
+ u16 mask;
+ u32 shift = 0;
+ u32 work = nrules;
+ u32 nslot;
+
+ while (work) {
+ work = work>>1;
+ shift++;
+ }
+ if (shift > 2)
+ shift = shift - 2;
+ nslot = 1 << shift;
+ if (nslot > MAX_AVTAB_SIZE)
+ nslot = MAX_AVTAB_SIZE;
+ mask = nslot - 1;
+
+ h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
if (!h->htable)
return -ENOMEM;
- for (i = 0; i < AVTAB_SIZE; i++)
- h->htable[i] = NULL;
h->nel = 0;
+ h->nslot = nslot;
+ h->mask = mask;
+ printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
+ "Num of rules:%d\n", h->nslot, nrules);
return 0;
}
void avtab_hash_eval(struct avtab *h, char *tag)
{
int i, chain_len, slots_used, max_chain_len;
+ unsigned long long chain2_len_sum;
struct avtab_node *cur;
slots_used = 0;
max_chain_len = 0;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ chain2_len_sum = 0;
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
if (cur) {
slots_used++;
@@ -274,12 +302,14 @@ void avtab_hash_eval(struct avtab *h, ch
if (chain_len > max_chain_len)
max_chain_len = chain_len;
+ chain2_len_sum += chain_len * chain_len;
}
}
printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
- "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
- max_chain_len);
+ "chain length %d sum of chain length^2 %Lu\n",
+ tag, h->nel, slots_used, h->nslot, max_chain_len,
+ chain2_len_sum);
}
static uint16_t spec_order[] = {
@@ -419,6 +449,13 @@ int avtab_read(struct avtab *a, void *fp
rc = -EINVAL;
goto bad;
}
+
+ rc = avtab_alloc(a, nel);
+ if (rc) {
+ rc = -ENOMEM;
+ goto bad;
+ }
+
for (i = 0; i < nel; i++) {
rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
if (rc) {
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.h linux-2.6.22/security/selinux/ss/avtab.h
--- linux-2.6.22.orig/security/selinux/ss/avtab.h 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/avtab.h 2007-08-22 11:42:27.000000000 +0900
@@ -16,6 +16,9 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
+ *
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
*/
#ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_
@@ -50,9 +53,13 @@ struct avtab_node {
struct avtab {
struct avtab_node **htable;
u32 nel; /* number of elements */
+ u32 nslot; /* number of hash slots */
+ u16 mask; /* mask to compute hash func */
+
};
int avtab_init(struct avtab *);
+int avtab_alloc(struct avtab *, int);
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
void avtab_destroy(struct avtab *h);
void avtab_hash_eval(struct avtab *h, char *tag);
@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nex
void avtab_cache_init(void);
void avtab_cache_destroy(void);
-#define AVTAB_HASH_BITS 15
-#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
-#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
-
-#define AVTAB_SIZE AVTAB_HASH_BUCKETS
+#define MAX_AVTAB_HASH_BITS 13
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
#endif /* _SS_AVTAB_H_ */
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/conditional.c linux-2.6.22/security/selinux/ss/conditional.c
--- linux-2.6.22.orig/security/selinux/ss/conditional.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/conditional.c 2007-08-22 10:47:32.000000000 +0900
@@ -456,6 +456,11 @@ int cond_read_list(struct policydb *p, v
len = le32_to_cpu(buf[0]);
+ rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
+ if (rc) {
+ goto err;
+ }
+
for (i = 0; i < len; i++) {
node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
if (!node)
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/policydb.c linux-2.6.22/security/selinux/ss/policydb.c
--- linux-2.6.22.orig/security/selinux/ss/policydb.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/policydb.c 2007-08-22 10:30:04.000000000 +0900
@@ -176,18 +176,15 @@ static int policydb_init(struct policydb
rc = roles_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
rc = cond_policydb_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
out:
return rc;
-out_free_avtab:
- avtab_destroy(&p->te_avtab);
-
out_free_symtab:
for (i = 0; i < SYM_NUM; i++)
hashtab_destroy(p->symtab[i].table);
--
Yuichi Nakamura
Hitachi Software Engineering Co., Ltd.
Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/
SELinux Policy Editor: http://seedit.sourceforge.net/
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 19:43 ` J. Tang
@ 2007-08-22 3:11 ` Yuichi Nakamura
0 siblings, 0 replies; 52+ messages in thread
From: Yuichi Nakamura @ 2007-08-22 3:11 UTC (permalink / raw)
To: J. Tang; +Cc: ynakam, selinux
On Tue, 21 Aug 2007 15:43:20 -0400
"J. Tang" wrote:
> On Tue, 2007-08-21 at 13:29 +0900, Yuichi Nakamura wrote:
> > I compared 3 hash functions, default, jhash, hash_long.
> > default is default AVTAB_HASH.
> > jhash is function defined in linux/jhash.h.
> > hash_long is defined in linux/hash.h, I used it like following.
> > (int)(hash_long(((unsigned long)keyp->target_class)+
> > (((unsigned long)keyp->target_type)<<2)+
> > (((unsigned long)keyp->source_type)<<9) , bits))
>
> A number of months ago, the SETools team also recognized the limitations
> of the current avtab hash function. Beginning with SETools 3.3 release,
> we use a different hashing routine that is better suited for refpolicy
> analysis. The following analysis may be of interest to those adjusting
> the kernel avtab.
>
> 0. Background
>
> The existing AV table in the kernel uses a 15-bit hash key, constructed
> as:[0]
>
> #define AVTAB_HASH(keyp) \
> ((keyp->target_class + \
> (keyp->target_type << 2) + \
> (keyp->source_type << 9)) & \
> AVTAB_HASH_MASK)
>
> We identified these problems with this hashing function:
>
> a. The majority of rules in refpolicy involve the object classes
> process (value 2), file (6), and dir (7). Thus at least three bits are
> needed to best express the target class.
>
> b. Refpolicy has roughly 2000 distinct types and attributes. Only 7
> bits are preserved for source_type.
>
> To our surprise, we discovered that for a particular policy with several
> hundred thousand rules, some buckets were empty, while others were
> nearly 200.[1] We measured the effectiveness of the hash table by way
> of calculating the standard deviation in bucket lengths; it was 65.8227.
>
> 1. Change in avtab size
>
> Our first optimization was to increase the hash table size to 16 bits.
> As expected, this roughly halved the access time and bucket lengths.
> With this change, we discovered that some buckets were still unused; the
> longest chain, however, was still excessively long at 101. The standard
> deviation halved to 33.0038.
>
> 2. Alternative Hashing Function
>
> In combination with the increase in hash table size, we devised this
> hashing function:[2]
>
> #define AVTAB_HASH(keyp) \
> ((((keyp->source_type & 0xff) << 8) | (keyp->target_type & 0xff)) ^ \
> (keyp->target_class & 0xf) ^ \
> AVTAB_HASH_MASK)
>
> This routine keeps the lower eight bits of the source and target types,
> as well as the lower four bits of the target class. The algorithm
> itself is very fast due to bitwise logic.[3]
>
> 2. Evaluation
>
> With this new hashing function, our calculated standard deviation
> dropped significantly, to 10.6086. With the aforementioned policy, the
> shortest chain was now 8, the longest slightly more at 112. This
> implies that the algorithm has better distribution than the original
> avtab algorithm. As expected, runtime was cut considerably, without
> further increasing the memory footprint of the avtab.
>
> 3. Applicability to Current Discussion
>
> The SETools hashing algorithm is designed for a 16-bit hash. It could
> be applied to other bucket sizes by modding it against an appopriate
> prime number.
>
> When choosing the hashing algorithm for the avtab, we recommend that the
> types of data be also considered. If it is known that policies will
> have thousands of types, the hashing function should reflect that
> information. Likewise, if most rules are clustered around a few object
> classes, those class values need to become better discriminators.[4]
> The hashing algorithm changes are independent of changes to the bitmap
> and can be implemented regardless of other patches.
>
>
> [0] From Linux kernel 2.6.22.1 source, security/selinux/ss/avtab.c,
> lines 25-29.
> [1] The precise policy used can be provided, if requiested.
Thanks for interesting information.
I tried this hash function,
but I could not improve the standard deviation to selinux-policy-strict-2.4.6-80.fc6.
Could you give me your policy?
> [2] We actually hash conditional rules into the same avtab as
> unconditional rules; for brevity conditionals are not shown.
> [3] On the x86 architecture, bitwise operations take a single cycle to
> complete.
> [4] Another improvement would be to have an avalanche effect in the
> algorithm.
>
> --
> Jason Tang / jtang@tresys.com
Regards,
--
Yuichi Nakamura
Hitachi Software Engineering Co., Ltd.
Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/
SELinux Policy Editor: http://seedit.sourceforge.net/
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-22 2:55 ` Yuichi Nakamura
@ 2007-08-22 3:42 ` KaiGai Kohei
2007-08-22 13:44 ` James Morris
2007-08-22 16:05 ` James Morris
2 siblings, 0 replies; 52+ messages in thread
From: KaiGai Kohei @ 2007-08-22 3:42 UTC (permalink / raw)
To: Yuichi Nakamura
Cc: James Morris, selinux, Stephen Smalley, busybox, Eric Paris
Yuichi Nakamura wrote:
> On Tue, 21 Aug 2007 07:00:56 -0700 (PDT)
> James Morris wrote:
>> On Tue, 21 Aug 2007, Yuichi Nakamura wrote:
>>
>>> Hi.
>>>
>>> I would like to propose patch that reduce memory usage of avtab again.
>> This looks good, although there are some coding style and other issues
>> which need to be fixed. Also see Documentation/SubmittingPatches and
>> Documentation/CodingStyle in the kernel tree.
> Thanks for review !
FYI.
These documents are also translated into Japanese language.
http://www.linux.or.jp/JF/JFdocs/kernel-docs-2.6/SubmittingPatches.html
http://www.linux.or.jp/JF/JFdocs/kernel-docs-2.6/CodingStyle.html
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-21 16:55 ` Paul Moore
@ 2007-08-22 9:25 ` KaiGai Kohei
2007-09-12 3:08 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-08-22 9:25 UTC (permalink / raw)
To: Paul Moore
Cc: Stephen Smalley, Yuichi Nakamura, selinux, James Morris,
Eric Paris
Paul Moore wrote:
> On Tuesday, August 21 2007 12:37:49 pm Stephen Smalley wrote:
>> On Tue, 2007-08-21 at 11:11 -0400, Paul Moore wrote:
>>> On Tuesday, August 21 2007 9:47:38 am Stephen Smalley wrote:
>>>> We likely should look at optimizing the ebitmap code, or replacing it
>>>> with the native kernel bitmaps (include/linux/bitmap.h, lib/bitmap.c).
>>>> For example, ebitmap_next could possibly use find_next_bit().
>>> [Removed the busybox list because I'm sure they don't care]
>>>
>>> Would the fact that the MLS category bitmaps grow to 1024 bits be a
>>> concern with using a single contiguous bitmap instead of the sparse
>>> bitmap the ebitmap currently uses? Granted, in the worst case of
>>> c0.c1023 the kernel bitmap would most certainly be better but I wonder
>>> what the common case is (and if the MLS compartments even factor into the
>>> discussion) and which type is better suited to handle this case.
>> Even if we retain the ebitmap type as a sparse bitmap, I think we can do
>> some optimization of its internals, possibly leveraging things like
>> find_next_bit(), to speed up the loops that were introduced when we
>> optimized the avtab memory layout by pushing attributes down into the
>> kernel policy (policy.20).
>>
>> Trying Yuichi's simple instrumentation of security_compute_av, I see a
>> huge difference in security_compute_av times between policy.19 and
>> policy.20. We knew it would slow security_compute_av down (standard
>> tradeoff between runtime performance and memory use), but the thinking
>> at the time was that it wouldn't matter because of the AVC. But we do
>> have to bound our worst case latency.
>
> I understand, I was just slightly concerned about losing the sparse bitmap
> feature which I have a hunch is beneficial in the MLS compartment case.
> Although I will readily admit I have no data to support this claim, I just
> wanted to throw it out as something to consider.
I think the sparse bitmap feature is also useful to skip unnecessary scan
on the ebitmap, so these features should be used together.
The current version of ebitmap contains a 64-bit length bitmap.
I have a concern to apply the standard bitops, and memory usage.
The one is a difference in the type of variable.
find_next_bit() requires the bitmap defined as unsigned long array,
but ebitmap uses a u64 value as a bitmap, so we cannot apply it as is.
The other is memory usage. The ebitmap_node is allocated by kzalloc().
However, sizeof(ebitmap_node) is 16-byte in 32bit arch, although
the minimun unit of kmalloc() is 32 byte.
In 32-bit arch, map should be defined as 'unsigned long map[6]'
to apply the standard bitops and to maximun memory usage.
Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-22 2:55 ` Yuichi Nakamura
2007-08-22 3:42 ` KaiGai Kohei
@ 2007-08-22 13:44 ` James Morris
2007-08-23 0:57 ` Yuichi Nakamura
2007-08-22 16:05 ` James Morris
2 siblings, 1 reply; 52+ messages in thread
From: James Morris @ 2007-08-22 13:44 UTC (permalink / raw)
To: Yuichi Nakamura; +Cc: selinux, Stephen Smalley, busybox, Eric Paris, kaigai
On Wed, 22 Aug 2007, Yuichi Nakamura wrote:
Just a couple more nits...
> +#define AVTAB_HASH(keyp, mask) \
> ((keyp->target_class + \
> (keyp->target_type << 2) + \
> (keyp->source_type << 9)) & \
> - AVTAB_HASH_MASK)
> + mask)
Can you make this a static inline ?
> + if (rc) {
> + goto err;
> + }
Don't need these braces.
- James
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-22 2:55 ` Yuichi Nakamura
2007-08-22 3:42 ` KaiGai Kohei
2007-08-22 13:44 ` James Morris
@ 2007-08-22 16:05 ` James Morris
2 siblings, 0 replies; 52+ messages in thread
From: James Morris @ 2007-08-22 16:05 UTC (permalink / raw)
To: Yuichi Nakamura; +Cc: selinux, Stephen Smalley, busybox, Eric Paris, kaigai
On Wed, 22 Aug 2007, Yuichi Nakamura wrote:
> + rc = avtab_alloc(a, nel);
> + if (rc) {
> + rc = -ENOMEM;
> + goto bad;
> + }
Please also just use the return code here.
- James
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-22 13:44 ` James Morris
@ 2007-08-23 0:57 ` Yuichi Nakamura
2007-08-23 13:15 ` Stephen Smalley
2007-08-23 14:46 ` James Morris
0 siblings, 2 replies; 52+ messages in thread
From: Yuichi Nakamura @ 2007-08-23 0:57 UTC (permalink / raw)
To: James Morris
Cc: ynakam, selinux, Stephen Smalley, busybox, Eric Paris, kaigai
On Wed, 22 Aug 2007 06:44:34 -0700 (PDT)
James Morris wrote:
> On Wed, 22 Aug 2007, Yuichi Nakamura wrote:
>
>
> Just a couple more nits...
>
> > +#define AVTAB_HASH(keyp, mask) \
> > ((keyp->target_class + \
> > (keyp->target_type << 2) + \
> > (keyp->source_type << 9)) & \
> > - AVTAB_HASH_MASK)
> > + mask)
>
> Can you make this a static inline ?
Changed it to static inline avtab_hash.
>
> > + if (rc) {
> > + goto err;
> > + }
>
> Don't need these braces.
Fixed.
Also fixed below
> + rc = avtab_alloc(a, nel);
> + if (rc) {
> + rc = -ENOMEM;
> + goto bad;
> + }
>
> - James
> --
> James Morris
> <jmorris@namei.org>
Following is updated patch to 2.6.22.
Signed-off-by: Yuichi Nakamura<ynakam@hitachisoft.jp>
---
security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++-----------
security/selinux/ss/avtab.h | 16 +++++--
security/selinux/ss/conditional.c | 4 +
security/selinux/ss/policydb.c | 7 ---
4 files changed, 73 insertions(+), 32 deletions(-)
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
--- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-23 09:30:03.000000000 +0900
@@ -12,24 +12,25 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
+ *
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
*/
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/errno.h>
-
#include "avtab.h"
#include "policydb.h"
-#define AVTAB_HASH(keyp) \
-((keyp->target_class + \
- (keyp->target_type << 2) + \
- (keyp->source_type << 9)) & \
- AVTAB_HASH_MASK)
-
static struct kmem_cache *avtab_node_cachep;
+static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
+{
+ return ((keyp->target_class + (keyp->target_type << 2) + \
+ (keyp->source_type << 9)) & mask);
+}
+
static struct avtab_node*
avtab_insert_node(struct avtab *h, int hvalue,
struct avtab_node * prev, struct avtab_node * cur,
@@ -62,7 +63,7 @@ static int avtab_insert(struct avtab *h,
if (!h)
return -EINVAL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
@@ -102,7 +103,7 @@ avtab_insert_nonunique(struct avtab * h,
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
@@ -135,7 +136,7 @@ struct avtab_datum *avtab_search(struct
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -170,7 +171,7 @@ avtab_search_node(struct avtab *h, struc
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h)
if (!h || !h->htable)
return;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
while (cur != NULL) {
temp = cur;
@@ -237,32 +238,58 @@ void avtab_destroy(struct avtab *h)
}
h->htable[i] = NULL;
}
- vfree(h->htable);
+ kfree(h->htable);
h->htable = NULL;
+ h->nslot = 0;
+ h->mask = 0;
}
-
int avtab_init(struct avtab *h)
{
- int i;
+ h->htable = NULL;
+ h->nel = 0;
+ return 0;
+}
+
+int avtab_alloc(struct avtab *h, int nrules)
+{
+ u16 mask;
+ u32 shift = 0;
+ u32 work = nrules;
+ u32 nslot;
+
+ while (work) {
+ work = work>>1;
+ shift++;
+ }
+ if (shift > 2)
+ shift = shift - 2;
+ nslot = 1 << shift;
+ if (nslot > MAX_AVTAB_SIZE)
+ nslot = MAX_AVTAB_SIZE;
+ mask = nslot - 1;
- h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
+ h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
if (!h->htable)
return -ENOMEM;
- for (i = 0; i < AVTAB_SIZE; i++)
- h->htable[i] = NULL;
h->nel = 0;
+ h->nslot = nslot;
+ h->mask = mask;
+ printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
+ "Num of rules:%d\n", h->nslot, nrules);
return 0;
}
void avtab_hash_eval(struct avtab *h, char *tag)
{
int i, chain_len, slots_used, max_chain_len;
+ unsigned long long chain2_len_sum;
struct avtab_node *cur;
slots_used = 0;
max_chain_len = 0;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ chain2_len_sum = 0;
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
if (cur) {
slots_used++;
@@ -274,12 +301,14 @@ void avtab_hash_eval(struct avtab *h, ch
if (chain_len > max_chain_len)
max_chain_len = chain_len;
+ chain2_len_sum += chain_len * chain_len;
}
}
printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
- "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
- max_chain_len);
+ "chain length %d sum of chain length^2 %Lu\n",
+ tag, h->nel, slots_used, h->nslot, max_chain_len,
+ chain2_len_sum);
}
static uint16_t spec_order[] = {
@@ -419,6 +448,11 @@ int avtab_read(struct avtab *a, void *fp
rc = -EINVAL;
goto bad;
}
+
+ rc = avtab_alloc(a, nel);
+ if (rc)
+ goto bad;
+
for (i = 0; i < nel; i++) {
rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
if (rc) {
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.h linux-2.6.22/security/selinux/ss/avtab.h
--- linux-2.6.22.orig/security/selinux/ss/avtab.h 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/avtab.h 2007-08-23 09:28:54.000000000 +0900
@@ -16,6 +16,9 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
+ *
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
*/
#ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_
@@ -50,9 +53,13 @@ struct avtab_node {
struct avtab {
struct avtab_node **htable;
u32 nel; /* number of elements */
+ u32 nslot; /* number of hash slots */
+ u16 mask; /* mask to compute hash func */
+
};
int avtab_init(struct avtab *);
+int avtab_alloc(struct avtab *, int);
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
void avtab_destroy(struct avtab *h);
void avtab_hash_eval(struct avtab *h, char *tag);
@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nex
void avtab_cache_init(void);
void avtab_cache_destroy(void);
-#define AVTAB_HASH_BITS 15
-#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
-#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
-
-#define AVTAB_SIZE AVTAB_HASH_BUCKETS
+#define MAX_AVTAB_HASH_BITS 13
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
#endif /* _SS_AVTAB_H_ */
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/conditional.c linux-2.6.22/security/selinux/ss/conditional.c
--- linux-2.6.22.orig/security/selinux/ss/conditional.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/conditional.c 2007-08-23 09:28:54.000000000 +0900
@@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, v
len = le32_to_cpu(buf[0]);
+ rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
+ if (rc)
+ goto err;
+
for (i = 0; i < len; i++) {
node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
if (!node)
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/policydb.c linux-2.6.22/security/selinux/ss/policydb.c
--- linux-2.6.22.orig/security/selinux/ss/policydb.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/policydb.c 2007-08-23 09:28:54.000000000 +0900
@@ -176,18 +176,15 @@ static int policydb_init(struct policydb
rc = roles_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
rc = cond_policydb_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
out:
return rc;
-out_free_avtab:
- avtab_destroy(&p->te_avtab);
-
out_free_symtab:
for (i = 0; i < SYM_NUM; i++)
hashtab_destroy(p->symtab[i].table);
Regards,
--
Yuichi Nakamura
Hitachi Software Engineering Co., Ltd.
Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/
SELinux Policy Editor: http://seedit.sourceforge.net/
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-23 0:57 ` Yuichi Nakamura
@ 2007-08-23 13:15 ` Stephen Smalley
2007-08-24 2:55 ` Yuichi Nakamura
2007-08-23 14:46 ` James Morris
1 sibling, 1 reply; 52+ messages in thread
From: Stephen Smalley @ 2007-08-23 13:15 UTC (permalink / raw)
To: Yuichi Nakamura; +Cc: James Morris, selinux, busybox, Eric Paris, kaigai
On Thu, 2007-08-23 at 09:57 +0900, Yuichi Nakamura wrote:
> Following is updated patch to 2.6.22.
>
> Signed-off-by: Yuichi Nakamura<ynakam@hitachisoft.jp>
> ---
> security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++-----------
> security/selinux/ss/avtab.h | 16 +++++--
> security/selinux/ss/conditional.c | 4 +
> security/selinux/ss/policydb.c | 7 ---
> 4 files changed, 73 insertions(+), 32 deletions(-)
> diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
> --- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
> +++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-23 09:30:03.000000000 +0900
> +int avtab_alloc(struct avtab *h, int nrules)
nrules should be u32 too.
And you should likely test for the degenerate case (nrules == 0) and
bail on it.
> +{
> + u16 mask;
> + u32 shift = 0;
> + u32 work = nrules;
> + u32 nslot;
> +
> + while (work) {
> + work = work>>1;
> + shift++;
> + }
> + if (shift > 2)
> + shift = shift - 2;
> + nslot = 1 << shift;
> + if (nslot > MAX_AVTAB_SIZE)
> + nslot = MAX_AVTAB_SIZE;
> + mask = nslot - 1;
>
> - h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
> + h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
> if (!h->htable)
> return -ENOMEM;
> - for (i = 0; i < AVTAB_SIZE; i++)
> - h->htable[i] = NULL;
> h->nel = 0;
> + h->nslot = nslot;
> + h->mask = mask;
> + printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
> + "Num of rules:%d\n", h->nslot, nrules);
> return 0;
> }
>
> void avtab_hash_eval(struct avtab *h, char *tag)
> {
> int i, chain_len, slots_used, max_chain_len;
> + unsigned long long chain2_len_sum;
> struct avtab_node *cur;
>
> slots_used = 0;
> max_chain_len = 0;
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + chain2_len_sum = 0;
> + for (i = 0; i < h->nslot; i++) {
> cur = h->htable[i];
> if (cur) {
> slots_used++;
> @@ -274,12 +301,14 @@ void avtab_hash_eval(struct avtab *h, ch
>
> if (chain_len > max_chain_len)
> max_chain_len = chain_len;
> + chain2_len_sum += chain_len * chain_len;
> }
> }
>
> printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
> - "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
> - max_chain_len);
> + "chain length %d sum of chain length^2 %Lu\n",
> + tag, h->nel, slots_used, h->nslot, max_chain_len,
> + chain2_len_sum);
> }
>
> static uint16_t spec_order[] = {
> @@ -419,6 +448,11 @@ int avtab_read(struct avtab *a, void *fp
> rc = -EINVAL;
> goto bad;
> }
> +
> + rc = avtab_alloc(a, nel);
> + if (rc)
> + goto bad;
> +
> for (i = 0; i < nel; i++) {
> rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
> if (rc) {
> diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.h linux-2.6.22/security/selinux/ss/avtab.h
> --- linux-2.6.22.orig/security/selinux/ss/avtab.h 2007-07-09 08:32:17.000000000 +0900
> +++ linux-2.6.22/security/selinux/ss/avtab.h 2007-08-23 09:28:54.000000000 +0900
> @@ -16,6 +16,9 @@
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License as published by
> * the Free Software Foundation, version 2.
> + *
> + * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
> + * Tuned number of hash slots for avtab to reduce memory usage
> */
> #ifndef _SS_AVTAB_H_
> #define _SS_AVTAB_H_
> @@ -50,9 +53,13 @@ struct avtab_node {
> struct avtab {
> struct avtab_node **htable;
> u32 nel; /* number of elements */
> + u32 nslot; /* number of hash slots */
> + u16 mask; /* mask to compute hash func */
> +
> };
>
> int avtab_init(struct avtab *);
> +int avtab_alloc(struct avtab *, int);
> struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
> void avtab_destroy(struct avtab *h);
> void avtab_hash_eval(struct avtab *h, char *tag);
> @@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nex
> void avtab_cache_init(void);
> void avtab_cache_destroy(void);
>
> -#define AVTAB_HASH_BITS 15
> -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
> -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
> -
> -#define AVTAB_SIZE AVTAB_HASH_BUCKETS
> +#define MAX_AVTAB_HASH_BITS 13
> +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
> +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
> +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
>
> #endif /* _SS_AVTAB_H_ */
>
> diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/conditional.c linux-2.6.22/security/selinux/ss/conditional.c
> --- linux-2.6.22.orig/security/selinux/ss/conditional.c 2007-07-09 08:32:17.000000000 +0900
> +++ linux-2.6.22/security/selinux/ss/conditional.c 2007-08-23 09:28:54.000000000 +0900
> @@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, v
>
> len = le32_to_cpu(buf[0]);
>
> + rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
> + if (rc)
> + goto err;
> +
> for (i = 0; i < len; i++) {
> node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
> if (!node)
> diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/policydb.c linux-2.6.22/security/selinux/ss/policydb.c
> --- linux-2.6.22.orig/security/selinux/ss/policydb.c 2007-07-09 08:32:17.000000000 +0900
> +++ linux-2.6.22/security/selinux/ss/policydb.c 2007-08-23 09:28:54.000000000 +0900
> @@ -176,18 +176,15 @@ static int policydb_init(struct policydb
>
> rc = roles_init(p);
> if (rc)
> - goto out_free_avtab;
> + goto out_free_symtab;
>
> rc = cond_policydb_init(p);
> if (rc)
> - goto out_free_avtab;
> + goto out_free_symtab;
>
> out:
> return rc;
>
> -out_free_avtab:
> - avtab_destroy(&p->te_avtab);
> -
> out_free_symtab:
> for (i = 0; i < SYM_NUM; i++)
> hashtab_destroy(p->symtab[i].table);
>
>
>
> Regards,
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-23 0:57 ` Yuichi Nakamura
2007-08-23 13:15 ` Stephen Smalley
@ 2007-08-23 14:46 ` James Morris
2007-08-24 2:33 ` Yuichi Nakamura
1 sibling, 1 reply; 52+ messages in thread
From: James Morris @ 2007-08-23 14:46 UTC (permalink / raw)
To: Yuichi Nakamura; +Cc: selinux, Stephen Smalley, busybox, Eric Paris, kaigai
On Thu, 23 Aug 2007, Yuichi Nakamura wrote:
> +static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
> +{
> + return ((keyp->target_class + (keyp->target_type << 2) + \
> + (keyp->source_type << 9)) & mask);
> +}
As you'll need to resubmit the patch, please remove the \ (I had fixed it
up in my local tree).
Please also provide a short description of the patch (one paragraph at the
most), to go in the git log.
- James
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-23 14:46 ` James Morris
@ 2007-08-24 2:33 ` Yuichi Nakamura
0 siblings, 0 replies; 52+ messages in thread
From: Yuichi Nakamura @ 2007-08-24 2:33 UTC (permalink / raw)
To: James Morris
Cc: ynakam, selinux, Stephen Smalley, busybox, Eric Paris, kaigai
On Thu, 23 Aug 2007 07:46:52 -0700 (PDT)
James Morris wrote:
> On Thu, 23 Aug 2007, Yuichi Nakamura wrote:
>
> > +static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
> > +{
> > + return ((keyp->target_class + (keyp->target_type << 2) + \
> > + (keyp->source_type << 9)) & mask);
> > +}
>
> As you'll need to resubmit the patch, please remove the \ (I had fixed it
> up in my local tree).
I will fix in next patch.
> Please also provide a short description of the patch (one paragraph at the
> most), to go in the git log.
I see.
>
> - James
> --
> James Morris
> <jmorris@namei.org>
--
Yuichi Nakamura
Hitachi Software Engineering Co., Ltd.
Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/
SELinux Policy Editor: http://seedit.sourceforge.net/
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-23 13:15 ` Stephen Smalley
@ 2007-08-24 2:55 ` Yuichi Nakamura
2007-08-27 13:39 ` Stephen Smalley
2008-01-31 21:00 ` Stephen Smalley
0 siblings, 2 replies; 52+ messages in thread
From: Yuichi Nakamura @ 2007-08-24 2:55 UTC (permalink / raw)
To: Stephen Smalley
Cc: ynakam, James Morris, selinux, busybox, Eric Paris, kaigai
On Thu, 23 Aug 2007 09:15:25 -0400
Stephen Smalley wrote:
> On Thu, 2007-08-23 at 09:57 +0900, Yuichi Nakamura wrote:
> > Following is updated patch to 2.6.22.
> >
> > Signed-off-by: Yuichi Nakamura<ynakam@hitachisoft.jp>
> > ---
> > security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++-----------
> > security/selinux/ss/avtab.h | 16 +++++--
> > security/selinux/ss/conditional.c | 4 +
> > security/selinux/ss/policydb.c | 7 ---
> > 4 files changed, 73 insertions(+), 32 deletions(-)
> > diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
> > --- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
> > +++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-23 09:30:03.000000000 +0900
> > +int avtab_alloc(struct avtab *h, int nrules)
>
> nrules should be u32 too.
Fixed.
>
> And you should likely test for the degenerate case (nrules == 0) and
> bail on it.
Checking nrules==0.
And also checking !h->htable like below in avtab_search_node etc.
- if (!h)
+ if (!h || !h->htable)
Following is updated patch.
From: Yuichi Nakamura <ynakam@hitachisoft.jp>
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>
---
security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++-----------
security/selinux/ss/avtab.h | 16 ++++--
security/selinux/ss/conditional.c | 4 +
security/selinux/ss/policydb.c | 7 --
4 files changed, 82 insertions(+), 36 deletions(-)
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
--- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-24 11:53:12.000000000 +0900
@@ -12,24 +12,25 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
+ *
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
*/
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/errno.h>
-
#include "avtab.h"
#include "policydb.h"
-#define AVTAB_HASH(keyp) \
-((keyp->target_class + \
- (keyp->target_type << 2) + \
- (keyp->source_type << 9)) & \
- AVTAB_HASH_MASK)
-
static struct kmem_cache *avtab_node_cachep;
+static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
+{
+ return ((keyp->target_class + (keyp->target_type << 2) +
+ (keyp->source_type << 9)) & mask);
+}
+
static struct avtab_node*
avtab_insert_node(struct avtab *h, int hvalue,
struct avtab_node * prev, struct avtab_node * cur,
@@ -59,10 +60,10 @@ static int avtab_insert(struct avtab *h,
struct avtab_node *prev, *cur, *newnode;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
- if (!h)
+ if (!h || !h->htable)
return -EINVAL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
@@ -100,9 +101,9 @@ avtab_insert_nonunique(struct avtab * h,
struct avtab_node *prev, *cur, *newnode;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
- if (!h)
+ if (!h || !h->htable)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
@@ -132,10 +133,10 @@ struct avtab_datum *avtab_search(struct
struct avtab_node *cur;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
- if (!h)
+ if (!h || !h->htable)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -167,10 +168,10 @@ avtab_search_node(struct avtab *h, struc
struct avtab_node *cur;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
- if (!h)
+ if (!h || !h->htable)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h)
if (!h || !h->htable)
return;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
while (cur != NULL) {
temp = cur;
@@ -237,32 +238,63 @@ void avtab_destroy(struct avtab *h)
}
h->htable[i] = NULL;
}
- vfree(h->htable);
+ kfree(h->htable);
h->htable = NULL;
+ h->nslot = 0;
+ h->mask = 0;
}
-
int avtab_init(struct avtab *h)
{
- int i;
+ h->htable = NULL;
+ h->nel = 0;
+ return 0;
+}
+
+int avtab_alloc(struct avtab *h, u32 nrules)
+{
+ u16 mask = 0;
+ u32 shift = 0;
+ u32 work = nrules;
+ u32 nslot = 0;
+
+ if (nrules == 0)
+ goto avtab_alloc_out;
+
+ while (work) {
+ work = work >> 1;
+ shift++;
+ }
+ if (shift > 2)
+ shift = shift - 2;
+ nslot = 1 << shift;
+ if (nslot > MAX_AVTAB_SIZE)
+ nslot = MAX_AVTAB_SIZE;
+ mask = nslot - 1;
- h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
+ h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
if (!h->htable)
return -ENOMEM;
- for (i = 0; i < AVTAB_SIZE; i++)
- h->htable[i] = NULL;
+
+ avtab_alloc_out:
h->nel = 0;
+ h->nslot = nslot;
+ h->mask = mask;
+ printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
+ "Num of rules:%d\n", h->nslot, nrules);
return 0;
}
void avtab_hash_eval(struct avtab *h, char *tag)
{
int i, chain_len, slots_used, max_chain_len;
+ unsigned long long chain2_len_sum;
struct avtab_node *cur;
slots_used = 0;
max_chain_len = 0;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ chain2_len_sum = 0;
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
if (cur) {
slots_used++;
@@ -274,12 +306,14 @@ void avtab_hash_eval(struct avtab *h, ch
if (chain_len > max_chain_len)
max_chain_len = chain_len;
+ chain2_len_sum += chain_len * chain_len;
}
}
printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
- "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
- max_chain_len);
+ "chain length %d sum of chain length^2 %Lu\n",
+ tag, h->nel, slots_used, h->nslot, max_chain_len,
+ chain2_len_sum);
}
static uint16_t spec_order[] = {
@@ -419,6 +453,11 @@ int avtab_read(struct avtab *a, void *fp
rc = -EINVAL;
goto bad;
}
+
+ rc = avtab_alloc(a, nel);
+ if (rc)
+ goto bad;
+
for (i = 0; i < nel; i++) {
rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
if (rc) {
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.h linux-2.6.22/security/selinux/ss/avtab.h
--- linux-2.6.22.orig/security/selinux/ss/avtab.h 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/avtab.h 2007-08-24 11:52:24.000000000 +0900
@@ -16,6 +16,9 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
+ *
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
*/
#ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_
@@ -50,9 +53,13 @@ struct avtab_node {
struct avtab {
struct avtab_node **htable;
u32 nel; /* number of elements */
+ u32 nslot; /* number of hash slots */
+ u16 mask; /* mask to compute hash func */
+
};
int avtab_init(struct avtab *);
+int avtab_alloc(struct avtab *, u32);
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
void avtab_destroy(struct avtab *h);
void avtab_hash_eval(struct avtab *h, char *tag);
@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nex
void avtab_cache_init(void);
void avtab_cache_destroy(void);
-#define AVTAB_HASH_BITS 15
-#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
-#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
-
-#define AVTAB_SIZE AVTAB_HASH_BUCKETS
+#define MAX_AVTAB_HASH_BITS 13
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
#endif /* _SS_AVTAB_H_ */
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/conditional.c linux-2.6.22/security/selinux/ss/conditional.c
--- linux-2.6.22.orig/security/selinux/ss/conditional.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/conditional.c 2007-08-24 11:52:24.000000000 +0900
@@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, v
len = le32_to_cpu(buf[0]);
+ rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
+ if (rc)
+ goto err;
+
for (i = 0; i < len; i++) {
node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
if (!node)
diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/policydb.c linux-2.6.22/security/selinux/ss/policydb.c
--- linux-2.6.22.orig/security/selinux/ss/policydb.c 2007-07-09 08:32:17.000000000 +0900
+++ linux-2.6.22/security/selinux/ss/policydb.c 2007-08-24 11:52:24.000000000 +0900
@@ -176,18 +176,15 @@ static int policydb_init(struct policydb
rc = roles_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
rc = cond_policydb_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
out:
return rc;
-out_free_avtab:
- avtab_destroy(&p->te_avtab);
-
out_free_symtab:
for (i = 0; i < SYM_NUM; i++)
hashtab_destroy(p->symtab[i].table);
Regards,
--
Yuichi Nakamura
Hitachi Software Engineering Co., Ltd.
Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/
SELinux Policy Editor: http://seedit.sourceforge.net/
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-24 2:55 ` Yuichi Nakamura
@ 2007-08-27 13:39 ` Stephen Smalley
2007-08-27 16:55 ` James Morris
2008-01-31 21:00 ` Stephen Smalley
1 sibling, 1 reply; 52+ messages in thread
From: Stephen Smalley @ 2007-08-27 13:39 UTC (permalink / raw)
To: Yuichi Nakamura; +Cc: James Morris, selinux, busybox, Eric Paris, kaigai
On Fri, 2007-08-24 at 11:55 +0900, Yuichi Nakamura wrote:
> On Thu, 23 Aug 2007 09:15:25 -0400
> Stephen Smalley wrote:
> > On Thu, 2007-08-23 at 09:57 +0900, Yuichi Nakamura wrote:
> > > Following is updated patch to 2.6.22.
> > >
> > > Signed-off-by: Yuichi Nakamura<ynakam@hitachisoft.jp>
> > > ---
> > > security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++-----------
> > > security/selinux/ss/avtab.h | 16 +++++--
> > > security/selinux/ss/conditional.c | 4 +
> > > security/selinux/ss/policydb.c | 7 ---
> > > 4 files changed, 73 insertions(+), 32 deletions(-)
> > > diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
> > > --- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
> > > +++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-23 09:30:03.000000000 +0900
> > > +int avtab_alloc(struct avtab *h, int nrules)
> >
> > nrules should be u32 too.
> Fixed.
>
> >
> > And you should likely test for the degenerate case (nrules == 0) and
> > bail on it.
> Checking nrules==0.
> And also checking !h->htable like below in avtab_search_node etc.
> - if (!h)
> + if (!h || !h->htable)
>
> Following is updated patch.
> From: Yuichi Nakamura <ynakam@hitachisoft.jp>
>
> 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>
Looks good, thanks.
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
> ---
> security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++-----------
> security/selinux/ss/avtab.h | 16 ++++--
> security/selinux/ss/conditional.c | 4 +
> security/selinux/ss/policydb.c | 7 --
> 4 files changed, 82 insertions(+), 36 deletions(-)
> diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
> --- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
> +++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-24 11:53:12.000000000 +0900
> @@ -12,24 +12,25 @@
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License as published by
> * the Free Software Foundation, version 2.
> + *
> + * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
> + * Tuned number of hash slots for avtab to reduce memory usage
> */
>
> #include <linux/kernel.h>
> #include <linux/slab.h>
> -#include <linux/vmalloc.h>
> #include <linux/errno.h>
> -
> #include "avtab.h"
> #include "policydb.h"
>
> -#define AVTAB_HASH(keyp) \
> -((keyp->target_class + \
> - (keyp->target_type << 2) + \
> - (keyp->source_type << 9)) & \
> - AVTAB_HASH_MASK)
> -
> static struct kmem_cache *avtab_node_cachep;
>
> +static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
> +{
> + return ((keyp->target_class + (keyp->target_type << 2) +
> + (keyp->source_type << 9)) & mask);
> +}
> +
> static struct avtab_node*
> avtab_insert_node(struct avtab *h, int hvalue,
> struct avtab_node * prev, struct avtab_node * cur,
> @@ -59,10 +60,10 @@ static int avtab_insert(struct avtab *h,
> struct avtab_node *prev, *cur, *newnode;
> u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
>
> - if (!h)
> + if (!h || !h->htable)
> return -EINVAL;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = avtab_hash(key, h->mask);
> for (prev = NULL, cur = h->htable[hvalue];
> cur;
> prev = cur, cur = cur->next) {
> @@ -100,9 +101,9 @@ avtab_insert_nonunique(struct avtab * h,
> struct avtab_node *prev, *cur, *newnode;
> u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
>
> - if (!h)
> + if (!h || !h->htable)
> return NULL;
> - hvalue = AVTAB_HASH(key);
> + hvalue = avtab_hash(key, h->mask);
> for (prev = NULL, cur = h->htable[hvalue];
> cur;
> prev = cur, cur = cur->next) {
> @@ -132,10 +133,10 @@ struct avtab_datum *avtab_search(struct
> struct avtab_node *cur;
> u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
>
> - if (!h)
> + if (!h || !h->htable)
> return NULL;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = avtab_hash(key, h->mask);
> for (cur = h->htable[hvalue]; cur; cur = cur->next) {
> if (key->source_type == cur->key.source_type &&
> key->target_type == cur->key.target_type &&
> @@ -167,10 +168,10 @@ avtab_search_node(struct avtab *h, struc
> struct avtab_node *cur;
> u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
>
> - if (!h)
> + if (!h || !h->htable)
> return NULL;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = avtab_hash(key, h->mask);
> for (cur = h->htable[hvalue]; cur; cur = cur->next) {
> if (key->source_type == cur->key.source_type &&
> key->target_type == cur->key.target_type &&
> @@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h)
> if (!h || !h->htable)
> return;
>
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < h->nslot; i++) {
> cur = h->htable[i];
> while (cur != NULL) {
> temp = cur;
> @@ -237,32 +238,63 @@ void avtab_destroy(struct avtab *h)
> }
> h->htable[i] = NULL;
> }
> - vfree(h->htable);
> + kfree(h->htable);
> h->htable = NULL;
> + h->nslot = 0;
> + h->mask = 0;
> }
>
> -
> int avtab_init(struct avtab *h)
> {
> - int i;
> + h->htable = NULL;
> + h->nel = 0;
> + return 0;
> +}
> +
> +int avtab_alloc(struct avtab *h, u32 nrules)
> +{
> + u16 mask = 0;
> + u32 shift = 0;
> + u32 work = nrules;
> + u32 nslot = 0;
> +
> + if (nrules == 0)
> + goto avtab_alloc_out;
> +
> + while (work) {
> + work = work >> 1;
> + shift++;
> + }
> + if (shift > 2)
> + shift = shift - 2;
> + nslot = 1 << shift;
> + if (nslot > MAX_AVTAB_SIZE)
> + nslot = MAX_AVTAB_SIZE;
> + mask = nslot - 1;
>
> - h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
> + h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
> if (!h->htable)
> return -ENOMEM;
> - for (i = 0; i < AVTAB_SIZE; i++)
> - h->htable[i] = NULL;
> +
> + avtab_alloc_out:
> h->nel = 0;
> + h->nslot = nslot;
> + h->mask = mask;
> + printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
> + "Num of rules:%d\n", h->nslot, nrules);
> return 0;
> }
>
> void avtab_hash_eval(struct avtab *h, char *tag)
> {
> int i, chain_len, slots_used, max_chain_len;
> + unsigned long long chain2_len_sum;
> struct avtab_node *cur;
>
> slots_used = 0;
> max_chain_len = 0;
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + chain2_len_sum = 0;
> + for (i = 0; i < h->nslot; i++) {
> cur = h->htable[i];
> if (cur) {
> slots_used++;
> @@ -274,12 +306,14 @@ void avtab_hash_eval(struct avtab *h, ch
>
> if (chain_len > max_chain_len)
> max_chain_len = chain_len;
> + chain2_len_sum += chain_len * chain_len;
> }
> }
>
> printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
> - "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
> - max_chain_len);
> + "chain length %d sum of chain length^2 %Lu\n",
> + tag, h->nel, slots_used, h->nslot, max_chain_len,
> + chain2_len_sum);
> }
>
> static uint16_t spec_order[] = {
> @@ -419,6 +453,11 @@ int avtab_read(struct avtab *a, void *fp
> rc = -EINVAL;
> goto bad;
> }
> +
> + rc = avtab_alloc(a, nel);
> + if (rc)
> + goto bad;
> +
> for (i = 0; i < nel; i++) {
> rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
> if (rc) {
> diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.h linux-2.6.22/security/selinux/ss/avtab.h
> --- linux-2.6.22.orig/security/selinux/ss/avtab.h 2007-07-09 08:32:17.000000000 +0900
> +++ linux-2.6.22/security/selinux/ss/avtab.h 2007-08-24 11:52:24.000000000 +0900
> @@ -16,6 +16,9 @@
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License as published by
> * the Free Software Foundation, version 2.
> + *
> + * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
> + * Tuned number of hash slots for avtab to reduce memory usage
> */
> #ifndef _SS_AVTAB_H_
> #define _SS_AVTAB_H_
> @@ -50,9 +53,13 @@ struct avtab_node {
> struct avtab {
> struct avtab_node **htable;
> u32 nel; /* number of elements */
> + u32 nslot; /* number of hash slots */
> + u16 mask; /* mask to compute hash func */
> +
> };
>
> int avtab_init(struct avtab *);
> +int avtab_alloc(struct avtab *, u32);
> struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
> void avtab_destroy(struct avtab *h);
> void avtab_hash_eval(struct avtab *h, char *tag);
> @@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nex
> void avtab_cache_init(void);
> void avtab_cache_destroy(void);
>
> -#define AVTAB_HASH_BITS 15
> -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
> -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
> -
> -#define AVTAB_SIZE AVTAB_HASH_BUCKETS
> +#define MAX_AVTAB_HASH_BITS 13
> +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
> +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
> +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
>
> #endif /* _SS_AVTAB_H_ */
>
> diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/conditional.c linux-2.6.22/security/selinux/ss/conditional.c
> --- linux-2.6.22.orig/security/selinux/ss/conditional.c 2007-07-09 08:32:17.000000000 +0900
> +++ linux-2.6.22/security/selinux/ss/conditional.c 2007-08-24 11:52:24.000000000 +0900
> @@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, v
>
> len = le32_to_cpu(buf[0]);
>
> + rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
> + if (rc)
> + goto err;
> +
> for (i = 0; i < len; i++) {
> node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
> if (!node)
> diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/policydb.c linux-2.6.22/security/selinux/ss/policydb.c
> --- linux-2.6.22.orig/security/selinux/ss/policydb.c 2007-07-09 08:32:17.000000000 +0900
> +++ linux-2.6.22/security/selinux/ss/policydb.c 2007-08-24 11:52:24.000000000 +0900
> @@ -176,18 +176,15 @@ static int policydb_init(struct policydb
>
> rc = roles_init(p);
> if (rc)
> - goto out_free_avtab;
> + goto out_free_symtab;
>
> rc = cond_policydb_init(p);
> if (rc)
> - goto out_free_avtab;
> + goto out_free_symtab;
>
> out:
> return rc;
>
> -out_free_avtab:
> - avtab_destroy(&p->te_avtab);
> -
> out_free_symtab:
> for (i = 0; i < SYM_NUM; i++)
> hashtab_destroy(p->symtab[i].table);
>
> Regards,
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-27 13:39 ` Stephen Smalley
@ 2007-08-27 16:55 ` James Morris
0 siblings, 0 replies; 52+ messages in thread
From: James Morris @ 2007-08-27 16:55 UTC (permalink / raw)
To: Stephen Smalley; +Cc: Yuichi Nakamura, selinux, Eric Paris, kaigai
On Mon, 27 Aug 2007, Stephen Smalley wrote:
> Looks good, thanks.
>
> Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Applied to
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6.git#for-akpm
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-22 9:25 ` KaiGai Kohei
@ 2007-09-12 3:08 ` KaiGai Kohei
2007-09-12 19:54 ` Paul Moore
2007-09-18 17:21 ` [patch] Tuning avtab to reduce memory usage Stephen Smalley
0 siblings, 2 replies; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-12 3:08 UTC (permalink / raw)
To: selinux
Cc: Paul Moore, Stephen Smalley, Yuichi Nakamura, James Morris,
Eric Paris
[-- Attachment #1: Type: text/plain, Size: 4891 bytes --]
The attached patch applies the standard bitmap operations
for the iteration macro of ebitmap, and enables to improve
the performance in AVC-misses case.
Real-time responsibility is a significant issue for embedded
Linux people. This patch also reduce amount of busy loop in
the kernel, so it can improve real-time responsibility.
I added ebitmap_for_each_positive_bit() macro not to walk
on any native bit within ebitmap, and applies it on
- context_struct_compute_av()
- security_get_user_sids()
- mls_context_isvalid()
ebitmap_node was redefined as follows:
#define EBITMAP_UNIT_NUMS \
((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
struct ebitmap_node {
struct ebitmap_node *next;
unsigned long maps[EBITMAP_UNIT_NUMS];
u32 startbit;
};
"u64 map" is replaced by an array of "unsigned long". It enables to
apply standard bit operations. In addition, length of the array is
determind to fit 32-bytes, the minimum size of kmalloc().
The result of benchmarks seems to me fine.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s]
STD: 0.265 0.019
------------------------------------------
1st: 22.558 [s] 8.786 [s]
2nd: 22.458 [s] 8.750 [s]
3rd: 22.478 [s] 8.754 [s]
4th: 22.724 [s] 8.745 [s]
5th: 22.918 [s] 8.748 [s]
6th: 22.905 [s] 8.764 [s]
7th: 23.238 [s] 8.726 [s]
8th: 22.822 [s] 8.729 [s]
NOTE: We used the following operatins as a test case.
No need to say, it is a corner case to highlight.
[root@saba ~]# id -Z
root:system_r:unconfined_t:SystemLow-SystemHigh
[root@saba ~]# cd /dev/shm
[root@saba shm]# for I in `seq 1 640`
> do
> echo > file${I}
> chcon -l s0:c${I} file${I}
> done
[root@saba shm]# ~kaigai/manyfiles 800 file*
I also attached "manyfiles.c" to reproduce them.
In addition, we could not make sure a statistical difference
in the AVC-hits case.
Thanks,
KaiGai Kohei wrote:
> Paul Moore wrote:
>> On Tuesday, August 21 2007 12:37:49 pm Stephen Smalley wrote:
>>> On Tue, 2007-08-21 at 11:11 -0400, Paul Moore wrote:
>>>> On Tuesday, August 21 2007 9:47:38 am Stephen Smalley wrote:
>>>>> We likely should look at optimizing the ebitmap code, or replacing it
>>>>> with the native kernel bitmaps (include/linux/bitmap.h, lib/bitmap.c).
>>>>> For example, ebitmap_next could possibly use find_next_bit().
>>>> [Removed the busybox list because I'm sure they don't care]
>>>>
>>>> Would the fact that the MLS category bitmaps grow to 1024 bits be a
>>>> concern with using a single contiguous bitmap instead of the sparse
>>>> bitmap the ebitmap currently uses? Granted, in the worst case of
>>>> c0.c1023 the kernel bitmap would most certainly be better but I wonder
>>>> what the common case is (and if the MLS compartments even factor
>>>> into the
>>>> discussion) and which type is better suited to handle this case.
>>> Even if we retain the ebitmap type as a sparse bitmap, I think we can do
>>> some optimization of its internals, possibly leveraging things like
>>> find_next_bit(), to speed up the loops that were introduced when we
>>> optimized the avtab memory layout by pushing attributes down into the
>>> kernel policy (policy.20).
>>>
>>> Trying Yuichi's simple instrumentation of security_compute_av, I see a
>>> huge difference in security_compute_av times between policy.19 and
>>> policy.20. We knew it would slow security_compute_av down (standard
>>> tradeoff between runtime performance and memory use), but the thinking
>>> at the time was that it wouldn't matter because of the AVC. But we do
>>> have to bound our worst case latency.
>>
>> I understand, I was just slightly concerned about losing the sparse
>> bitmap feature which I have a hunch is beneficial in the MLS
>> compartment case. Although I will readily admit I have no data to
>> support this claim, I just wanted to throw it out as something to
>> consider.
>
> I think the sparse bitmap feature is also useful to skip unnecessary scan
> on the ebitmap, so these features should be used together.
>
> The current version of ebitmap contains a 64-bit length bitmap.
> I have a concern to apply the standard bitops, and memory usage.
>
> The one is a difference in the type of variable.
> find_next_bit() requires the bitmap defined as unsigned long array,
> but ebitmap uses a u64 value as a bitmap, so we cannot apply it as is.
>
> The other is memory usage. The ebitmap_node is allocated by kzalloc().
> However, sizeof(ebitmap_node) is 16-byte in 32bit arch, although
> the minimun unit of kmalloc() is 32 byte.
>
> In 32-bit arch, map should be defined as 'unsigned long map[6]'
> to apply the standard bitops and to maximun memory usage.
>
> Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
[-- Attachment #2: ebitmap-bitops.patch --]
[-- Type: text/x-patch, Size: 18599 bytes --]
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ce492a6..de9ef55 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/
+/*
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Applied standard bit operations to improve bitmap scanning.
+ */
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
n2 = e2->node;
while (n1 && n2 &&
(n1->startbit == n2->startbit) &&
- (n1->map == n2->map)) {
+ !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
n1 = n1->next;
n2 = n2->next;
}
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
return -ENOMEM;
}
new->startbit = n->startbit;
- new->map = n->map;
+ memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
new->next = NULL;
if (prev)
prev->next = new;
@@ -84,7 +88,8 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
{
struct ebitmap_node *e_iter = ebmap->node;
struct netlbl_lsm_secattr_catmap *c_iter;
- u32 cmap_idx;
+ u32 cmap_idx, cmap_sft;
+ int i;
/* This function is a much simpler because SELinux's MAPTYPE happens
* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
@@ -104,19 +109,20 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) {
- if (e_iter->startbit >=
- (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
- c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
- if (c_iter->next == NULL)
- goto netlbl_export_failure;
- c_iter = c_iter->next;
- c_iter->startbit = e_iter->startbit &
- ~(NETLBL_CATMAP_SIZE - 1);
+ for (i=0; i < EBITMAP_UNIT_NUMS; i++) {
+ unsigned int e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
+ if (e_startbit >= c_iter->startbit + NETLBL_CATMAP_SIZE) {
+ c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (c_iter->next == NULL)
+ goto netlbl_export_failure;
+ c_iter = c_iter->next;
+ c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
+ cmap_idx = (e_startbit - c_iter->startbit) / NETLBL_CATMAP_MAPSIZE;
+ cmap_sft = (e_startbit - c_iter->startbit) % NETLBL_CATMAP_MAPSIZE;
+ c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft;
+ e_iter = e_iter->next;
}
- cmap_idx = (e_iter->startbit - c_iter->startbit) /
- NETLBL_CATMAP_MAPSIZE;
- c_iter->bitmap[cmap_idx] = e_iter->map;
- e_iter = e_iter->next;
}
return 0;
@@ -128,7 +134,7 @@ netlbl_export_failure:
/**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
- * @ebmap: the ebitmap to export
+ * @ebmap: the ebitmap to import
* @catmap: the NetLabel category bitmap
*
* Description:
@@ -142,7 +148,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap;
- u32 c_idx;
+ u32 c_idx, c_pos, e_idx, e_sft;
/* This function is a much simpler because SELinux's MAPTYPE happens
* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
@@ -152,26 +158,34 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
- if (c_iter->bitmap[c_idx] == 0)
+ u64 map = c_iter->bitmap[c_idx];
+
+ if (!map)
continue;
- e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
- if (e_iter == NULL)
- goto netlbl_import_failure;
- if (emap_prev == NULL)
- ebmap->node = e_iter;
- else
- emap_prev->next = e_iter;
- emap_prev = e_iter;
-
- e_iter->startbit = c_iter->startbit +
- NETLBL_CATMAP_MAPSIZE * c_idx;
- e_iter->map = c_iter->bitmap[c_idx];
+ c_pos = c_iter->startbit + c_idx * NETLBL_CATMAP_MAPSIZE;
+ if (!e_iter || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
+ e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+ if (!e_iter)
+ goto netlbl_import_failure;
+ e_iter->startbit = c_pos - (c_pos % EBITMAP_SIZE);
+ if (emap_prev == NULL)
+ ebmap->node = e_iter;
+ else
+ emap_prev->next = e_iter;
+ emap_prev = e_iter;
+ }
+ e_idx = (c_pos - e_iter->startbit) / EBITMAP_UNIT_SIZE;
+ e_sft = (c_pos - e_iter->startbit) % EBITMAP_UNIT_SIZE;
+ while (map) {
+ e_iter->maps[e_idx++] |= map & (-1UL);
+ map >>= EBITMAP_UNIT_SIZE;
+ }
}
c_iter = c_iter->next;
} while (c_iter != NULL);
if (e_iter != NULL)
- ebmap->highbit = e_iter->startbit + MAPSIZE;
+ ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
else
ebitmap_destroy(ebmap);
@@ -186,6 +200,7 @@ netlbl_import_failure:
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
+ int i;
if (e1->highbit < e2->highbit)
return 0;
@@ -197,8 +212,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next;
continue;
}
- if ((n1->map & n2->map) != n2->map)
- return 0;
+ for (i=0; i < EBITMAP_UNIT_NUMS; i++) {
+ if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
+ return 0;
+ }
n1 = n1->next;
n2 = n2->next;
@@ -219,12 +236,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node;
while (n && (n->startbit <= bit)) {
- if ((n->startbit + MAPSIZE) > bit) {
- if (n->map & (MAPBIT << (bit - n->startbit)))
- return 1;
- else
- return 0;
- }
+ if ((n->startbit + EBITMAP_SIZE) > bit)
+ return ebitmap_node_get_bit(n, bit);
n = n->next;
}
@@ -238,31 +251,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
- if ((n->startbit + MAPSIZE) > bit) {
+ if ((n->startbit + EBITMAP_SIZE) > bit) {
if (value) {
- n->map |= (MAPBIT << (bit - n->startbit));
+ ebitmap_node_set_bit(n, bit);
} else {
- n->map &= ~(MAPBIT << (bit - n->startbit));
- if (!n->map) {
- /* drop this node from the bitmap */
-
- if (!n->next) {
- /*
- * this was the highest map
- * within the bitmap
- */
- if (prev)
- e->highbit = prev->startbit + MAPSIZE;
- else
- e->highbit = 0;
- }
+ ebitmap_node_clr_bit(n, bit);
+
+ if (find_first_bit(n->maps, EBITMAP_SIZE) < EBITMAP_SIZE)
+ return 0;
+
+ /* drop this node from the bitmap */
+ if (!n->next) {
+ /*
+ * this was the highest map
+ * within the bitmap
+ */
if (prev)
- prev->next = n->next;
+ e->highbit = prev->startbit + EBITMAP_SIZE;
else
- e->node = n->next;
-
- kfree(n);
+ e->highbit = 0;
}
+ if (prev)
+ prev->next = n->next;
+ else
+ e->node = n->next;
+ kfree(n);
}
return 0;
}
@@ -277,12 +290,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new)
return -ENOMEM;
- new->startbit = bit & ~(MAPSIZE - 1);
- new->map = (MAPBIT << (bit - new->startbit));
+ new->startbit = bit - (bit % EBITMAP_SIZE);
+ ebitmap_node_set_bit(new, bit);
if (!n)
/* this node will be the highest map within the bitmap */
- e->highbit = new->startbit + MAPSIZE;
+ e->highbit = new->startbit + EBITMAP_SIZE;
if (prev) {
new->next = prev->next;
@@ -316,11 +329,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
- int rc;
- struct ebitmap_node *n, *l;
+ struct ebitmap_node *n = NULL;
+ u32 mapunit, count, startbit, index;
+ u64 map;
__le32 buf[3];
- u32 mapsize, count, i;
- __le64 map;
+ int rc, i;
ebitmap_init(e);
@@ -328,85 +341,84 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
- mapsize = le32_to_cpu(buf[0]);
+ mapunit = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]);
- if (mapsize != MAPSIZE) {
+ /* round up e->highbit */
+ e->highbit += EBITMAP_SIZE - 1;
+ e->highbit -= (e->highbit % EBITMAP_SIZE);
+
+ if (mapunit != sizeof(u64) * 8) {
printk(KERN_ERR "security: ebitmap: map size %u does not "
- "match my size %Zd (high bit was %d)\n", mapsize,
- MAPSIZE, e->highbit);
+ "match my size %Zd (high bit was %d)\n",
+ mapunit, sizeof(u64) * 8, e->highbit);
goto bad;
}
if (!e->highbit) {
e->node = NULL;
goto ok;
}
- if (e->highbit & (MAPSIZE - 1)) {
- printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
- "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
- goto bad;
- }
- l = NULL;
+
for (i = 0; i < count; i++) {
- rc = next_entry(buf, fp, sizeof(u32));
+ rc = next_entry(&startbit, fp, sizeof(u32));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad;
}
- n = kzalloc(sizeof(*n), GFP_KERNEL);
- if (!n) {
- printk(KERN_ERR "security: ebitmap: out of memory\n");
- rc = -ENOMEM;
- goto bad;
- }
-
- n->startbit = le32_to_cpu(buf[0]);
+ startbit = le32_to_cpu(startbit);
- if (n->startbit & (MAPSIZE - 1)) {
+ if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map size (%Zd)\n",
- n->startbit, MAPSIZE);
- goto bad_free;
+ "not a multiple of the map unit size (%Zd)\n",
+ startbit, mapunit);
+ goto bad;
}
- if (n->startbit > (e->highbit - MAPSIZE)) {
+ if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%Zd)\n",
- n->startbit, (e->highbit - MAPSIZE));
- goto bad_free;
+ startbit, (e->highbit - mapunit));
+ goto bad;
}
+
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
+ struct ebitmap_node *_n = kzalloc(sizeof(*_n), GFP_KERNEL);
+ if (!_n) {
+ printk(KERN_ERR "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ _n->startbit = startbit - (startbit % EBITMAP_SIZE); /* round down */
+ if (n) {
+ n->next = _n;
+ } else {
+ e->node = _n;
+ }
+ n = _n;
+ } else if (startbit <= n->startbit) {
+ printk(KERN_ERR "security: ebitmap: start bit %d"
+ " comes after start bit %d\n",
+ startbit, n->startbit);
+ }
+
rc = next_entry(&map, fp, sizeof(u64));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
- goto bad_free;
+ goto bad;
}
- n->map = le64_to_cpu(map);
+ map = le64_to_cpu(map);
- if (!n->map) {
- printk(KERN_ERR "security: ebitmap: null map in "
- "ebitmap (startbit %d)\n", n->startbit);
- goto bad_free;
+ index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
+ while (map) {
+ n->maps[index] = map & (-1UL);
+ map = map >> EBITMAP_UNIT_SIZE;
+ index++;
}
- if (l) {
- if (n->startbit <= l->startbit) {
- printk(KERN_ERR "security: ebitmap: start "
- "bit %d comes after start bit %d\n",
- n->startbit, l->startbit);
- goto bad_free;
- }
- l->next = n;
- } else
- e->node = n;
-
- l = n;
}
-
ok:
rc = 0;
out:
return rc;
-bad_free:
- kfree(n);
bad:
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 1270e34..fc0ce05 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -16,14 +16,15 @@
#include <net/netlabel.h>
-#define MAPTYPE u64 /* portion of bitmap in each node */
-#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
-#define MAPBIT 1ULL /* a bit in the node bitmap */
+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1ULL
struct ebitmap_node {
- u32 startbit; /* starting position in the total bitmap */
- MAPTYPE map; /* this node's portion of the bitmap */
struct ebitmap_node *next;
+ unsigned long maps[EBITMAP_UNIT_NUMS];
+ u32 startbit;
};
struct ebitmap {
@@ -41,6 +42,19 @@ static inline unsigned int ebitmap_start(struct ebitmap *e,
return ebitmap_startbit(e);
}
+static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+ struct ebitmap_node **n)
+{
+ unsigned int ofs;
+
+ for (*n = e->node; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return (*n)->startbit + ofs;
+ }
+ return ebitmap_length(e);
+}
+
static inline void ebitmap_init(struct ebitmap *e)
{
memset(e, 0, sizeof(*e));
@@ -49,7 +63,7 @@ static inline void ebitmap_init(struct ebitmap *e)
static inline unsigned int ebitmap_next(struct ebitmap_node **n,
unsigned int bit)
{
- if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
+ if ((bit == ((*n)->startbit + EBITMAP_SIZE - 1)) &&
(*n)->next) {
*n = (*n)->next;
return (*n)->startbit;
@@ -58,16 +72,64 @@ static inline unsigned int ebitmap_next(struct ebitmap_node **n,
return (bit+1);
}
+static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
+ struct ebitmap_node **n,
+ unsigned int bit)
+{
+ unsigned int ofs;
+
+ ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+
+ for (*n = (*n)->next; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+ }
+ return ebitmap_length(e);
+}
+
static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
unsigned int bit)
{
- if (n->map & (MAPBIT << (bit - n->startbit)))
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
+
+ if (index < EBITMAP_UNIT_NUMS && (n->maps[index] & (EBITMAP_BIT << ofs)))
return 1;
return 0;
}
-#define ebitmap_for_each_bit(e, n, bit) \
- for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+
+ if (index < EBITMAP_UNIT_NUMS)
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+
+ if (index < EBITMAP_UNIT_NUMS)
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+ for (bit = ebitmap_start(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next(&n, bit)) \
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for (bit = ebitmap_start_positive(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2..846314f 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -190,17 +190,17 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (i > p->p_cats.nprim)
- return 0;
- if (!ebitmap_get_bit(&levdatum->level->cat, i))
- /*
- * Category may not be associated with
- * sensitivity in low level.
- */
- return 0;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ // BUG_ON(!ebitmap_node_get_bit(node, i));
+
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
+ /*
+ * Category may not be associated with
+ * sensitivity in low level.
+ */
+ return 0;
}
}
@@ -485,18 +485,17 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- int rc;
-
- catdatum = hashtab_search(newp->p_cats.table,
- oldp->p_cat_val_to_name[i]);
- if (!catdatum)
- return -EINVAL;
- rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
- if (rc)
- return rc;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ int rc;
+
+ // BUG_ON(!ebitmap_node_get_bit(node, i));
+ catdatum = hashtab_search(newp->p_cats.table,
+ oldp->p_cat_val_to_name[i]);
+ if (!catdatum)
+ return -EINVAL;
+ rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
+ if (rc)
+ return rc;
}
ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 40660ff..0729996 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -329,12 +329,12 @@ static int context_struct_compute_av(struct context *scontext,
avkey.specified = AVTAB_AV;
sattr = &policydb.type_attr_map[scontext->type - 1];
tattr = &policydb.type_attr_map[tcontext->type - 1];
- ebitmap_for_each_bit(sattr, snode, i) {
- if (!ebitmap_node_get_bit(snode, i))
- continue;
- ebitmap_for_each_bit(tattr, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(sattr, snode, i) {
+ // BUG_ON(!ebitmap_node_get_bit(snode, i));
+
+ ebitmap_for_each_positive_bit(tattr, tnode, j) {
+ // BUG_ON(!ebitmap_node_get_bit(tnode, j));
+
avkey.source_type = i + 1;
avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1622,14 +1622,14 @@ int security_get_user_sids(u32 fromsid,
goto out_unlock;
}
- ebitmap_for_each_bit(&user->roles, rnode, i) {
- if (!ebitmap_node_get_bit(rnode, i))
- continue;
+ ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
+ // BUG_ON(!ebitmap_node_get_bit(rnode, i));
+
role = policydb.role_val_to_struct[i];
usercon.role = i+1;
- ebitmap_for_each_bit(&role->types, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(&role->types, tnode, j) {
+ // BUG_ON(!ebitmap_node_get_bit(tnode, j));
+
usercon.type = j+1;
if (mls_setup_user_range(fromcon, user, &usercon))
[-- Attachment #3: manyfiles.c --]
[-- Type: text/plain, Size: 1523 bytes --]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static void usage(int exitcode) {
fprintf(stderr, "usage: manyfiles <# of loop> <files ...>\n");
exit(exitcode);
}
#define TEST_STR "abcdefghijklmnopqrstuvwxyz0123456789\n"
int main(int argc, char *argv[]) {
char buffer[128];
int i, j, nloops, nfiles, *fd;
struct timeval t1, t2;
double delta;
if (argc < 3)
usage(1);
nloops = atoi(argv[1]);
if (nloops < 1)
nloops = 1;
fd = malloc(sizeof(int *) * argc);
if (!fd) {
fprintf(stderr, "could not allocate memory (%s)\n", strerror(errno));
return 1;
}
for (i=2, nfiles=0; argv[i]; i++) {
fd[nfiles] = open(argv[i], O_RDWR | O_CREAT, 0644);
if (fd[nfiles] < 0) {
fprintf(stderr, "could not open %s (%s)\n",
argv[i], strerror(errno));
continue;
}
nfiles++;
}
gettimeofday(&t1, NULL);
for (i=0; i < nloops; i++) {
for (j=0; j < nfiles; j++) {
lseek(fd[j], 0, SEEK_SET);
write(fd[j], TEST_STR, sizeof(TEST_STR));
}
for (j=0; j < nfiles; j++) {
lseek(fd[j], 0, SEEK_SET);
read(fd[j], buffer, sizeof(buffer));
}
}
gettimeofday(&t2, NULL);
delta = (((double)t2.tv_sec * 1000000.0 + (double)t2.tv_usec)
- ((double)t1.tv_sec * 1000000.0 + (double)t1.tv_usec)) / 1000000.0;
printf("%d files, %d loops, %.3f [sec]\n", nfiles, nloops, delta);
return 0;
}
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-09-12 3:08 ` KaiGai Kohei
@ 2007-09-12 19:54 ` Paul Moore
2007-09-13 1:37 ` [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage) KaiGai Kohei
2007-09-18 17:21 ` [patch] Tuning avtab to reduce memory usage Stephen Smalley
1 sibling, 1 reply; 52+ messages in thread
From: Paul Moore @ 2007-09-12 19:54 UTC (permalink / raw)
To: KaiGai Kohei
Cc: selinux, Stephen Smalley, Yuichi Nakamura, James Morris,
Eric Paris
On Tuesday, September 11 2007 11:08:44 pm KaiGai Kohei wrote:
> The attached patch applies the standard bitmap operations
> for the iteration macro of ebitmap, and enables to improve
> the performance in AVC-misses case.
In addition to the code changes to ebitmap_netlbl_{import,export}() you should
probably either remove, or preferably update, the comment block in the body
of the functions.
Thank you for also fixing my cut and paste error in the comment block at the
top of the ebitmap_netlbl_import() function :)
--
paul moore
linux security @ hp
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage)
2007-09-12 19:54 ` Paul Moore
@ 2007-09-13 1:37 ` KaiGai Kohei
2007-09-13 11:34 ` Stephen Smalley
2007-09-13 20:47 ` [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage) Paul Moore
0 siblings, 2 replies; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-13 1:37 UTC (permalink / raw)
To: Paul Moore
Cc: selinux, Stephen Smalley, Yuichi Nakamura, James Morris,
Eric Paris
Paul Moore wrote:
> On Tuesday, September 11 2007 11:08:44 pm KaiGai Kohei wrote:
>> The attached patch applies the standard bitmap operations
>> for the iteration macro of ebitmap, and enables to improve
>> the performance in AVC-misses case.
>
> In addition to the code changes to ebitmap_netlbl_{import,export}() you should
> probably either remove, or preferably update, the comment block in the body
> of the functions.
I replaced the comment block as follows:
/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
* however, it is not always compatible with an array of unsigned long
* in ebitmap_node.
* In addition, you should pay attention the following implementation
* assumes unsigned long has a width equal with or less than 64-bit.
*/
BTW, is there any wrapper to copy an array of u64 to/from architecture specific
unsigned long? If so, it will help implement ebitmap_netlbl_{import|export}()
and ebitmap_read() more simply.
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage)
2007-09-13 1:37 ` [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage) KaiGai Kohei
@ 2007-09-13 11:34 ` Stephen Smalley
2007-09-14 1:02 ` KaiGai Kohei
2007-09-13 20:47 ` [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage) Paul Moore
1 sibling, 1 reply; 52+ messages in thread
From: Stephen Smalley @ 2007-09-13 11:34 UTC (permalink / raw)
To: KaiGai Kohei
Cc: Paul Moore, selinux, Yuichi Nakamura, James Morris, Eric Paris
On Thu, 2007-09-13 at 10:37 +0900, KaiGai Kohei wrote:
> Paul Moore wrote:
> > On Tuesday, September 11 2007 11:08:44 pm KaiGai Kohei wrote:
> >> The attached patch applies the standard bitmap operations
> >> for the iteration macro of ebitmap, and enables to improve
> >> the performance in AVC-misses case.
> >
> > In addition to the code changes to ebitmap_netlbl_{import,export}() you should
> > probably either remove, or preferably update, the comment block in the body
> > of the functions.
>
> I replaced the comment block as follows:
>
> /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
> * however, it is not always compatible with an array of unsigned long
> * in ebitmap_node.
> * In addition, you should pay attention the following implementation
> * assumes unsigned long has a width equal with or less than 64-bit.
> */
>
> BTW, is there any wrapper to copy an array of u64 to/from architecture specific
> unsigned long? If so, it will help implement ebitmap_netlbl_{import|export}()
> and ebitmap_read() more simply.
Might want to ask on linux-kernel. More generally, it might be a good
idea to cc linux-kernel on your next posting of the patch to get wider
review of how you are using the native linux bitmap support.
The patch looks very promising, although a detailed review and testing
might take a little bit.
--
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage)
2007-09-13 1:37 ` [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage) KaiGai Kohei
2007-09-13 11:34 ` Stephen Smalley
@ 2007-09-13 20:47 ` Paul Moore
1 sibling, 0 replies; 52+ messages in thread
From: Paul Moore @ 2007-09-13 20:47 UTC (permalink / raw)
To: KaiGai Kohei
Cc: selinux, Stephen Smalley, Yuichi Nakamura, James Morris,
Eric Paris
On Wednesday, September 12 2007 9:37:30 pm KaiGai Kohei wrote:
> Paul Moore wrote:
> > On Tuesday, September 11 2007 11:08:44 pm KaiGai Kohei wrote:
> >> The attached patch applies the standard bitmap operations
> >> for the iteration macro of ebitmap, and enables to improve
> >> the performance in AVC-misses case.
> >
> > In addition to the code changes to ebitmap_netlbl_{import,export}() you
> > should probably either remove, or preferably update, the comment block in
> > the body of the functions.
>
> I replaced the comment block as follows:
>
> /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
> * however, it is not always compatible with an array of unsigned long
> * in ebitmap_node.
> * In addition, you should pay attention the following implementation
> * assumes unsigned long has a width equal with or less than 64-bit.
> */
That sound good to me. FWIW, if/when this patch is accepted I'll take a look
at the NetLabel security attributes struct as it _may_ be possible to change
the NETLBL_CATMAP_MAPTYPE to an unsigned long from the u64 it currently uses.
That should make these import/export functions a little cleaner.
> BTW, is there any wrapper to copy an array of u64 to/from architecture
> specific unsigned long? If so, it will help implement
> ebitmap_netlbl_{import|export}() and ebitmap_read() more simply.
I'm not sure, but Stephen's suggestion to ask lkml sounds like a good one.
--
paul moore
linux security @ hp
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Wrappers to load bitmaps (Re: [PATCH] Improve ebitmap scanning)
2007-09-13 11:34 ` Stephen Smalley
@ 2007-09-14 1:02 ` KaiGai Kohei
0 siblings, 0 replies; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-14 1:02 UTC (permalink / raw)
To: linux-kernel
Cc: Stephen Smalley, Paul Moore, selinux, Yuichi Nakamura,
James Morris, Eric Paris
Now I'm improving the performance to scan bitmap in SELinux,
with replacing its original bitmap implementation (ebitmap)
by common bitops like find_next_bit().
I posted a patch to replace them, however, it got a bit complex
bacause we had to translate u64 <--> unsigned long by myself
to adjust between the format of security policy and common bitops.
http://marc.info/?l=selinux&m=118956715414494&w=2
I have an idea to provide several wrapper functions to copy u64/u32
to/from unsigned long for each architecture.
Maybe, it will be defined as follows:
int arraycpy_u64_to_ulong(u64 *src, unsigned long *dest, size_t len);
int arraycpy_ulong_to_u64(unsigned long *src, u64 *dest, size_t len);
I believe this feature will help getting code simpler and reducing bugs
for any other subsystem, not only SELinux, which loads bitmaps from/to
userspace and handle them using common bitops.
Any comment please.
Stephen Smalley wrote:
> On Thu, 2007-09-13 at 10:37 +0900, KaiGai Kohei wrote:
>> Paul Moore wrote:
>>> On Tuesday, September 11 2007 11:08:44 pm KaiGai Kohei wrote:
>>>> The attached patch applies the standard bitmap operations
>>>> for the iteration macro of ebitmap, and enables to improve
>>>> the performance in AVC-misses case.
<...snip...>
>> BTW, is there any wrapper to copy an array of u64 to/from architecture specific
>> unsigned long? If so, it will help implement ebitmap_netlbl_{import|export}()
>> and ebitmap_read() more simply.
>
> Might want to ask on linux-kernel. More generally, it might be a good
> idea to cc linux-kernel on your next posting of the patch to get wider
> review of how you are using the native linux bitmap support.
>
> The patch looks very promising, although a detailed review and testing
> might take a little bit.
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Wrappers to load bitmaps (Re: [PATCH] Improve ebitmap scanning)
@ 2007-09-14 1:02 ` KaiGai Kohei
0 siblings, 0 replies; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-14 1:02 UTC (permalink / raw)
To: linux-kernel
Cc: Stephen Smalley, Paul Moore, selinux, Yuichi Nakamura,
James Morris, Eric Paris
Now I'm improving the performance to scan bitmap in SELinux,
with replacing its original bitmap implementation (ebitmap)
by common bitops like find_next_bit().
I posted a patch to replace them, however, it got a bit complex
bacause we had to translate u64 <--> unsigned long by myself
to adjust between the format of security policy and common bitops.
http://marc.info/?l=selinux&m=118956715414494&w=2
I have an idea to provide several wrapper functions to copy u64/u32
to/from unsigned long for each architecture.
Maybe, it will be defined as follows:
int arraycpy_u64_to_ulong(u64 *src, unsigned long *dest, size_t len);
int arraycpy_ulong_to_u64(unsigned long *src, u64 *dest, size_t len);
I believe this feature will help getting code simpler and reducing bugs
for any other subsystem, not only SELinux, which loads bitmaps from/to
userspace and handle them using common bitops.
Any comment please.
Stephen Smalley wrote:
> On Thu, 2007-09-13 at 10:37 +0900, KaiGai Kohei wrote:
>> Paul Moore wrote:
>>> On Tuesday, September 11 2007 11:08:44 pm KaiGai Kohei wrote:
>>>> The attached patch applies the standard bitmap operations
>>>> for the iteration macro of ebitmap, and enables to improve
>>>> the performance in AVC-misses case.
<...snip...>
>> BTW, is there any wrapper to copy an array of u64 to/from architecture specific
>> unsigned long? If so, it will help implement ebitmap_netlbl_{import|export}()
>> and ebitmap_read() more simply.
>
> Might want to ask on linux-kernel. More generally, it might be a good
> idea to cc linux-kernel on your next posting of the patch to get wider
> review of how you are using the native linux bitmap support.
>
> The patch looks very promising, although a detailed review and testing
> might take a little bit.
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-09-12 3:08 ` KaiGai Kohei
2007-09-12 19:54 ` Paul Moore
@ 2007-09-18 17:21 ` Stephen Smalley
2007-09-18 22:11 ` Paul Moore
2007-09-20 8:14 ` KaiGai Kohei
1 sibling, 2 replies; 52+ messages in thread
From: Stephen Smalley @ 2007-09-18 17:21 UTC (permalink / raw)
To: KaiGai Kohei
Cc: selinux, Paul Moore, Yuichi Nakamura, James Morris, Eric Paris
On Wed, 2007-09-12 at 12:08 +0900, KaiGai Kohei wrote:
> The attached patch applies the standard bitmap operations
> for the iteration macro of ebitmap, and enables to improve
> the performance in AVC-misses case.
>
> Real-time responsibility is a significant issue for embedded
> Linux people. This patch also reduce amount of busy loop in
> the kernel, so it can improve real-time responsibility.
>
> I added ebitmap_for_each_positive_bit() macro not to walk
> on any native bit within ebitmap, and applies it on
> - context_struct_compute_av()
> - security_get_user_sids()
> - mls_context_isvalid()
>
> ebitmap_node was redefined as follows:
> #define EBITMAP_UNIT_NUMS \
> ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
> struct ebitmap_node {
> struct ebitmap_node *next;
> unsigned long maps[EBITMAP_UNIT_NUMS];
> u32 startbit;
> };
>
> "u64 map" is replaced by an array of "unsigned long". It enables to
> apply standard bit operations. In addition, length of the array is
> determind to fit 32-bytes, the minimum size of kmalloc().
>
> The result of benchmarks seems to me fine.
>
> selinux-2.6 selinux-2.6-ebitmap
> AVG: 22.763 [s] 8.750 [s]
> STD: 0.265 0.019
> ------------------------------------------
> 1st: 22.558 [s] 8.786 [s]
> 2nd: 22.458 [s] 8.750 [s]
> 3rd: 22.478 [s] 8.754 [s]
> 4th: 22.724 [s] 8.745 [s]
> 5th: 22.918 [s] 8.748 [s]
> 6th: 22.905 [s] 8.764 [s]
> 7th: 23.238 [s] 8.726 [s]
> 8th: 22.822 [s] 8.729 [s]
>
> NOTE: We used the following operatins as a test case.
> No need to say, it is a corner case to highlight.
> [root@saba ~]# id -Z
> root:system_r:unconfined_t:SystemLow-SystemHigh
> [root@saba ~]# cd /dev/shm
> [root@saba shm]# for I in `seq 1 640`
> > do
> > echo > file${I}
> > chcon -l s0:c${I} file${I}
> > done
> [root@saba shm]# ~kaigai/manyfiles 800 file*
>
> I also attached "manyfiles.c" to reproduce them.
>
> In addition, we could not make sure a statistical difference
> in the AVC-hits case.
>
> Thanks,
The patch looks good overall - a couple minor comments below.
Paul, can you test the netlabel import/export functionality?
I was wondering whether it might be useful to also introduce a new
policy version with an updated ebitmap representation in the policy
format that would be closer to the kernel native representation,
although we'd still need to be able to read the old formats for backward
compatibility.
If/when we introduce support for reading back the currently loaded
policy image from the kernel via a selinuxfs node for use by tools,
we'll need conversion code to map the kernel representation back to the
policy format. libsepol has an ebitmap_write() function to generate a
linear policy format representation from an in-memory policydb, which
could be ported to the kernel (it used to be there too, actually, but
was expunged because we didn't need it in the kernel code at the time),
but naturally it only deals with the current representation.
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ce492a6..de9ef55 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -328,85 +341,84 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
- mapsize = le32_to_cpu(buf[0]);
+ mapunit = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]);
- if (mapsize != MAPSIZE) {
+ /* round up e->highbit */
+ e->highbit += EBITMAP_SIZE - 1;
+ e->highbit -= (e->highbit % EBITMAP_SIZE);
+
+ if (mapunit != sizeof(u64) * 8) {
printk(KERN_ERR "security: ebitmap: map size %u does not "
- "match my size %Zd (high bit was %d)\n", mapsize,
- MAPSIZE, e->highbit);
+ "match my size %Zd (high bit was %d)\n",
+ mapunit, sizeof(u64) * 8, e->highbit);
Here you will display the modified highbit value rather than the one
that was actually in the policy image. I think you can just move the
check before mutating the highbit.
goto bad;
}
if (!e->highbit) {
e->node = NULL;
goto ok;
}
- if (e->highbit & (MAPSIZE - 1)) {
- printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
- "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
- goto bad;
- }
Not sure why you'd drop this sanity check. As before, it would need to happen before mutating the highbit.
<snip>
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
+ struct ebitmap_node *_n = kzalloc(sizeof(*_n), GFP_KERNEL);
+ if (!_n) {
+ printk(KERN_ERR "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ _n->startbit = startbit - (startbit % EBITMAP_SIZE); /* round down */
+ if (n) {
+ n->next = _n;
+ } else {
+ e->node = _n;
+ }
+ n = _n;
+ } else if (startbit <= n->startbit) {
+ printk(KERN_ERR "security: ebitmap: start bit %d"
+ " comes after start bit %d\n",
+ startbit, n->startbit);
Need to bail out here with an appropriate rc value.
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 1270e34..fc0ce05 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -41,6 +42,19 @@ static inline unsigned int ebitmap_start(struct ebitmap *e,
return ebitmap_startbit(e);
}
+static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+ struct ebitmap_node **n)
I suspect we could just make these all "static" (not explicitly inline)
and let the compiler do the right thing. That seemed to be the trend
upstream and guidance from arjan.
<snip>
static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
unsigned int bit)
{
- if (n->map & (MAPBIT << (bit - n->startbit)))
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
Possibly the computation of (ofs,index) should be a common macro since it is done in several of these
functions.
+
+ if (index < EBITMAP_UNIT_NUMS && (n->maps[index] & (EBITMAP_BIT << ofs)))
Possibly BUG_ON(index >= EBITMAP_UNIT_NUMS) instead of silently returning 0 in that case?
return 1;
return 0;
}
-#define ebitmap_for_each_bit(e, n, bit) \
- for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+
+ if (index < EBITMAP_UNIT_NUMS)
Ditto.
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+
+ if (index < EBITMAP_UNIT_NUMS)
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+ for (bit = ebitmap_start(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next(&n, bit)) \
Ideally we'd kill off all uses of ebitmap_for_each_bit and use the _positive_ form in all cases,
although I see that would require some changes to the mls logic.
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for (bit = ebitmap_start_positive(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2..846314f 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -190,17 +190,17 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (i > p->p_cats.nprim)
- return 0;
- if (!ebitmap_get_bit(&levdatum->level->cat, i))
- /*
- * Category may not be associated with
- * sensitivity in low level.
- */
- return 0;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ // BUG_ON(!ebitmap_node_get_bit(node, i));
Drop these BUG_ON's out, or uncomment them if you want to keep them for now for testing purposes.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-09-18 17:21 ` [patch] Tuning avtab to reduce memory usage Stephen Smalley
@ 2007-09-18 22:11 ` Paul Moore
2007-09-20 8:14 ` KaiGai Kohei
1 sibling, 0 replies; 52+ messages in thread
From: Paul Moore @ 2007-09-18 22:11 UTC (permalink / raw)
To: Stephen Smalley
Cc: KaiGai Kohei, selinux, Yuichi Nakamura, James Morris, Eric Paris
On Tuesday, September 18 2007 1:21:06 pm Stephen Smalley wrote:
> The patch looks good overall - a couple minor comments below.
> Paul, can you test the netlabel import/export functionality?
Yep, I just ran it through some simple tests using a patched kernel and the
categories looked okay (i.e. the same at both ends). I also inspected a few
packets by hand and the categories on the wire looked correct as well.
[NOTE: wireshark 0.99.6 appears to have my CIPSO patch in it now so you can
use that to decode CIPSO options]
--
paul moore
linux security @ hp
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-09-18 17:21 ` [patch] Tuning avtab to reduce memory usage Stephen Smalley
2007-09-18 22:11 ` Paul Moore
@ 2007-09-20 8:14 ` KaiGai Kohei
2007-09-21 19:21 ` Stephen Smalley
1 sibling, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-20 8:14 UTC (permalink / raw)
To: Stephen Smalley
Cc: selinux, Paul Moore, Yuichi Nakamura, James Morris, Eric Paris
[-- Attachment #1: Type: text/plain, Size: 9429 bytes --]
Stephen Smalley wrote:
> On Wed, 2007-09-12 at 12:08 +0900, KaiGai Kohei wrote:
>> The attached patch applies the standard bitmap operations
>> for the iteration macro of ebitmap, and enables to improve
>> the performance in AVC-misses case.
>>
>> Real-time responsibility is a significant issue for embedded
>> Linux people. This patch also reduce amount of busy loop in
>> the kernel, so it can improve real-time responsibility.
>>
>> I added ebitmap_for_each_positive_bit() macro not to walk
>> on any native bit within ebitmap, and applies it on
>> - context_struct_compute_av()
>> - security_get_user_sids()
>> - mls_context_isvalid()
>>
>> ebitmap_node was redefined as follows:
>> #define EBITMAP_UNIT_NUMS \
>> ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
>> struct ebitmap_node {
>> struct ebitmap_node *next;
>> unsigned long maps[EBITMAP_UNIT_NUMS];
>> u32 startbit;
>> };
>>
>> "u64 map" is replaced by an array of "unsigned long". It enables to
>> apply standard bit operations. In addition, length of the array is
>> determind to fit 32-bytes, the minimum size of kmalloc().
>>
>> The result of benchmarks seems to me fine.
>>
>> selinux-2.6 selinux-2.6-ebitmap
>> AVG: 22.763 [s] 8.750 [s]
>> STD: 0.265 0.019
>> ------------------------------------------
>> 1st: 22.558 [s] 8.786 [s]
>> 2nd: 22.458 [s] 8.750 [s]
>> 3rd: 22.478 [s] 8.754 [s]
>> 4th: 22.724 [s] 8.745 [s]
>> 5th: 22.918 [s] 8.748 [s]
>> 6th: 22.905 [s] 8.764 [s]
>> 7th: 23.238 [s] 8.726 [s]
>> 8th: 22.822 [s] 8.729 [s]
>>
>> NOTE: We used the following operatins as a test case.
>> No need to say, it is a corner case to highlight.
>> [root@saba ~]# id -Z
>> root:system_r:unconfined_t:SystemLow-SystemHigh
>> [root@saba ~]# cd /dev/shm
>> [root@saba shm]# for I in `seq 1 640`
>> > do
>> > echo > file${I}
>> > chcon -l s0:c${I} file${I}
>> > done
>> [root@saba shm]# ~kaigai/manyfiles 800 file*
>>
>> I also attached "manyfiles.c" to reproduce them.
>>
>> In addition, we could not make sure a statistical difference
>> in the AVC-hits case.
>>
>> Thanks,
Stephen, Thanks for your comments.
The attached second patch is revised in several points.
- comment blocks in ebitmap_netlbl_(inport|export) are rewritten
as I mentioned before.
- rest of codes using ebitmap_for_each_bit() were replaced by
_positive_ version. I had to modify logic in ss/mls.c a bit.
- applied your comment as follows:
> The patch looks good overall - a couple minor comments below.
> Paul, can you test the netlabel import/export functionality?
>
> I was wondering whether it might be useful to also introduce a new
> policy version with an updated ebitmap representation in the policy
> format that would be closer to the kernel native representation,
> although we'd still need to be able to read the old formats for backward
> compatibility.
I don't think a new policy format is necessary, because the width of
unsigned long depends on its architecture, although selinux-policy
is a "noarch" package.
The kernel should translate it into another format easier to handle
on run-time, if necessary.
> If/when we introduce support for reading back the currently loaded
> policy image from the kernel via a selinuxfs node for use by tools,
> we'll need conversion code to map the kernel representation back to the
> policy format. libsepol has an ebitmap_write() function to generate a
> linear policy format representation from an in-memory policydb, which
> could be ported to the kernel (it used to be there too, actually, but
> was expunged because we didn't need it in the kernel code at the time),
> but naturally it only deals with the current representation.
>
> diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
> index ce492a6..de9ef55 100644
> --- a/security/selinux/ss/ebitmap.c
> +++ b/security/selinux/ss/ebitmap.c
> @@ -328,85 +341,84 @@ int ebitmap_read(struct ebitmap *e, void *fp)
> if (rc < 0)
> goto out;
>
> - mapsize = le32_to_cpu(buf[0]);
> + mapunit = le32_to_cpu(buf[0]);
> e->highbit = le32_to_cpu(buf[1]);
> count = le32_to_cpu(buf[2]);
>
> - if (mapsize != MAPSIZE) {
> + /* round up e->highbit */
> + e->highbit += EBITMAP_SIZE - 1;
> + e->highbit -= (e->highbit % EBITMAP_SIZE);
> +
> + if (mapunit != sizeof(u64) * 8) {
> printk(KERN_ERR "security: ebitmap: map size %u does not "
> - "match my size %Zd (high bit was %d)\n", mapsize,
> - MAPSIZE, e->highbit);
> + "match my size %Zd (high bit was %d)\n",
> + mapunit, sizeof(u64) * 8, e->highbit);
>
> Here you will display the modified highbit value rather than the one
> that was actually in the policy image. I think you can just move the
> check before mutating the highbit.
I moved it in front of rounding up e->highbit.
> goto bad;
> }
> if (!e->highbit) {
> e->node = NULL;
> goto ok;
> }
> - if (e->highbit & (MAPSIZE - 1)) {
> - printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
> - "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
> - goto bad;
> - }
>
> Not sure why you'd drop this sanity check. As before, it would need to happen before mutating the highbit.
The reason why I dropped this sanity check is to avoid redundant one,
because e->highbit is already rounded up to the align of EBITMAP_SIZE.
The above condition is not always false.
> + } else if (startbit <= n->startbit) {
> + printk(KERN_ERR "security: ebitmap: start bit %d"
> + " comes after start bit %d\n",
> + startbit, n->startbit);
>
> Need to bail out here with an appropriate rc value.
I added "goto bad;" at the point. It returns -EINVAL.
> diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
> index 1270e34..fc0ce05 100644
> --- a/security/selinux/ss/ebitmap.h
> +++ b/security/selinux/ss/ebitmap.h
> @@ -41,6 +42,19 @@ static inline unsigned int ebitmap_start(struct ebitmap *e,
> return ebitmap_startbit(e);
> }
>
> +static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
> + struct ebitmap_node **n)
>
> I suspect we could just make these all "static" (not explicitly inline)
> and let the compiler do the right thing. That seemed to be the trend
> upstream and guidance from arjan.
How should we do the explicitly inlined static functions used as stubs?
For example, ebitmap_netlbl_export() when NetLabel is not enabled is
defined as explicitly inlined function which always returns -ENOMEM,
however, these are also declarations of function when NetLabel is enabled.
> <snip>
> static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
> unsigned int bit)
> {
> - if (n->map & (MAPBIT << (bit - n->startbit)))
> + unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
> + unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
>
> Possibly the computation of (ofs,index) should be a common macro since it is done in several of these
> functions.
I added EBITMAP_NODE_INDEX(node,bit) and EBITMAP_NODE_OFFSET(node,bit) to compute them.
> +
> + if (index < EBITMAP_UNIT_NUMS && (n->maps[index] & (EBITMAP_BIT << ofs)))
>
> Possibly BUG_ON(index >= EBITMAP_UNIT_NUMS) instead of silently returning 0 in that case?
It is good idea indeed.
All caller of ebitmap_node_get_bit() always confirms 'bit' is in the range of
ebitmap_node. If the index overs EBITMAP_UNIT_NUMS, it is a bug surely.
> +#define ebitmap_for_each_bit(e, n, bit) \
> + for (bit = ebitmap_start(e, &n); \
> + bit < ebitmap_length(e); \
> + bit = ebitmap_next(&n, bit)) \
>
> Ideally we'd kill off all uses of ebitmap_for_each_bit and use the _positive_ form in all cases,
> although I see that would require some changes to the mls logic.
ebitmap_start, ebitmap_next and ebitmap_for_each_bit are dropped.
The rest of codes using ebitmap_for_each_bit(), in ss/mls.c, are
also replaced with _positive_ version.
> +#define ebitmap_for_each_positive_bit(e, n, bit) \
> + for (bit = ebitmap_start_positive(e, &n); \
> + bit < ebitmap_length(e); \
> + bit = ebitmap_next_positive(e, &n, bit)) \
>
> int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
> int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
> diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
> index 4a8bab2..846314f 100644
> --- a/security/selinux/ss/mls.c
> +++ b/security/selinux/ss/mls.c
> @@ -190,17 +190,17 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
> if (!levdatum)
> return 0;
>
> - ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (i > p->p_cats.nprim)
> - return 0;
> - if (!ebitmap_get_bit(&levdatum->level->cat, i))
> - /*
> - * Category may not be associated with
> - * sensitivity in low level.
> - */
> - return 0;
> - }
> + ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
> + // BUG_ON(!ebitmap_node_get_bit(node, i));
>
> Drop these BUG_ON's out, or uncomment them if you want to keep them for now for testing purposes.
I dropped the BUG_ON() to confirm each bit is actually positive.
Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
[-- Attachment #2: ebitmap-bitops.2.patch --]
[-- Type: text/x-patch, Size: 23414 bytes --]
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ce492a6..f03a347 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/
+/*
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Applied standard bit operations to improve bitmap scanning.
+ */
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
n2 = e2->node;
while (n1 && n2 &&
(n1->startbit == n2->startbit) &&
- (n1->map == n2->map)) {
+ !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
n1 = n1->next;
n2 = n2->next;
}
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
return -ENOMEM;
}
new->startbit = n->startbit;
- new->map = n->map;
+ memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
new->next = NULL;
if (prev)
prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
{
struct ebitmap_node *e_iter = ebmap->node;
struct netlbl_lsm_secattr_catmap *c_iter;
- u32 cmap_idx;
+ u32 cmap_idx, cmap_sft;
+ int i;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
if (e_iter == NULL) {
*catmap = NULL;
@@ -104,19 +110,20 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) {
- if (e_iter->startbit >=
- (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
- c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
- if (c_iter->next == NULL)
- goto netlbl_export_failure;
- c_iter = c_iter->next;
- c_iter->startbit = e_iter->startbit &
- ~(NETLBL_CATMAP_SIZE - 1);
+ for (i=0; i < EBITMAP_UNIT_NUMS; i++) {
+ unsigned int e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
+ if (e_startbit >= c_iter->startbit + NETLBL_CATMAP_SIZE) {
+ c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (c_iter->next == NULL)
+ goto netlbl_export_failure;
+ c_iter = c_iter->next;
+ c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
+ cmap_idx = (e_startbit - c_iter->startbit) / NETLBL_CATMAP_MAPSIZE;
+ cmap_sft = (e_startbit - c_iter->startbit) % NETLBL_CATMAP_MAPSIZE;
+ c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft;
+ e_iter = e_iter->next;
}
- cmap_idx = (e_iter->startbit - c_iter->startbit) /
- NETLBL_CATMAP_MAPSIZE;
- c_iter->bitmap[cmap_idx] = e_iter->map;
- e_iter = e_iter->next;
}
return 0;
@@ -128,7 +135,7 @@ netlbl_export_failure:
/**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
- * @ebmap: the ebitmap to export
+ * @ebmap: the ebitmap to import
* @catmap: the NetLabel category bitmap
*
* Description:
@@ -142,36 +149,45 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap;
- u32 c_idx;
+ u32 c_idx, c_pos, e_idx, e_sft;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
- if (c_iter->bitmap[c_idx] == 0)
+ u64 map = c_iter->bitmap[c_idx];
+
+ if (!map)
continue;
- e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
- if (e_iter == NULL)
- goto netlbl_import_failure;
- if (emap_prev == NULL)
- ebmap->node = e_iter;
- else
- emap_prev->next = e_iter;
- emap_prev = e_iter;
-
- e_iter->startbit = c_iter->startbit +
- NETLBL_CATMAP_MAPSIZE * c_idx;
- e_iter->map = c_iter->bitmap[c_idx];
+ c_pos = c_iter->startbit + c_idx * NETLBL_CATMAP_MAPSIZE;
+ if (!e_iter || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
+ e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+ if (!e_iter)
+ goto netlbl_import_failure;
+ e_iter->startbit = c_pos - (c_pos % EBITMAP_SIZE);
+ if (emap_prev == NULL)
+ ebmap->node = e_iter;
+ else
+ emap_prev->next = e_iter;
+ emap_prev = e_iter;
+ }
+ e_idx = (c_pos - e_iter->startbit) / EBITMAP_UNIT_SIZE;
+ e_sft = (c_pos - e_iter->startbit) % EBITMAP_UNIT_SIZE;
+ while (map) {
+ e_iter->maps[e_idx++] |= map & (-1UL);
+ map >>= EBITMAP_UNIT_SIZE;
+ }
}
c_iter = c_iter->next;
} while (c_iter != NULL);
if (e_iter != NULL)
- ebmap->highbit = e_iter->startbit + MAPSIZE;
+ ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
else
ebitmap_destroy(ebmap);
@@ -186,6 +202,7 @@ netlbl_import_failure:
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
+ int i;
if (e1->highbit < e2->highbit)
return 0;
@@ -197,8 +214,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next;
continue;
}
- if ((n1->map & n2->map) != n2->map)
- return 0;
+ for (i=0; i < EBITMAP_UNIT_NUMS; i++) {
+ if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
+ return 0;
+ }
n1 = n1->next;
n2 = n2->next;
@@ -219,12 +238,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node;
while (n && (n->startbit <= bit)) {
- if ((n->startbit + MAPSIZE) > bit) {
- if (n->map & (MAPBIT << (bit - n->startbit)))
- return 1;
- else
- return 0;
- }
+ if ((n->startbit + EBITMAP_SIZE) > bit)
+ return ebitmap_node_get_bit(n, bit);
n = n->next;
}
@@ -238,31 +253,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
- if ((n->startbit + MAPSIZE) > bit) {
+ if ((n->startbit + EBITMAP_SIZE) > bit) {
if (value) {
- n->map |= (MAPBIT << (bit - n->startbit));
+ ebitmap_node_set_bit(n, bit);
} else {
- n->map &= ~(MAPBIT << (bit - n->startbit));
- if (!n->map) {
- /* drop this node from the bitmap */
-
- if (!n->next) {
- /*
- * this was the highest map
- * within the bitmap
- */
- if (prev)
- e->highbit = prev->startbit + MAPSIZE;
- else
- e->highbit = 0;
- }
+ ebitmap_node_clr_bit(n, bit);
+
+ if (find_first_bit(n->maps, EBITMAP_SIZE) < EBITMAP_SIZE)
+ return 0;
+
+ /* drop this node from the bitmap */
+ if (!n->next) {
+ /*
+ * this was the highest map
+ * within the bitmap
+ */
if (prev)
- prev->next = n->next;
+ e->highbit = prev->startbit + EBITMAP_SIZE;
else
- e->node = n->next;
-
- kfree(n);
+ e->highbit = 0;
}
+ if (prev)
+ prev->next = n->next;
+ else
+ e->node = n->next;
+ kfree(n);
}
return 0;
}
@@ -277,12 +292,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new)
return -ENOMEM;
- new->startbit = bit & ~(MAPSIZE - 1);
- new->map = (MAPBIT << (bit - new->startbit));
+ new->startbit = bit - (bit % EBITMAP_SIZE);
+ ebitmap_node_set_bit(new, bit);
if (!n)
/* this node will be the highest map within the bitmap */
- e->highbit = new->startbit + MAPSIZE;
+ e->highbit = new->startbit + EBITMAP_SIZE;
if (prev) {
new->next = prev->next;
@@ -316,11 +331,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
- int rc;
- struct ebitmap_node *n, *l;
+ struct ebitmap_node *n = NULL;
+ u32 mapunit, count, startbit, index;
+ u64 map;
__le32 buf[3];
- u32 mapsize, count, i;
- __le64 map;
+ int rc, i;
ebitmap_init(e);
@@ -328,85 +343,86 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
- mapsize = le32_to_cpu(buf[0]);
+ mapunit = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]);
- if (mapsize != MAPSIZE) {
+ if (mapunit != sizeof(u64) * 8) {
printk(KERN_ERR "security: ebitmap: map size %u does not "
- "match my size %Zd (high bit was %d)\n", mapsize,
- MAPSIZE, e->highbit);
+ "match my size %Zd (high bit was %d)\n",
+ mapunit, sizeof(u64) * 8, e->highbit);
goto bad;
}
+
+ /* round up e->highbit */
+ e->highbit += EBITMAP_SIZE - 1;
+ e->highbit -= (e->highbit % EBITMAP_SIZE);
+
if (!e->highbit) {
e->node = NULL;
goto ok;
}
- if (e->highbit & (MAPSIZE - 1)) {
- printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
- "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
- goto bad;
- }
- l = NULL;
+
for (i = 0; i < count; i++) {
- rc = next_entry(buf, fp, sizeof(u32));
+ rc = next_entry(&startbit, fp, sizeof(u32));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad;
}
- n = kzalloc(sizeof(*n), GFP_KERNEL);
- if (!n) {
- printk(KERN_ERR "security: ebitmap: out of memory\n");
- rc = -ENOMEM;
- goto bad;
- }
-
- n->startbit = le32_to_cpu(buf[0]);
+ startbit = le32_to_cpu(startbit);
- if (n->startbit & (MAPSIZE - 1)) {
+ if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map size (%Zd)\n",
- n->startbit, MAPSIZE);
- goto bad_free;
+ "not a multiple of the map unit size (%Zd)\n",
+ startbit, mapunit);
+ goto bad;
}
- if (n->startbit > (e->highbit - MAPSIZE)) {
+ if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%Zd)\n",
- n->startbit, (e->highbit - MAPSIZE));
- goto bad_free;
+ startbit, (e->highbit - mapunit));
+ goto bad;
+ }
+
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
+ struct ebitmap_node *_n = kzalloc(sizeof(*_n), GFP_KERNEL);
+ if (!_n) {
+ printk(KERN_ERR "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ _n->startbit = startbit - (startbit % EBITMAP_SIZE); /* round down */
+ if (n) {
+ n->next = _n;
+ } else {
+ e->node = _n;
+ }
+ n = _n;
+ } else if (startbit <= n->startbit) {
+ printk(KERN_ERR "security: ebitmap: start bit %d"
+ " comes after start bit %d\n",
+ startbit, n->startbit);
+ goto bad;
}
+
rc = next_entry(&map, fp, sizeof(u64));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
- goto bad_free;
+ goto bad;
}
- n->map = le64_to_cpu(map);
+ map = le64_to_cpu(map);
- if (!n->map) {
- printk(KERN_ERR "security: ebitmap: null map in "
- "ebitmap (startbit %d)\n", n->startbit);
- goto bad_free;
+ index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
+ while (map) {
+ n->maps[index] = map & (-1UL);
+ map = map >> EBITMAP_UNIT_SIZE;
+ index++;
}
- if (l) {
- if (n->startbit <= l->startbit) {
- printk(KERN_ERR "security: ebitmap: start "
- "bit %d comes after start bit %d\n",
- n->startbit, l->startbit);
- goto bad_free;
- }
- l->next = n;
- } else
- e->node = n;
-
- l = n;
}
-
ok:
rc = 0;
out:
return rc;
-bad_free:
- kfree(n);
bad:
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 1270e34..a07e8d9 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -16,14 +16,15 @@
#include <net/netlabel.h>
-#define MAPTYPE u64 /* portion of bitmap in each node */
-#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
-#define MAPBIT 1ULL /* a bit in the node bitmap */
+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1ULL
struct ebitmap_node {
- u32 startbit; /* starting position in the total bitmap */
- MAPTYPE map; /* this node's portion of the bitmap */
struct ebitmap_node *next;
+ unsigned long maps[EBITMAP_UNIT_NUMS];
+ u32 startbit;
};
struct ebitmap {
@@ -34,11 +35,17 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
-static inline unsigned int ebitmap_start(struct ebitmap *e,
- struct ebitmap_node **n)
+static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+ struct ebitmap_node **n)
{
- *n = e->node;
- return ebitmap_startbit(e);
+ unsigned int ofs;
+
+ for (*n = e->node; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return (*n)->startbit + ofs;
+ }
+ return ebitmap_length(e);
}
static inline void ebitmap_init(struct ebitmap *e)
@@ -46,28 +53,68 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
-static inline unsigned int ebitmap_next(struct ebitmap_node **n,
- unsigned int bit)
+static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
+ struct ebitmap_node **n,
+ unsigned int bit)
{
- if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
- (*n)->next) {
- *n = (*n)->next;
- return (*n)->startbit;
- }
+ unsigned int ofs;
+
+ ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
- return (bit+1);
+ for (*n = (*n)->next; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+ }
+ return ebitmap_length(e);
}
+#define EBITMAP_NODE_INDEX(node, bit) (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
+#define EBITMAP_NODE_OFFSET(node, bit) (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
+
static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
unsigned int bit)
{
- if (n->map & (MAPBIT << (bit - n->startbit)))
+ unsigned int index = EBITMAP_NODE_INDEX(n,bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n,bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ if ((n->maps[index] & (EBITMAP_BIT << ofs)))
return 1;
return 0;
}
-#define ebitmap_for_each_bit(e, n, bit) \
- for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n,bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n,bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n,bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n,bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+ for (bit = ebitmap_start(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next(&n, bit)) \
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for (bit = ebitmap_start_positive(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2..98f4c12 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -34,7 +34,7 @@
*/
int mls_compute_context_len(struct context * context)
{
- int i, l, len, range;
+ int i, l, len, head, prev;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -42,31 +42,25 @@ int mls_compute_context_len(struct context * context)
len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) {
- range = 0;
len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
-
+ /* categories */
+ head = prev = -2;
+ ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped, at least. */
+ if (head != prev)
+ len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
len += strlen(policydb.p_cat_val_to_name[i]) + 1;
- range++;
- } else {
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
- range = 0;
+ head = i;
}
+ prev = i;
}
- /* Handle case where last category is the end of range */
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
-
+ if (prev != head)
+ len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
- &context->range.level[1]))
+ &context->range.level[1]))
break;
else
len++;
@@ -85,7 +79,7 @@ void mls_sid_to_context(struct context *context,
char **scontext)
{
char *scontextp;
- int i, l, range, wrote_sep;
+ int i, l, head, prev;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -97,61 +91,49 @@ void mls_sid_to_context(struct context *context,
scontextp++;
for (l = 0; l < 2; l++) {
- range = 0;
- wrote_sep = 0;
strcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
- scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+ scontextp += strlen(scontextp);
/* categories */
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
-
- if (!wrote_sep) {
- *scontextp++ = ':';
- wrote_sep = 1;
- } else
- *scontextp++ = ',';
- strcpy(scontextp, policydb.p_cat_val_to_name[i]);
- scontextp += strlen(policydb.p_cat_val_to_name[i]);
- range++;
- } else {
- if (range > 1) {
- if (range > 2)
+ head = prev = -2;
+ ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped, at least. */
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
+ scontextp += strlen(scontextp);
}
- range = 0;
+ if (prev < 0)
+ *scontextp++ = ':';
+ else
+ *scontextp++ = ',';
+ strcpy(scontextp, policydb.p_cat_val_to_name[i]);
+ scontextp += strlen(scontextp);
+ head = i;
}
+ prev = i;
}
- /* Handle case where last category is the end of range */
- if (range > 1) {
- if (range > 2)
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
+ scontextp += strlen(scontextp);
}
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
&context->range.level[1]))
break;
- else {
- *scontextp = '-';
- scontextp++;
- }
+ else
+ *scontextp++ = '-';
}
}
@@ -190,17 +172,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (i > p->p_cats.nprim)
- return 0;
- if (!ebitmap_get_bit(&levdatum->level->cat, i))
- /*
- * Category may not be associated with
- * sensitivity in low level.
- */
- return 0;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
+ /*
+ * Category may not be associated with
+ * sensitivity in low level.
+ */
+ return 0;
}
}
@@ -485,18 +465,16 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- int rc;
-
- catdatum = hashtab_search(newp->p_cats.table,
- oldp->p_cat_val_to_name[i]);
- if (!catdatum)
- return -EINVAL;
- rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
- if (rc)
- return rc;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ int rc;
+
+ catdatum = hashtab_search(newp->p_cats.table,
+ oldp->p_cat_val_to_name[i]);
+ if (!catdatum)
+ return -EINVAL;
+ rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
+ if (rc)
+ return rc;
}
ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 6100fc0..19be935 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext,
avkey.specified = AVTAB_AV;
sattr = &policydb.type_attr_map[scontext->type - 1];
tattr = &policydb.type_attr_map[tcontext->type - 1];
- ebitmap_for_each_bit(sattr, snode, i) {
- if (!ebitmap_node_get_bit(snode, i))
- continue;
- ebitmap_for_each_bit(tattr, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(sattr, snode, i) {
+ ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1;
avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid,
goto out_unlock;
}
- ebitmap_for_each_bit(&user->roles, rnode, i) {
- if (!ebitmap_node_get_bit(rnode, i))
- continue;
+ ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
role = policydb.role_val_to_struct[i];
usercon.role = i+1;
- ebitmap_for_each_bit(&role->types, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(&role->types, tnode, j) {
usercon.type = j+1;
if (mls_setup_user_range(fromcon, user, &usercon))
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-09-20 8:14 ` KaiGai Kohei
@ 2007-09-21 19:21 ` Stephen Smalley
2007-09-25 5:06 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: Stephen Smalley @ 2007-09-21 19:21 UTC (permalink / raw)
To: KaiGai Kohei
Cc: selinux, Paul Moore, Yuichi Nakamura, James Morris, Eric Paris
On Thu, 2007-09-20 at 17:14 +0900, KaiGai Kohei wrote:
> Stephen Smalley wrote:
> > On Wed, 2007-09-12 at 12:08 +0900, KaiGai Kohei wrote:
> >> The attached patch applies the standard bitmap operations
> >> for the iteration macro of ebitmap, and enables to improve
> >> the performance in AVC-misses case.
> >>
> >> Real-time responsibility is a significant issue for embedded
> >> Linux people. This patch also reduce amount of busy loop in
> >> the kernel, so it can improve real-time responsibility.
> >>
> >> I added ebitmap_for_each_positive_bit() macro not to walk
> >> on any native bit within ebitmap, and applies it on
> >> - context_struct_compute_av()
> >> - security_get_user_sids()
> >> - mls_context_isvalid()
> >>
> >> ebitmap_node was redefined as follows:
> >> #define EBITMAP_UNIT_NUMS \
> >> ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
> >> struct ebitmap_node {
> >> struct ebitmap_node *next;
> >> unsigned long maps[EBITMAP_UNIT_NUMS];
> >> u32 startbit;
> >> };
> >>
> >> "u64 map" is replaced by an array of "unsigned long". It enables to
> >> apply standard bit operations. In addition, length of the array is
> >> determind to fit 32-bytes, the minimum size of kmalloc().
> >>
> >> The result of benchmarks seems to me fine.
> >>
> >> selinux-2.6 selinux-2.6-ebitmap
> >> AVG: 22.763 [s] 8.750 [s]
> >> STD: 0.265 0.019
> >> ------------------------------------------
> >> 1st: 22.558 [s] 8.786 [s]
> >> 2nd: 22.458 [s] 8.750 [s]
> >> 3rd: 22.478 [s] 8.754 [s]
> >> 4th: 22.724 [s] 8.745 [s]
> >> 5th: 22.918 [s] 8.748 [s]
> >> 6th: 22.905 [s] 8.764 [s]
> >> 7th: 23.238 [s] 8.726 [s]
> >> 8th: 22.822 [s] 8.729 [s]
> >>
> >> NOTE: We used the following operatins as a test case.
> >> No need to say, it is a corner case to highlight.
> >> [root@saba ~]# id -Z
> >> root:system_r:unconfined_t:SystemLow-SystemHigh
> >> [root@saba ~]# cd /dev/shm
> >> [root@saba shm]# for I in `seq 1 640`
> >> > do
> >> > echo > file${I}
> >> > chcon -l s0:c${I} file${I}
> >> > done
> >> [root@saba shm]# ~kaigai/manyfiles 800 file*
> >>
> >> I also attached "manyfiles.c" to reproduce them.
> >>
> >> In addition, we could not make sure a statistical difference
> >> in the AVC-hits case.
> >>
> >> Thanks,
>
> Stephen, Thanks for your comments.
>
> The attached second patch is revised in several points.
> - comment blocks in ebitmap_netlbl_(inport|export) are rewritten
> as I mentioned before.
> - rest of codes using ebitmap_for_each_bit() were replaced by
> _positive_ version. I had to modify logic in ss/mls.c a bit.
> - applied your comment as follows:
>
> > The patch looks good overall - a couple minor comments below.
> > Paul, can you test the netlabel import/export functionality?
> >
> > I was wondering whether it might be useful to also introduce a new
> > policy version with an updated ebitmap representation in the policy
> > format that would be closer to the kernel native representation,
> > although we'd still need to be able to read the old formats for backward
> > compatibility.
>
> I don't think a new policy format is necessary, because the width of
> unsigned long depends on its architecture, although selinux-policy
> is a "noarch" package.
> The kernel should translate it into another format easier to handle
> on run-time, if necessary.
>
> > If/when we introduce support for reading back the currently loaded
> > policy image from the kernel via a selinuxfs node for use by tools,
> > we'll need conversion code to map the kernel representation back to the
> > policy format. libsepol has an ebitmap_write() function to generate a
> > linear policy format representation from an in-memory policydb, which
> > could be ported to the kernel (it used to be there too, actually, but
> > was expunged because we didn't need it in the kernel code at the time),
> > but naturally it only deals with the current representation.
> >
> > diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
> > index ce492a6..de9ef55 100644
> > --- a/security/selinux/ss/ebitmap.c
> > +++ b/security/selinux/ss/ebitmap.c
> > @@ -328,85 +341,84 @@ int ebitmap_read(struct ebitmap *e, void *fp)
> > if (rc < 0)
> > goto out;
> >
> > - mapsize = le32_to_cpu(buf[0]);
> > + mapunit = le32_to_cpu(buf[0]);
> > e->highbit = le32_to_cpu(buf[1]);
> > count = le32_to_cpu(buf[2]);
> >
> > - if (mapsize != MAPSIZE) {
> > + /* round up e->highbit */
> > + e->highbit += EBITMAP_SIZE - 1;
> > + e->highbit -= (e->highbit % EBITMAP_SIZE);
> > +
> > + if (mapunit != sizeof(u64) * 8) {
> > printk(KERN_ERR "security: ebitmap: map size %u does not "
> > - "match my size %Zd (high bit was %d)\n", mapsize,
> > - MAPSIZE, e->highbit);
> > + "match my size %Zd (high bit was %d)\n",
> > + mapunit, sizeof(u64) * 8, e->highbit);
> >
> > Here you will display the modified highbit value rather than the one
> > that was actually in the policy image. I think you can just move the
> > check before mutating the highbit.
>
> I moved it in front of rounding up e->highbit.
>
> > goto bad;
> > }
> > if (!e->highbit) {
> > e->node = NULL;
> > goto ok;
> > }
> > - if (e->highbit & (MAPSIZE - 1)) {
> > - printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
> > - "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
> > - goto bad;
> > - }
> >
> > Not sure why you'd drop this sanity check. As before, it would need to happen before mutating the highbit.
>
> The reason why I dropped this sanity check is to avoid redundant one,
> because e->highbit is already rounded up to the align of EBITMAP_SIZE.
> The above condition is not always false.
>
> > + } else if (startbit <= n->startbit) {
> > + printk(KERN_ERR "security: ebitmap: start bit %d"
> > + " comes after start bit %d\n",
> > + startbit, n->startbit);
> >
> > Need to bail out here with an appropriate rc value.
>
> I added "goto bad;" at the point. It returns -EINVAL.
>
> > diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
> > index 1270e34..fc0ce05 100644
> > --- a/security/selinux/ss/ebitmap.h
> > +++ b/security/selinux/ss/ebitmap.h
> > @@ -41,6 +42,19 @@ static inline unsigned int ebitmap_start(struct ebitmap *e,
> > return ebitmap_startbit(e);
> > }
> >
> > +static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
> > + struct ebitmap_node **n)
> >
> > I suspect we could just make these all "static" (not explicitly inline)
> > and let the compiler do the right thing. That seemed to be the trend
> > upstream and guidance from arjan.
>
> How should we do the explicitly inlined static functions used as stubs?
>
> For example, ebitmap_netlbl_export() when NetLabel is not enabled is
> defined as explicitly inlined function which always returns -ENOMEM,
> however, these are also declarations of function when NetLabel is enabled.
Ah, never mind - as these are defined in the header file, they can stay
static inline.
> > <snip>
> > static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
> > unsigned int bit)
> > {
> > - if (n->map & (MAPBIT << (bit - n->startbit)))
> > + unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
> > + unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
> >
> > Possibly the computation of (ofs,index) should be a common macro since it is done in several of these
> > functions.
>
> I added EBITMAP_NODE_INDEX(node,bit) and EBITMAP_NODE_OFFSET(node,bit) to compute them.
>
> > +
> > + if (index < EBITMAP_UNIT_NUMS && (n->maps[index] & (EBITMAP_BIT << ofs)))
> >
> > Possibly BUG_ON(index >= EBITMAP_UNIT_NUMS) instead of silently returning 0 in that case?
>
> It is good idea indeed.
> All caller of ebitmap_node_get_bit() always confirms 'bit' is in the range of
> ebitmap_node. If the index overs EBITMAP_UNIT_NUMS, it is a bug surely.
>
> > +#define ebitmap_for_each_bit(e, n, bit) \
> > + for (bit = ebitmap_start(e, &n); \
> > + bit < ebitmap_length(e); \
> > + bit = ebitmap_next(&n, bit)) \
> >
> > Ideally we'd kill off all uses of ebitmap_for_each_bit and use the _positive_ form in all cases,
> > although I see that would require some changes to the mls logic.
>
> ebitmap_start, ebitmap_next and ebitmap_for_each_bit are dropped.
> The rest of codes using ebitmap_for_each_bit(), in ss/mls.c, are
> also replaced with _positive_ version.
Looks like you've left ebitmap_for_each_bit defined even though no
longer used in ebitmap.h.
> > +#define ebitmap_for_each_positive_bit(e, n, bit) \
> > + for (bit = ebitmap_start_positive(e, &n); \
> > + bit < ebitmap_length(e); \
> > + bit = ebitmap_next_positive(e, &n, bit)) \
> >
> > int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
> > int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
> > diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
> > index 4a8bab2..846314f 100644
> > --- a/security/selinux/ss/mls.c
> > +++ b/security/selinux/ss/mls.c
> > @@ -190,17 +190,17 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
> > if (!levdatum)
> > return 0;
> >
> > - ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
> > - if (ebitmap_node_get_bit(node, i)) {
> > - if (i > p->p_cats.nprim)
> > - return 0;
> > - if (!ebitmap_get_bit(&levdatum->level->cat, i))
> > - /*
> > - * Category may not be associated with
> > - * sensitivity in low level.
> > - */
> > - return 0;
> > - }
> > + ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
> > + // BUG_ON(!ebitmap_node_get_bit(node, i));
> >
> > Drop these BUG_ON's out, or uncomment them if you want to keep them for now for testing purposes.
>
> I dropped the BUG_ON() to confirm each bit is actually positive.
Ok, looks reasonable. Please run it through ./scripts/checkpatch.pl and
fix up the minor issues it reports, then post a clean message with a
suitable description and the patch inline.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-09-21 19:21 ` Stephen Smalley
@ 2007-09-25 5:06 ` KaiGai Kohei
2007-09-25 12:04 ` Paul Moore
2007-09-25 13:53 ` Stephen Smalley
0 siblings, 2 replies; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-25 5:06 UTC (permalink / raw)
To: Stephen Smalley
Cc: selinux, Paul Moore, Yuichi Nakamura, James Morris, Eric Paris
- snip -
>>> +static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
>>> + struct ebitmap_node **n)
>>>
>>> I suspect we could just make these all "static" (not explicitly inline)
>>> and let the compiler do the right thing. That seemed to be the trend
>>> upstream and guidance from arjan.
>> How should we do the explicitly inlined static functions used as stubs?
>>
>> For example, ebitmap_netlbl_export() when NetLabel is not enabled is
>> defined as explicitly inlined function which always returns -ENOMEM,
>> however, these are also declarations of function when NetLabel is enabled.
>
> Ah, never mind - as these are defined in the header file, they can stay
> static inline.
OK. I'll submit a patch to clean up non-stub static inline functions
next to this patch.
- snip -
>>> +#define ebitmap_for_each_bit(e, n, bit) \
>>> + for (bit = ebitmap_start(e, &n); \
>>> + bit < ebitmap_length(e); \
>>> + bit = ebitmap_next(&n, bit)) \
>>>
>>> Ideally we'd kill off all uses of ebitmap_for_each_bit and use the _positive_ form in all cases,
>>> although I see that would require some changes to the mls logic.
>> ebitmap_start, ebitmap_next and ebitmap_for_each_bit are dropped.
>> The rest of codes using ebitmap_for_each_bit(), in ss/mls.c, are
>> also replaced with _positive_ version.
>
> Looks like you've left ebitmap_for_each_bit defined even though no
> longer used in ebitmap.h.
I misses to remove it, so its definition is also removed.
- snip -
> Ok, looks reasonable. Please run it through ./scripts/checkpatch.pl and
> fix up the minor issues it reports, then post a clean message with a
> suitable description and the patch inline.
What is your stance about warnings for "line over 80 characters" ?
To resolve all of them makes harder to read source code, so I'm ignoring
them in the attached version.
Rest of warnings except for them are removed.
Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ce492a6..3a60186 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/
+/*
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Applied standard bit operations to improve bitmap scanning.
+ */
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
n2 = e2->node;
while (n1 && n2 &&
(n1->startbit == n2->startbit) &&
- (n1->map == n2->map)) {
+ !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
n1 = n1->next;
n2 = n2->next;
}
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
return -ENOMEM;
}
new->startbit = n->startbit;
- new->map = n->map;
+ memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
new->next = NULL;
if (prev)
prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
{
struct ebitmap_node *e_iter = ebmap->node;
struct netlbl_lsm_secattr_catmap *c_iter;
- u32 cmap_idx;
+ u32 cmap_idx, cmap_sft;
+ int i;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
if (e_iter == NULL) {
*catmap = NULL;
@@ -104,19 +110,21 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) {
- if (e_iter->startbit >=
- (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
- c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
- if (c_iter->next == NULL)
- goto netlbl_export_failure;
- c_iter = c_iter->next;
- c_iter->startbit = e_iter->startbit &
- ~(NETLBL_CATMAP_SIZE - 1);
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+ unsigned int e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
+
+ if (e_startbit >= c_iter->startbit + NETLBL_CATMAP_SIZE) {
+ c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (c_iter->next == NULL)
+ goto netlbl_export_failure;
+ c_iter = c_iter->next;
+ c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
+ cmap_idx = (e_startbit - c_iter->startbit) / NETLBL_CATMAP_MAPSIZE;
+ cmap_sft = (e_startbit - c_iter->startbit) % NETLBL_CATMAP_MAPSIZE;
+ c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft;
+ e_iter = e_iter->next;
}
- cmap_idx = (e_iter->startbit - c_iter->startbit) /
- NETLBL_CATMAP_MAPSIZE;
- c_iter->bitmap[cmap_idx] = e_iter->map;
- e_iter = e_iter->next;
}
return 0;
@@ -128,7 +136,7 @@ netlbl_export_failure:
/**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
- * @ebmap: the ebitmap to export
+ * @ebmap: the ebitmap to import
* @catmap: the NetLabel category bitmap
*
* Description:
@@ -142,36 +150,45 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap;
- u32 c_idx;
+ u32 c_idx, c_pos, e_idx, e_sft;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
- if (c_iter->bitmap[c_idx] == 0)
+ u64 map = c_iter->bitmap[c_idx];
+
+ if (!map)
continue;
- e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
- if (e_iter == NULL)
- goto netlbl_import_failure;
- if (emap_prev == NULL)
- ebmap->node = e_iter;
- else
- emap_prev->next = e_iter;
- emap_prev = e_iter;
-
- e_iter->startbit = c_iter->startbit +
- NETLBL_CATMAP_MAPSIZE * c_idx;
- e_iter->map = c_iter->bitmap[c_idx];
+ c_pos = c_iter->startbit + c_idx * NETLBL_CATMAP_MAPSIZE;
+ if (!e_iter || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
+ e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+ if (!e_iter)
+ goto netlbl_import_failure;
+ e_iter->startbit = c_pos - (c_pos % EBITMAP_SIZE);
+ if (emap_prev == NULL)
+ ebmap->node = e_iter;
+ else
+ emap_prev->next = e_iter;
+ emap_prev = e_iter;
+ }
+ e_idx = (c_pos - e_iter->startbit) / EBITMAP_UNIT_SIZE;
+ e_sft = (c_pos - e_iter->startbit) % EBITMAP_UNIT_SIZE;
+ while (map) {
+ e_iter->maps[e_idx++] |= map & (-1UL);
+ map >>= EBITMAP_UNIT_SIZE;
+ }
}
c_iter = c_iter->next;
} while (c_iter != NULL);
if (e_iter != NULL)
- ebmap->highbit = e_iter->startbit + MAPSIZE;
+ ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
else
ebitmap_destroy(ebmap);
@@ -186,6 +203,7 @@ netlbl_import_failure:
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
+ int i;
if (e1->highbit < e2->highbit)
return 0;
@@ -197,8 +215,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next;
continue;
}
- if ((n1->map & n2->map) != n2->map)
- return 0;
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+ if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
+ return 0;
+ }
n1 = n1->next;
n2 = n2->next;
@@ -219,12 +239,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node;
while (n && (n->startbit <= bit)) {
- if ((n->startbit + MAPSIZE) > bit) {
- if (n->map & (MAPBIT << (bit - n->startbit)))
- return 1;
- else
- return 0;
- }
+ if ((n->startbit + EBITMAP_SIZE) > bit)
+ return ebitmap_node_get_bit(n, bit);
n = n->next;
}
@@ -238,31 +254,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
- if ((n->startbit + MAPSIZE) > bit) {
+ if ((n->startbit + EBITMAP_SIZE) > bit) {
if (value) {
- n->map |= (MAPBIT << (bit - n->startbit));
+ ebitmap_node_set_bit(n, bit);
} else {
- n->map &= ~(MAPBIT << (bit - n->startbit));
- if (!n->map) {
- /* drop this node from the bitmap */
-
- if (!n->next) {
- /*
- * this was the highest map
- * within the bitmap
- */
- if (prev)
- e->highbit = prev->startbit + MAPSIZE;
- else
- e->highbit = 0;
- }
+ ebitmap_node_clr_bit(n, bit);
+
+ if (find_first_bit(n->maps, EBITMAP_SIZE) < EBITMAP_SIZE)
+ return 0;
+
+ /* drop this node from the bitmap */
+ if (!n->next) {
+ /*
+ * this was the highest map
+ * within the bitmap
+ */
if (prev)
- prev->next = n->next;
+ e->highbit = prev->startbit + EBITMAP_SIZE;
else
- e->node = n->next;
-
- kfree(n);
+ e->highbit = 0;
}
+ if (prev)
+ prev->next = n->next;
+ else
+ e->node = n->next;
+ kfree(n);
}
return 0;
}
@@ -277,12 +293,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new)
return -ENOMEM;
- new->startbit = bit & ~(MAPSIZE - 1);
- new->map = (MAPBIT << (bit - new->startbit));
+ new->startbit = bit - (bit % EBITMAP_SIZE);
+ ebitmap_node_set_bit(new, bit);
if (!n)
/* this node will be the highest map within the bitmap */
- e->highbit = new->startbit + MAPSIZE;
+ e->highbit = new->startbit + EBITMAP_SIZE;
if (prev) {
new->next = prev->next;
@@ -316,11 +332,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
- int rc;
- struct ebitmap_node *n, *l;
+ struct ebitmap_node *n = NULL;
+ u32 mapunit, count, startbit, index;
+ u64 map;
__le32 buf[3];
- u32 mapsize, count, i;
- __le64 map;
+ int rc, i;
ebitmap_init(e);
@@ -328,85 +344,86 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
- mapsize = le32_to_cpu(buf[0]);
+ mapunit = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]);
- if (mapsize != MAPSIZE) {
+ if (mapunit != sizeof(u64) * 8) {
printk(KERN_ERR "security: ebitmap: map size %u does not "
- "match my size %Zd (high bit was %d)\n", mapsize,
- MAPSIZE, e->highbit);
+ "match my size %Zd (high bit was %d)\n",
+ mapunit, sizeof(u64) * 8, e->highbit);
goto bad;
}
+
+ /* round up e->highbit */
+ e->highbit += EBITMAP_SIZE - 1;
+ e->highbit -= (e->highbit % EBITMAP_SIZE);
+
if (!e->highbit) {
e->node = NULL;
goto ok;
}
- if (e->highbit & (MAPSIZE - 1)) {
- printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
- "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
- goto bad;
- }
- l = NULL;
+
for (i = 0; i < count; i++) {
- rc = next_entry(buf, fp, sizeof(u32));
+ rc = next_entry(&startbit, fp, sizeof(u32));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad;
}
- n = kzalloc(sizeof(*n), GFP_KERNEL);
- if (!n) {
- printk(KERN_ERR "security: ebitmap: out of memory\n");
- rc = -ENOMEM;
- goto bad;
- }
-
- n->startbit = le32_to_cpu(buf[0]);
+ startbit = le32_to_cpu(startbit);
- if (n->startbit & (MAPSIZE - 1)) {
+ if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map size (%Zd)\n",
- n->startbit, MAPSIZE);
- goto bad_free;
+ "not a multiple of the map unit size (%Zd)\n",
+ startbit, mapunit);
+ goto bad;
}
- if (n->startbit > (e->highbit - MAPSIZE)) {
+ if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%Zd)\n",
- n->startbit, (e->highbit - MAPSIZE));
- goto bad_free;
+ startbit, (e->highbit - mapunit));
+ goto bad;
+ }
+
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
+ struct ebitmap_node *_n = kzalloc(sizeof(*_n), GFP_KERNEL);
+ if (!_n) {
+ printk(KERN_ERR "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ _n->startbit = startbit - (startbit % EBITMAP_SIZE); /* round down */
+ if (n) {
+ n->next = _n;
+ } else {
+ e->node = _n;
+ }
+ n = _n;
+ } else if (startbit <= n->startbit) {
+ printk(KERN_ERR "security: ebitmap: start bit %d"
+ " comes after start bit %d\n",
+ startbit, n->startbit);
+ goto bad;
}
+
rc = next_entry(&map, fp, sizeof(u64));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
- goto bad_free;
+ goto bad;
}
- n->map = le64_to_cpu(map);
+ map = le64_to_cpu(map);
- if (!n->map) {
- printk(KERN_ERR "security: ebitmap: null map in "
- "ebitmap (startbit %d)\n", n->startbit);
- goto bad_free;
+ index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
+ while (map) {
+ n->maps[index] = map & (-1UL);
+ map = map >> EBITMAP_UNIT_SIZE;
+ index++;
}
- if (l) {
- if (n->startbit <= l->startbit) {
- printk(KERN_ERR "security: ebitmap: start "
- "bit %d comes after start bit %d\n",
- n->startbit, l->startbit);
- goto bad_free;
- }
- l->next = n;
- } else
- e->node = n;
-
- l = n;
}
-
ok:
rc = 0;
out:
return rc;
-bad_free:
- kfree(n);
bad:
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 1270e34..417053e 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -16,14 +16,15 @@
#include <net/netlabel.h>
-#define MAPTYPE u64 /* portion of bitmap in each node */
-#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
-#define MAPBIT 1ULL /* a bit in the node bitmap */
+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1ULL
struct ebitmap_node {
- u32 startbit; /* starting position in the total bitmap */
- MAPTYPE map; /* this node's portion of the bitmap */
struct ebitmap_node *next;
+ unsigned long maps[EBITMAP_UNIT_NUMS];
+ u32 startbit;
};
struct ebitmap {
@@ -34,11 +35,17 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
-static inline unsigned int ebitmap_start(struct ebitmap *e,
- struct ebitmap_node **n)
+static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+ struct ebitmap_node **n)
{
- *n = e->node;
- return ebitmap_startbit(e);
+ unsigned int ofs;
+
+ for (*n = e->node; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return (*n)->startbit + ofs;
+ }
+ return ebitmap_length(e);
}
static inline void ebitmap_init(struct ebitmap *e)
@@ -46,28 +53,65 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
-static inline unsigned int ebitmap_next(struct ebitmap_node **n,
- unsigned int bit)
+static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
+ struct ebitmap_node **n,
+ unsigned int bit)
{
- if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
- (*n)->next) {
- *n = (*n)->next;
- return (*n)->startbit;
- }
+ unsigned int ofs;
+
+ ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
- return (bit+1);
+ for (*n = (*n)->next; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+ }
+ return ebitmap_length(e);
}
-static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
+#define EBITMAP_NODE_INDEX(node, bit) \
+ (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
+#define EBITMAP_NODE_OFFSET(node, bit) \
+ (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
unsigned int bit)
{
- if (n->map & (MAPBIT << (bit - n->startbit)))
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ if ((n->maps[index] & (EBITMAP_BIT << ofs)))
return 1;
return 0;
}
-#define ebitmap_for_each_bit(e, n, bit) \
- for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for (bit = ebitmap_start_positive(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2..27ef5eb 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -34,7 +34,7 @@
*/
int mls_compute_context_len(struct context * context)
{
- int i, l, len, range;
+ int i, l, len, head, prev;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -42,31 +42,26 @@ int mls_compute_context_len(struct context * context)
len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) {
- range = 0;
len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
-
+ /* categories */
+ head = -2;
+ prev = -2;
+ ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped, at least. */
+ if (head != prev)
+ len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
len += strlen(policydb.p_cat_val_to_name[i]) + 1;
- range++;
- } else {
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
- range = 0;
+ head = i;
}
+ prev = i;
}
- /* Handle case where last category is the end of range */
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
-
+ if (prev != head)
+ len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
- &context->range.level[1]))
+ &context->range.level[1]))
break;
else
len++;
@@ -85,7 +80,7 @@ void mls_sid_to_context(struct context *context,
char **scontext)
{
char *scontextp;
- int i, l, range, wrote_sep;
+ int i, l, head, prev;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -97,61 +92,50 @@ void mls_sid_to_context(struct context *context,
scontextp++;
for (l = 0; l < 2; l++) {
- range = 0;
- wrote_sep = 0;
strcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
- scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+ scontextp += strlen(scontextp);
/* categories */
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
-
- if (!wrote_sep) {
- *scontextp++ = ':';
- wrote_sep = 1;
- } else
- *scontextp++ = ',';
- strcpy(scontextp, policydb.p_cat_val_to_name[i]);
- scontextp += strlen(policydb.p_cat_val_to_name[i]);
- range++;
- } else {
- if (range > 1) {
- if (range > 2)
+ head = -2;
+ prev = -2;
+ ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped, at least. */
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
+ scontextp += strlen(scontextp);
}
- range = 0;
+ if (prev < 0)
+ *scontextp++ = ':';
+ else
+ *scontextp++ = ',';
+ strcpy(scontextp, policydb.p_cat_val_to_name[i]);
+ scontextp += strlen(scontextp);
+ head = i;
}
+ prev = i;
}
- /* Handle case where last category is the end of range */
- if (range > 1) {
- if (range > 2)
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
+ scontextp += strlen(scontextp);
}
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
&context->range.level[1]))
break;
- else {
- *scontextp = '-';
- scontextp++;
- }
+ else
+ *scontextp++ = '-';
}
}
@@ -190,17 +174,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (i > p->p_cats.nprim)
- return 0;
- if (!ebitmap_get_bit(&levdatum->level->cat, i))
- /*
- * Category may not be associated with
- * sensitivity in low level.
- */
- return 0;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
+ /*
+ * Category may not be associated with
+ * sensitivity in low level.
+ */
+ return 0;
}
}
@@ -485,18 +467,16 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- int rc;
-
- catdatum = hashtab_search(newp->p_cats.table,
- oldp->p_cat_val_to_name[i]);
- if (!catdatum)
- return -EINVAL;
- rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
- if (rc)
- return rc;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ int rc;
+
+ catdatum = hashtab_search(newp->p_cats.table,
+ oldp->p_cat_val_to_name[i]);
+ if (!catdatum)
+ return -EINVAL;
+ rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
+ if (rc)
+ return rc;
}
ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 6100fc0..19be935 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext,
avkey.specified = AVTAB_AV;
sattr = &policydb.type_attr_map[scontext->type - 1];
tattr = &policydb.type_attr_map[tcontext->type - 1];
- ebitmap_for_each_bit(sattr, snode, i) {
- if (!ebitmap_node_get_bit(snode, i))
- continue;
- ebitmap_for_each_bit(tattr, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(sattr, snode, i) {
+ ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1;
avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid,
goto out_unlock;
}
- ebitmap_for_each_bit(&user->roles, rnode, i) {
- if (!ebitmap_node_get_bit(rnode, i))
- continue;
+ ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
role = policydb.role_val_to_struct[i];
usercon.role = i+1;
- ebitmap_for_each_bit(&role->types, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(&role->types, tnode, j) {
usercon.type = j+1;
if (mls_setup_user_range(fromcon, user, &usercon))
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-09-25 5:06 ` KaiGai Kohei
@ 2007-09-25 12:04 ` Paul Moore
2007-09-25 13:53 ` Stephen Smalley
1 sibling, 0 replies; 52+ messages in thread
From: Paul Moore @ 2007-09-25 12:04 UTC (permalink / raw)
To: KaiGai Kohei
Cc: Stephen Smalley, selinux, Yuichi Nakamura, James Morris,
Eric Paris
On Tuesday 25 September 2007 1:06:47 am KaiGai Kohei wrote:
> > Ok, looks reasonable. Please run it through ./scripts/checkpatch.pl and
> > fix up the minor issues it reports, then post a clean message with a
> > suitable description and the patch inline.
>
> What is your stance about warnings for "line over 80 characters" ?
> To resolve all of them makes harder to read source code, so I'm ignoring
> them in the attached version.
Others might have different or stronger opinions about this issue, but I would
encourage you to keep the line length less than or equal to 80 characters. I
know it can make for some ugly looking code in some cases but being able to
see the entire line in a 80 character wide terminal/editor is worth the cost.
--
paul moore
linux security @ hp
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-09-25 5:06 ` KaiGai Kohei
2007-09-25 12:04 ` Paul Moore
@ 2007-09-25 13:53 ` Stephen Smalley
2007-09-26 5:49 ` [PATCH] Improve SELinux performance when AVC misses KaiGai Kohei
1 sibling, 1 reply; 52+ messages in thread
From: Stephen Smalley @ 2007-09-25 13:53 UTC (permalink / raw)
To: KaiGai Kohei
Cc: selinux, Paul Moore, Yuichi Nakamura, James Morris, Eric Paris
On Tue, 2007-09-25 at 14:06 +0900, KaiGai Kohei wrote:
> - snip -
> >>> +static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
> >>> + struct ebitmap_node **n)
> >>>
> >>> I suspect we could just make these all "static" (not explicitly inline)
> >>> and let the compiler do the right thing. That seemed to be the trend
> >>> upstream and guidance from arjan.
> >> How should we do the explicitly inlined static functions used as stubs?
> >>
> >> For example, ebitmap_netlbl_export() when NetLabel is not enabled is
> >> defined as explicitly inlined function which always returns -ENOMEM,
> >> however, these are also declarations of function when NetLabel is enabled.
> >
> > Ah, never mind - as these are defined in the header file, they can stay
> > static inline.
>
> OK. I'll submit a patch to clean up non-stub static inline functions
> next to this patch.
I don't think it is necessary.
>
> - snip -
> >>> +#define ebitmap_for_each_bit(e, n, bit) \
> >>> + for (bit = ebitmap_start(e, &n); \
> >>> + bit < ebitmap_length(e); \
> >>> + bit = ebitmap_next(&n, bit)) \
> >>>
> >>> Ideally we'd kill off all uses of ebitmap_for_each_bit and use the _positive_ form in all cases,
> >>> although I see that would require some changes to the mls logic.
> >> ebitmap_start, ebitmap_next and ebitmap_for_each_bit are dropped.
> >> The rest of codes using ebitmap_for_each_bit(), in ss/mls.c, are
> >> also replaced with _positive_ version.
> >
> > Looks like you've left ebitmap_for_each_bit defined even though no
> > longer used in ebitmap.h.
>
> I misses to remove it, so its definition is also removed.
>
> - snip -
> > Ok, looks reasonable. Please run it through ./scripts/checkpatch.pl and
> > fix up the minor issues it reports, then post a clean message with a
> > suitable description and the patch inline.
>
> What is your stance about warnings for "line over 80 characters" ?
> To resolve all of them makes harder to read source code, so I'm ignoring
> them in the attached version.
> Rest of warnings except for them are removed.
I think we have to conform to it, and if it makes it harder to read,
possibly that suggests that we need to rework the code in some way.
> Thanks,
> --
> OSS Platform Development Division, NEC
> KaiGai Kohei <kaigai@ak.jp.nec.com>
>
> Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
Need to make a fresh posting with appropriate subject line, text
description of the patch, Signed-off-by, diffstat -p1 output, inlined
patch. No residue from prior replies.
>
> diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
> index ce492a6..3a60186 100644
> --- a/security/selinux/ss/ebitmap.c
> +++ b/security/selinux/ss/ebitmap.c
> @@ -10,6 +10,10 @@
> *
> * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
> */
> +/*
> + * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
> + * Applied standard bit operations to improve bitmap scanning.
> + */
>
> #include <linux/kernel.h>
> #include <linux/slab.h>
> @@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
> n2 = e2->node;
> while (n1 && n2 &&
> (n1->startbit == n2->startbit) &&
> - (n1->map == n2->map)) {
> + !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
> n1 = n1->next;
> n2 = n2->next;
> }
> @@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
> return -ENOMEM;
> }
> new->startbit = n->startbit;
> - new->map = n->map;
> + memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
> new->next = NULL;
> if (prev)
> prev->next = new;
> @@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
> {
> struct ebitmap_node *e_iter = ebmap->node;
> struct netlbl_lsm_secattr_catmap *c_iter;
> - u32 cmap_idx;
> + u32 cmap_idx, cmap_sft;
> + int i;
>
> - /* This function is a much simpler because SELinux's MAPTYPE happens
> - * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
> - * changed from a u64 this function will most likely need to be changed
> - * as well. It's not ideal but I think the tradeoff in terms of
> - * neatness and speed is worth it. */
> + /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
> + * however, it is not always compatible with an array of unsigned long
> + * in ebitmap_node.
> + * In addition, you should pay attention the following implementation
> + * assumes unsigned long has a width equal with or less than 64-bit.
> + */
>
> if (e_iter == NULL) {
> *catmap = NULL;
> @@ -104,19 +110,21 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
> c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
>
> while (e_iter != NULL) {
> - if (e_iter->startbit >=
> - (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
> - c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
> - if (c_iter->next == NULL)
> - goto netlbl_export_failure;
> - c_iter = c_iter->next;
> - c_iter->startbit = e_iter->startbit &
> - ~(NETLBL_CATMAP_SIZE - 1);
> + for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
> + unsigned int e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
> +
> + if (e_startbit >= c_iter->startbit + NETLBL_CATMAP_SIZE) {
> + c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
> + if (c_iter->next == NULL)
> + goto netlbl_export_failure;
> + c_iter = c_iter->next;
> + c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
> + }
> + cmap_idx = (e_startbit - c_iter->startbit) / NETLBL_CATMAP_MAPSIZE;
> + cmap_sft = (e_startbit - c_iter->startbit) % NETLBL_CATMAP_MAPSIZE;
> + c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft;
> + e_iter = e_iter->next;
> }
> - cmap_idx = (e_iter->startbit - c_iter->startbit) /
> - NETLBL_CATMAP_MAPSIZE;
> - c_iter->bitmap[cmap_idx] = e_iter->map;
> - e_iter = e_iter->next;
> }
>
> return 0;
> @@ -128,7 +136,7 @@ netlbl_export_failure:
>
> /**
> * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
> - * @ebmap: the ebitmap to export
> + * @ebmap: the ebitmap to import
> * @catmap: the NetLabel category bitmap
> *
> * Description:
> @@ -142,36 +150,45 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
> struct ebitmap_node *e_iter = NULL;
> struct ebitmap_node *emap_prev = NULL;
> struct netlbl_lsm_secattr_catmap *c_iter = catmap;
> - u32 c_idx;
> + u32 c_idx, c_pos, e_idx, e_sft;
>
> - /* This function is a much simpler because SELinux's MAPTYPE happens
> - * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
> - * changed from a u64 this function will most likely need to be changed
> - * as well. It's not ideal but I think the tradeoff in terms of
> - * neatness and speed is worth it. */
> + /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
> + * however, it is not always compatible with an array of unsigned long
> + * in ebitmap_node.
> + * In addition, you should pay attention the following implementation
> + * assumes unsigned long has a width equal with or less than 64-bit.
> + */
>
> do {
> for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
> - if (c_iter->bitmap[c_idx] == 0)
> + u64 map = c_iter->bitmap[c_idx];
> +
> + if (!map)
> continue;
>
> - e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
> - if (e_iter == NULL)
> - goto netlbl_import_failure;
> - if (emap_prev == NULL)
> - ebmap->node = e_iter;
> - else
> - emap_prev->next = e_iter;
> - emap_prev = e_iter;
> -
> - e_iter->startbit = c_iter->startbit +
> - NETLBL_CATMAP_MAPSIZE * c_idx;
> - e_iter->map = c_iter->bitmap[c_idx];
> + c_pos = c_iter->startbit + c_idx * NETLBL_CATMAP_MAPSIZE;
> + if (!e_iter || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
> + e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
> + if (!e_iter)
> + goto netlbl_import_failure;
> + e_iter->startbit = c_pos - (c_pos % EBITMAP_SIZE);
> + if (emap_prev == NULL)
> + ebmap->node = e_iter;
> + else
> + emap_prev->next = e_iter;
> + emap_prev = e_iter;
> + }
> + e_idx = (c_pos - e_iter->startbit) / EBITMAP_UNIT_SIZE;
> + e_sft = (c_pos - e_iter->startbit) % EBITMAP_UNIT_SIZE;
> + while (map) {
> + e_iter->maps[e_idx++] |= map & (-1UL);
> + map >>= EBITMAP_UNIT_SIZE;
> + }
> }
> c_iter = c_iter->next;
> } while (c_iter != NULL);
> if (e_iter != NULL)
> - ebmap->highbit = e_iter->startbit + MAPSIZE;
> + ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
> else
> ebitmap_destroy(ebmap);
>
> @@ -186,6 +203,7 @@ netlbl_import_failure:
> int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
> {
> struct ebitmap_node *n1, *n2;
> + int i;
>
> if (e1->highbit < e2->highbit)
> return 0;
> @@ -197,8 +215,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
> n1 = n1->next;
> continue;
> }
> - if ((n1->map & n2->map) != n2->map)
> - return 0;
> + for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
> + if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
> + return 0;
> + }
>
> n1 = n1->next;
> n2 = n2->next;
> @@ -219,12 +239,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
>
> n = e->node;
> while (n && (n->startbit <= bit)) {
> - if ((n->startbit + MAPSIZE) > bit) {
> - if (n->map & (MAPBIT << (bit - n->startbit)))
> - return 1;
> - else
> - return 0;
> - }
> + if ((n->startbit + EBITMAP_SIZE) > bit)
> + return ebitmap_node_get_bit(n, bit);
> n = n->next;
> }
>
> @@ -238,31 +254,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
> prev = NULL;
> n = e->node;
> while (n && n->startbit <= bit) {
> - if ((n->startbit + MAPSIZE) > bit) {
> + if ((n->startbit + EBITMAP_SIZE) > bit) {
> if (value) {
> - n->map |= (MAPBIT << (bit - n->startbit));
> + ebitmap_node_set_bit(n, bit);
> } else {
> - n->map &= ~(MAPBIT << (bit - n->startbit));
> - if (!n->map) {
> - /* drop this node from the bitmap */
> -
> - if (!n->next) {
> - /*
> - * this was the highest map
> - * within the bitmap
> - */
> - if (prev)
> - e->highbit = prev->startbit + MAPSIZE;
> - else
> - e->highbit = 0;
> - }
> + ebitmap_node_clr_bit(n, bit);
> +
> + if (find_first_bit(n->maps, EBITMAP_SIZE) < EBITMAP_SIZE)
> + return 0;
> +
> + /* drop this node from the bitmap */
> + if (!n->next) {
> + /*
> + * this was the highest map
> + * within the bitmap
> + */
> if (prev)
> - prev->next = n->next;
> + e->highbit = prev->startbit + EBITMAP_SIZE;
> else
> - e->node = n->next;
> -
> - kfree(n);
> + e->highbit = 0;
> }
> + if (prev)
> + prev->next = n->next;
> + else
> + e->node = n->next;
> + kfree(n);
> }
> return 0;
> }
> @@ -277,12 +293,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
> if (!new)
> return -ENOMEM;
>
> - new->startbit = bit & ~(MAPSIZE - 1);
> - new->map = (MAPBIT << (bit - new->startbit));
> + new->startbit = bit - (bit % EBITMAP_SIZE);
> + ebitmap_node_set_bit(new, bit);
>
> if (!n)
> /* this node will be the highest map within the bitmap */
> - e->highbit = new->startbit + MAPSIZE;
> + e->highbit = new->startbit + EBITMAP_SIZE;
>
> if (prev) {
> new->next = prev->next;
> @@ -316,11 +332,11 @@ void ebitmap_destroy(struct ebitmap *e)
>
> int ebitmap_read(struct ebitmap *e, void *fp)
> {
> - int rc;
> - struct ebitmap_node *n, *l;
> + struct ebitmap_node *n = NULL;
> + u32 mapunit, count, startbit, index;
> + u64 map;
> __le32 buf[3];
> - u32 mapsize, count, i;
> - __le64 map;
> + int rc, i;
>
> ebitmap_init(e);
>
> @@ -328,85 +344,86 @@ int ebitmap_read(struct ebitmap *e, void *fp)
> if (rc < 0)
> goto out;
>
> - mapsize = le32_to_cpu(buf[0]);
> + mapunit = le32_to_cpu(buf[0]);
> e->highbit = le32_to_cpu(buf[1]);
> count = le32_to_cpu(buf[2]);
>
> - if (mapsize != MAPSIZE) {
> + if (mapunit != sizeof(u64) * 8) {
> printk(KERN_ERR "security: ebitmap: map size %u does not "
> - "match my size %Zd (high bit was %d)\n", mapsize,
> - MAPSIZE, e->highbit);
> + "match my size %Zd (high bit was %d)\n",
> + mapunit, sizeof(u64) * 8, e->highbit);
> goto bad;
> }
> +
> + /* round up e->highbit */
> + e->highbit += EBITMAP_SIZE - 1;
> + e->highbit -= (e->highbit % EBITMAP_SIZE);
> +
> if (!e->highbit) {
> e->node = NULL;
> goto ok;
> }
> - if (e->highbit & (MAPSIZE - 1)) {
> - printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
> - "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
> - goto bad;
> - }
> - l = NULL;
> +
> for (i = 0; i < count; i++) {
> - rc = next_entry(buf, fp, sizeof(u32));
> + rc = next_entry(&startbit, fp, sizeof(u32));
> if (rc < 0) {
> printk(KERN_ERR "security: ebitmap: truncated map\n");
> goto bad;
> }
> - n = kzalloc(sizeof(*n), GFP_KERNEL);
> - if (!n) {
> - printk(KERN_ERR "security: ebitmap: out of memory\n");
> - rc = -ENOMEM;
> - goto bad;
> - }
> -
> - n->startbit = le32_to_cpu(buf[0]);
> + startbit = le32_to_cpu(startbit);
>
> - if (n->startbit & (MAPSIZE - 1)) {
> + if (startbit & (mapunit - 1)) {
> printk(KERN_ERR "security: ebitmap start bit (%d) is "
> - "not a multiple of the map size (%Zd)\n",
> - n->startbit, MAPSIZE);
> - goto bad_free;
> + "not a multiple of the map unit size (%Zd)\n",
> + startbit, mapunit);
> + goto bad;
> }
> - if (n->startbit > (e->highbit - MAPSIZE)) {
> + if (startbit > e->highbit - mapunit) {
> printk(KERN_ERR "security: ebitmap start bit (%d) is "
> "beyond the end of the bitmap (%Zd)\n",
> - n->startbit, (e->highbit - MAPSIZE));
> - goto bad_free;
> + startbit, (e->highbit - mapunit));
> + goto bad;
> + }
> +
> + if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
> + struct ebitmap_node *_n = kzalloc(sizeof(*_n), GFP_KERNEL);
> + if (!_n) {
> + printk(KERN_ERR "security: ebitmap: out of memory\n");
> + rc = -ENOMEM;
> + goto bad;
> + }
> + _n->startbit = startbit - (startbit % EBITMAP_SIZE); /* round down */
> + if (n) {
> + n->next = _n;
> + } else {
> + e->node = _n;
> + }
> + n = _n;
> + } else if (startbit <= n->startbit) {
> + printk(KERN_ERR "security: ebitmap: start bit %d"
> + " comes after start bit %d\n",
> + startbit, n->startbit);
> + goto bad;
> }
> +
> rc = next_entry(&map, fp, sizeof(u64));
> if (rc < 0) {
> printk(KERN_ERR "security: ebitmap: truncated map\n");
> - goto bad_free;
> + goto bad;
> }
> - n->map = le64_to_cpu(map);
> + map = le64_to_cpu(map);
>
> - if (!n->map) {
> - printk(KERN_ERR "security: ebitmap: null map in "
> - "ebitmap (startbit %d)\n", n->startbit);
> - goto bad_free;
> + index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
> + while (map) {
> + n->maps[index] = map & (-1UL);
> + map = map >> EBITMAP_UNIT_SIZE;
> + index++;
> }
> - if (l) {
> - if (n->startbit <= l->startbit) {
> - printk(KERN_ERR "security: ebitmap: start "
> - "bit %d comes after start bit %d\n",
> - n->startbit, l->startbit);
> - goto bad_free;
> - }
> - l->next = n;
> - } else
> - e->node = n;
> -
> - l = n;
> }
> -
> ok:
> rc = 0;
> out:
> return rc;
> -bad_free:
> - kfree(n);
> bad:
> if (!rc)
> rc = -EINVAL;
> diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
> index 1270e34..417053e 100644
> --- a/security/selinux/ss/ebitmap.h
> +++ b/security/selinux/ss/ebitmap.h
> @@ -16,14 +16,15 @@
>
> #include <net/netlabel.h>
>
> -#define MAPTYPE u64 /* portion of bitmap in each node */
> -#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
> -#define MAPBIT 1ULL /* a bit in the node bitmap */
> +#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
> +#define EBITMAP_UNIT_SIZE BITS_PER_LONG
> +#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
> +#define EBITMAP_BIT 1ULL
>
> struct ebitmap_node {
> - u32 startbit; /* starting position in the total bitmap */
> - MAPTYPE map; /* this node's portion of the bitmap */
> struct ebitmap_node *next;
> + unsigned long maps[EBITMAP_UNIT_NUMS];
> + u32 startbit;
> };
>
> struct ebitmap {
> @@ -34,11 +35,17 @@ struct ebitmap {
> #define ebitmap_length(e) ((e)->highbit)
> #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
>
> -static inline unsigned int ebitmap_start(struct ebitmap *e,
> - struct ebitmap_node **n)
> +static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
> + struct ebitmap_node **n)
> {
> - *n = e->node;
> - return ebitmap_startbit(e);
> + unsigned int ofs;
> +
> + for (*n = e->node; *n; *n = (*n)->next) {
> + ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
> + if (ofs < EBITMAP_SIZE)
> + return (*n)->startbit + ofs;
> + }
> + return ebitmap_length(e);
> }
>
> static inline void ebitmap_init(struct ebitmap *e)
> @@ -46,28 +53,65 @@ static inline void ebitmap_init(struct ebitmap *e)
> memset(e, 0, sizeof(*e));
> }
>
> -static inline unsigned int ebitmap_next(struct ebitmap_node **n,
> - unsigned int bit)
> +static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
> + struct ebitmap_node **n,
> + unsigned int bit)
> {
> - if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
> - (*n)->next) {
> - *n = (*n)->next;
> - return (*n)->startbit;
> - }
> + unsigned int ofs;
> +
> + ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
> + if (ofs < EBITMAP_SIZE)
> + return ofs + (*n)->startbit;
>
> - return (bit+1);
> + for (*n = (*n)->next; *n; *n = (*n)->next) {
> + ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
> + if (ofs < EBITMAP_SIZE)
> + return ofs + (*n)->startbit;
> + }
> + return ebitmap_length(e);
> }
>
> -static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
> +#define EBITMAP_NODE_INDEX(node, bit) \
> + (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
> +#define EBITMAP_NODE_OFFSET(node, bit) \
> + (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
> +
> +static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
> unsigned int bit)
> {
> - if (n->map & (MAPBIT << (bit - n->startbit)))
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + if ((n->maps[index] & (EBITMAP_BIT << ofs)))
> return 1;
> return 0;
> }
>
> -#define ebitmap_for_each_bit(e, n, bit) \
> - for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
> +static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
> + unsigned int bit)
> +{
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + n->maps[index] |= (EBITMAP_BIT << ofs);
> +}
> +
> +static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
> + unsigned int bit)
> +{
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + n->maps[index] &= ~(EBITMAP_BIT << ofs);
> +}
> +
> +#define ebitmap_for_each_positive_bit(e, n, bit) \
> + for (bit = ebitmap_start_positive(e, &n); \
> + bit < ebitmap_length(e); \
> + bit = ebitmap_next_positive(e, &n, bit)) \
>
> int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
> int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
> diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
> index 4a8bab2..27ef5eb 100644
> --- a/security/selinux/ss/mls.c
> +++ b/security/selinux/ss/mls.c
> @@ -34,7 +34,7 @@
> */
> int mls_compute_context_len(struct context * context)
> {
> - int i, l, len, range;
> + int i, l, len, head, prev;
> struct ebitmap_node *node;
>
> if (!selinux_mls_enabled)
> @@ -42,31 +42,26 @@ int mls_compute_context_len(struct context * context)
>
> len = 1; /* for the beginning ":" */
> for (l = 0; l < 2; l++) {
> - range = 0;
> len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
>
> - ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (range) {
> - range++;
> - continue;
> - }
> -
> + /* categories */
> + head = -2;
> + prev = -2;
> + ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
> + if (i - prev > 1) {
> + /* one or more negative bits are skipped, at least. */
> + if (head != prev)
> + len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
> len += strlen(policydb.p_cat_val_to_name[i]) + 1;
> - range++;
> - } else {
> - if (range > 1)
> - len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
> - range = 0;
> + head = i;
> }
> + prev = i;
> }
> - /* Handle case where last category is the end of range */
> - if (range > 1)
> - len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
> -
> + if (prev != head)
> + len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
> if (l == 0) {
> if (mls_level_eq(&context->range.level[0],
> - &context->range.level[1]))
> + &context->range.level[1]))
> break;
> else
> len++;
> @@ -85,7 +80,7 @@ void mls_sid_to_context(struct context *context,
> char **scontext)
> {
> char *scontextp;
> - int i, l, range, wrote_sep;
> + int i, l, head, prev;
> struct ebitmap_node *node;
>
> if (!selinux_mls_enabled)
> @@ -97,61 +92,50 @@ void mls_sid_to_context(struct context *context,
> scontextp++;
>
> for (l = 0; l < 2; l++) {
> - range = 0;
> - wrote_sep = 0;
> strcpy(scontextp,
> policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
> - scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
> + scontextp += strlen(scontextp);
>
> /* categories */
> - ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (range) {
> - range++;
> - continue;
> - }
> -
> - if (!wrote_sep) {
> - *scontextp++ = ':';
> - wrote_sep = 1;
> - } else
> - *scontextp++ = ',';
> - strcpy(scontextp, policydb.p_cat_val_to_name[i]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i]);
> - range++;
> - } else {
> - if (range > 1) {
> - if (range > 2)
> + head = -2;
> + prev = -2;
> + ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
> + if (i - prev > 1) {
> + /* one or more negative bits are skipped, at least. */
> + if (prev != head) {
> + if (prev - head > 1)
> *scontextp++ = '.';
> else
> *scontextp++ = ',';
> -
> - strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
> + strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
> + scontextp += strlen(scontextp);
> }
> - range = 0;
> + if (prev < 0)
> + *scontextp++ = ':';
> + else
> + *scontextp++ = ',';
> + strcpy(scontextp, policydb.p_cat_val_to_name[i]);
> + scontextp += strlen(scontextp);
> + head = i;
> }
> + prev = i;
> }
>
> - /* Handle case where last category is the end of range */
> - if (range > 1) {
> - if (range > 2)
> + if (prev != head) {
> + if (prev - head > 1)
> *scontextp++ = '.';
> else
> *scontextp++ = ',';
> -
> - strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
> + strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
> + scontextp += strlen(scontextp);
> }
>
> if (l == 0) {
> if (mls_level_eq(&context->range.level[0],
> &context->range.level[1]))
> break;
> - else {
> - *scontextp = '-';
> - scontextp++;
> - }
> + else
> + *scontextp++ = '-';
> }
> }
>
> @@ -190,17 +174,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
> if (!levdatum)
> return 0;
>
> - ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (i > p->p_cats.nprim)
> - return 0;
> - if (!ebitmap_get_bit(&levdatum->level->cat, i))
> - /*
> - * Category may not be associated with
> - * sensitivity in low level.
> - */
> - return 0;
> - }
> + ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
> + if (i > p->p_cats.nprim)
> + return 0;
> + if (!ebitmap_get_bit(&levdatum->level->cat, i))
> + /*
> + * Category may not be associated with
> + * sensitivity in low level.
> + */
> + return 0;
> }
> }
>
> @@ -485,18 +467,16 @@ int mls_convert_context(struct policydb *oldp,
> c->range.level[l].sens = levdatum->level->sens;
>
> ebitmap_init(&bitmap);
> - ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - int rc;
> -
> - catdatum = hashtab_search(newp->p_cats.table,
> - oldp->p_cat_val_to_name[i]);
> - if (!catdatum)
> - return -EINVAL;
> - rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
> - if (rc)
> - return rc;
> - }
> + ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
> + int rc;
> +
> + catdatum = hashtab_search(newp->p_cats.table,
> + oldp->p_cat_val_to_name[i]);
> + if (!catdatum)
> + return -EINVAL;
> + rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
> + if (rc)
> + return rc;
> }
> ebitmap_destroy(&c->range.level[l].cat);
> c->range.level[l].cat = bitmap;
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index 6100fc0..19be935 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext,
> avkey.specified = AVTAB_AV;
> sattr = &policydb.type_attr_map[scontext->type - 1];
> tattr = &policydb.type_attr_map[tcontext->type - 1];
> - ebitmap_for_each_bit(sattr, snode, i) {
> - if (!ebitmap_node_get_bit(snode, i))
> - continue;
> - ebitmap_for_each_bit(tattr, tnode, j) {
> - if (!ebitmap_node_get_bit(tnode, j))
> - continue;
> + ebitmap_for_each_positive_bit(sattr, snode, i) {
> + ebitmap_for_each_positive_bit(tattr, tnode, j) {
> avkey.source_type = i + 1;
> avkey.target_type = j + 1;
> for (node = avtab_search_node(&policydb.te_avtab, &avkey);
> @@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid,
> goto out_unlock;
> }
>
> - ebitmap_for_each_bit(&user->roles, rnode, i) {
> - if (!ebitmap_node_get_bit(rnode, i))
> - continue;
> + ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
> role = policydb.role_val_to_struct[i];
> usercon.role = i+1;
> - ebitmap_for_each_bit(&role->types, tnode, j) {
> - if (!ebitmap_node_get_bit(tnode, j))
> - continue;
> + ebitmap_for_each_positive_bit(&role->types, tnode, j) {
> usercon.type = j+1;
>
> if (mls_setup_user_range(fromcon, user, &usercon))
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH] Improve SELinux performance when AVC misses.
2007-09-25 13:53 ` Stephen Smalley
@ 2007-09-26 5:49 ` KaiGai Kohei
2007-09-27 2:22 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-26 5:49 UTC (permalink / raw)
To: Stephen Smalley
Cc: selinux, Paul Moore, Yuichi Nakamura, James Morris, Eric Paris
>>>> For example, ebitmap_netlbl_export() when NetLabel is not enabled is
>>>> defined as explicitly inlined function which always returns -ENOMEM,
>>>> however, these are also declarations of function when NetLabel is enabled.
>>> Ah, never mind - as these are defined in the header file, they can stay
>>> static inline.
>> OK. I'll submit a patch to clean up non-stub static inline functions
>> next to this patch.
>
> I don't think it is necessary.
Sorry, I might misread your suggestion.
>>> Ok, looks reasonable. Please run it through ./scripts/checkpatch.pl and
>>> fix up the minor issues it reports, then post a clean message with a
>>> suitable description and the patch inline.
>> What is your stance about warnings for "line over 80 characters" ?
>> To resolve all of them makes harder to read source code, so I'm ignoring
>> them in the attached version.
>> Rest of warnings except for them are removed.
>
> I think we have to conform to it, and if it makes it harder to read,
> possibly that suggests that we need to rework the code in some way.
I'm preparing another version of patch which does not contain any
"line over 80 characters" warning. Please wait for a while.
> Need to make a fresh posting with appropriate subject line, text
> description of the patch, Signed-off-by, diffstat -p1 output, inlined
> patch. No residue from prior replies.
OK, the following part is a fresh patch.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-26 5:49 ` [PATCH] Improve SELinux performance when AVC misses KaiGai Kohei
@ 2007-09-27 2:22 ` KaiGai Kohei
2007-09-27 2:43 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-27 2:22 UTC (permalink / raw)
To: Stephen Smalley
Cc: selinux, Paul Moore, Yuichi Nakamura, James Morris, Eric Paris
>> I think we have to conform to it, and if it makes it harder to read,
>> possibly that suggests that we need to rework the code in some way.
>
> I'm preparing another version of patch which does not contain any
> "line over 80 characters" warning. Please wait for a while.
The following part is the patch which does not contain any "line
over 80 characters" warnings.
--------
[PATCH] Improve SELinux performance when AVC misses.
* We add ebitmap_for_each_positive_bit() which enables to walk on
any positive bit on the given ebitmap, to improve its performance
using common bit-operations defined in linux/bitops.h.
In the previous version, this logic was implemented using a combination
of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
in performance aspect.
This logic is most frequestly used to compute a new AVC entry,
so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get
suitable for using find_next_bit() which is fasted than iteration of
shift and logical operation, and to maximize memory usage allocated
from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation
in ss/service.c and ss/mls.c. Some of related implementation are
changed, however, there is no incompatibility with the previous
version.
* The width of any new line are less or equal than 80-chars.
The following benchmark shows the effect of this patch, when we
access many files which have different security context one after
another. The number is more than /selinux/avc/cache_threshold, so
any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s]
STD: 0.265 0.019
------------------------------------------
1st: 22.558 [s] 8.786 [s]
2nd: 22.458 [s] 8.750 [s]
3rd: 22.478 [s] 8.754 [s]
4th: 22.724 [s] 8.745 [s]
5th: 22.918 [s] 8.748 [s]
6th: 22.905 [s] 8.764 [s]
7th: 23.238 [s] 8.726 [s]
8th: 22.822 [s] 8.729 [s]
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
---
security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++-----------------
security/selinux/ss/ebitmap.h | 87 ++++++++++---
security/selinux/ss/mls.c | 156 +++++++++++------------
security/selinux/ss/services.c | 16 +--
4 files changed, 303 insertions(+), 237 deletions(-)
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ce492a6..5643bdd 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/
+/*
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Applied standard bit operations to improve bitmap scanning.
+ */
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
n2 = e2->node;
while (n1 && n2 &&
(n1->startbit == n2->startbit) &&
- (n1->map == n2->map)) {
+ !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
n1 = n1->next;
n2 = n2->next;
}
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
return -ENOMEM;
}
new->startbit = n->startbit;
- new->map = n->map;
+ memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
new->next = NULL;
if (prev)
prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
{
struct ebitmap_node *e_iter = ebmap->node;
struct netlbl_lsm_secattr_catmap *c_iter;
- u32 cmap_idx;
+ u32 cmap_idx, cmap_sft;
+ int i;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
if (e_iter == NULL) {
*catmap = NULL;
@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) {
- if (e_iter->startbit >=
- (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
- c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
- if (c_iter->next == NULL)
- goto netlbl_export_failure;
- c_iter = c_iter->next;
- c_iter->startbit = e_iter->startbit &
- ~(NETLBL_CATMAP_SIZE - 1);
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+ unsigned int delta, e_startbit, c_endbit;
+
+ e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
+ c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
+ if (e_startbit >= c_endbit) {
+ c_iter->next
+ = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (c_iter->next == NULL)
+ goto netlbl_export_failure;
+ c_iter = c_iter->next;
+ c_iter->startbit
+ = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
+ delta = e_startbit - c_iter->startbit;
+ cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
+ cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
+ c_iter->bitmap[cmap_idx]
+ |= e_iter->maps[cmap_idx] << cmap_sft;
+ e_iter = e_iter->next;
}
- cmap_idx = (e_iter->startbit - c_iter->startbit) /
- NETLBL_CATMAP_MAPSIZE;
- c_iter->bitmap[cmap_idx] = e_iter->map;
- e_iter = e_iter->next;
}
return 0;
@@ -128,7 +142,7 @@ netlbl_export_failure:
/**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
- * @ebmap: the ebitmap to export
+ * @ebmap: the ebitmap to import
* @catmap: the NetLabel category bitmap
*
* Description:
@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap;
- u32 c_idx;
+ u32 c_idx, c_pos, e_idx, e_sft;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
- if (c_iter->bitmap[c_idx] == 0)
+ unsigned int delta;
+ u64 map = c_iter->bitmap[c_idx];
+
+ if (!map)
continue;
- e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
- if (e_iter == NULL)
- goto netlbl_import_failure;
- if (emap_prev == NULL)
- ebmap->node = e_iter;
- else
- emap_prev->next = e_iter;
- emap_prev = e_iter;
-
- e_iter->startbit = c_iter->startbit +
- NETLBL_CATMAP_MAPSIZE * c_idx;
- e_iter->map = c_iter->bitmap[c_idx];
+ c_pos = c_iter->startbit
+ + c_idx * NETLBL_CATMAP_MAPSIZE;
+ if (!e_iter
+ || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
+ e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+ if (!e_iter)
+ goto netlbl_import_failure;
+ e_iter->startbit
+ = c_pos - (c_pos % EBITMAP_SIZE);
+ if (emap_prev == NULL)
+ ebmap->node = e_iter;
+ else
+ emap_prev->next = e_iter;
+ emap_prev = e_iter;
+ }
+ delta = c_pos - e_iter->startbit;
+ e_idx = delta / EBITMAP_UNIT_SIZE;
+ e_sft = delta % EBITMAP_UNIT_SIZE;
+ while (map) {
+ e_iter->maps[e_idx++] |= map & (-1UL);
+ map >>= EBITMAP_UNIT_SIZE;
+ }
}
c_iter = c_iter->next;
} while (c_iter != NULL);
if (e_iter != NULL)
- ebmap->highbit = e_iter->startbit + MAPSIZE;
+ ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
else
ebitmap_destroy(ebmap);
@@ -186,6 +214,7 @@ netlbl_import_failure:
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
+ int i;
if (e1->highbit < e2->highbit)
return 0;
@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next;
continue;
}
- if ((n1->map & n2->map) != n2->map)
- return 0;
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+ if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
+ return 0;
+ }
n1 = n1->next;
n2 = n2->next;
@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node;
while (n && (n->startbit <= bit)) {
- if ((n->startbit + MAPSIZE) > bit) {
- if (n->map & (MAPBIT << (bit - n->startbit)))
- return 1;
- else
- return 0;
- }
+ if ((n->startbit + EBITMAP_SIZE) > bit)
+ return ebitmap_node_get_bit(n, bit);
n = n->next;
}
@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
- if ((n->startbit + MAPSIZE) > bit) {
+ if ((n->startbit + EBITMAP_SIZE) > bit) {
if (value) {
- n->map |= (MAPBIT << (bit - n->startbit));
+ ebitmap_node_set_bit(n, bit);
} else {
- n->map &= ~(MAPBIT << (bit - n->startbit));
- if (!n->map) {
- /* drop this node from the bitmap */
-
- if (!n->next) {
- /*
- * this was the highest map
- * within the bitmap
- */
- if (prev)
- e->highbit = prev->startbit + MAPSIZE;
- else
- e->highbit = 0;
- }
+ unsigned int s;
+
+ ebitmap_node_clr_bit(n, bit);
+
+ s = find_first_bit(n->maps, EBITMAP_SIZE);
+ if (s < EBITMAP_SIZE)
+ return 0;
+
+ /* drop this node from the bitmap */
+ if (!n->next) {
+ /*
+ * this was the highest map
+ * within the bitmap
+ */
if (prev)
- prev->next = n->next;
+ e->highbit = prev->startbit
+ + EBITMAP_SIZE;
else
- e->node = n->next;
-
- kfree(n);
+ e->highbit = 0;
}
+ if (prev)
+ prev->next = n->next;
+ else
+ e->node = n->next;
+ kfree(n);
}
return 0;
}
@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new)
return -ENOMEM;
- new->startbit = bit & ~(MAPSIZE - 1);
- new->map = (MAPBIT << (bit - new->startbit));
+ new->startbit = bit - (bit % EBITMAP_SIZE);
+ ebitmap_node_set_bit(new, bit);
if (!n)
/* this node will be the highest map within the bitmap */
- e->highbit = new->startbit + MAPSIZE;
+ e->highbit = new->startbit + EBITMAP_SIZE;
if (prev) {
new->next = prev->next;
@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
- int rc;
- struct ebitmap_node *n, *l;
+ struct ebitmap_node *n = NULL;
+ u32 mapunit, count, startbit, index;
+ u64 map;
__le32 buf[3];
- u32 mapsize, count, i;
- __le64 map;
+ int rc, i;
ebitmap_init(e);
@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
- mapsize = le32_to_cpu(buf[0]);
+ mapunit = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]);
- if (mapsize != MAPSIZE) {
+ if (mapunit != sizeof(u64) * 8) {
printk(KERN_ERR "security: ebitmap: map size %u does not "
- "match my size %Zd (high bit was %d)\n", mapsize,
- MAPSIZE, e->highbit);
+ "match my size %Zd (high bit was %d)\n",
+ mapunit, sizeof(u64) * 8, e->highbit);
goto bad;
}
+
+ /* round up e->highbit */
+ e->highbit += EBITMAP_SIZE - 1;
+ e->highbit -= (e->highbit % EBITMAP_SIZE);
+
if (!e->highbit) {
e->node = NULL;
goto ok;
}
- if (e->highbit & (MAPSIZE - 1)) {
- printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
- "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
- goto bad;
- }
- l = NULL;
+
for (i = 0; i < count; i++) {
- rc = next_entry(buf, fp, sizeof(u32));
+ rc = next_entry(&startbit, fp, sizeof(u32));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad;
}
- n = kzalloc(sizeof(*n), GFP_KERNEL);
- if (!n) {
- printk(KERN_ERR "security: ebitmap: out of memory\n");
- rc = -ENOMEM;
- goto bad;
- }
-
- n->startbit = le32_to_cpu(buf[0]);
+ startbit = le32_to_cpu(startbit);
- if (n->startbit & (MAPSIZE - 1)) {
+ if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map size (%Zd)\n",
- n->startbit, MAPSIZE);
- goto bad_free;
+ "not a multiple of the map unit size (%Zd)\n",
+ startbit, mapunit);
+ goto bad;
}
- if (n->startbit > (e->highbit - MAPSIZE)) {
+ if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%Zd)\n",
- n->startbit, (e->highbit - MAPSIZE));
- goto bad_free;
+ startbit, (e->highbit - mapunit));
+ goto bad;
+ }
+
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
+ struct ebitmap_node *_n;
+ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
+ if (!_n) {
+ printk(KERN_ERR
+ "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ /* round down */
+ _n->startbit = startbit - (startbit % EBITMAP_SIZE);
+ if (n) {
+ n->next = _n;
+ } else {
+ e->node = _n;
+ }
+ n = _n;
+ } else if (startbit <= n->startbit) {
+ printk(KERN_ERR "security: ebitmap: start bit %d"
+ " comes after start bit %d\n",
+ startbit, n->startbit);
+ goto bad;
}
+
rc = next_entry(&map, fp, sizeof(u64));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
- goto bad_free;
+ goto bad;
}
- n->map = le64_to_cpu(map);
+ map = le64_to_cpu(map);
- if (!n->map) {
- printk(KERN_ERR "security: ebitmap: null map in "
- "ebitmap (startbit %d)\n", n->startbit);
- goto bad_free;
+ index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
+ while (map) {
+ n->maps[index] = map & (-1UL);
+ map = map >> EBITMAP_UNIT_SIZE;
+ index++;
}
- if (l) {
- if (n->startbit <= l->startbit) {
- printk(KERN_ERR "security: ebitmap: start "
- "bit %d comes after start bit %d\n",
- n->startbit, l->startbit);
- goto bad_free;
- }
- l->next = n;
- } else
- e->node = n;
-
- l = n;
}
-
ok:
rc = 0;
out:
return rc;
-bad_free:
- kfree(n);
bad:
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 1270e34..e38a327 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -16,14 +16,16 @@
#include <net/netlabel.h>
-#define MAPTYPE u64 /* portion of bitmap in each node */
-#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
-#define MAPBIT 1ULL /* a bit in the node bitmap */
+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
+ / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1ULL
struct ebitmap_node {
- u32 startbit; /* starting position in the total bitmap */
- MAPTYPE map; /* this node's portion of the bitmap */
struct ebitmap_node *next;
+ unsigned long maps[EBITMAP_UNIT_NUMS];
+ u32 startbit;
};
struct ebitmap {
@@ -34,11 +36,17 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
-static inline unsigned int ebitmap_start(struct ebitmap *e,
- struct ebitmap_node **n)
+static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+ struct ebitmap_node **n)
{
- *n = e->node;
- return ebitmap_startbit(e);
+ unsigned int ofs;
+
+ for (*n = e->node; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return (*n)->startbit + ofs;
+ }
+ return ebitmap_length(e);
}
static inline void ebitmap_init(struct ebitmap *e)
@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
-static inline unsigned int ebitmap_next(struct ebitmap_node **n,
- unsigned int bit)
+static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
+ struct ebitmap_node **n,
+ unsigned int bit)
{
- if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
- (*n)->next) {
- *n = (*n)->next;
- return (*n)->startbit;
- }
+ unsigned int ofs;
+
+ ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
- return (bit+1);
+ for (*n = (*n)->next; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+ }
+ return ebitmap_length(e);
}
-static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
+#define EBITMAP_NODE_INDEX(node, bit) \
+ (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
+#define EBITMAP_NODE_OFFSET(node, bit) \
+ (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
unsigned int bit)
{
- if (n->map & (MAPBIT << (bit - n->startbit)))
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ if ((n->maps[index] & (EBITMAP_BIT << ofs)))
return 1;
return 0;
}
-#define ebitmap_for_each_bit(e, n, bit) \
- for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for (bit = ebitmap_start_positive(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2..9a11dea 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -34,7 +34,9 @@
*/
int mls_compute_context_len(struct context * context)
{
- int i, l, len, range;
+ int i, l, len, head, prev;
+ char *nm;
+ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) {
- range = 0;
- len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
-
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
+ int index_sens = context->range.level[l].sens;
+ len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
- len += strlen(policydb.p_cat_val_to_name[i]) + 1;
- range++;
- } else {
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
- range = 0;
+ /* categories */
+ head = -2;
+ prev = -2;
+ e = &context->range.level[l].cat;
+ ebitmap_for_each_positive_bit(e, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped */
+ if (head != prev) {
+ nm = policydb.p_cat_val_to_name[prev];
+ len += strlen(nm) + 1;
+ }
+ nm = policydb.p_cat_val_to_name[i];
+ len += strlen(nm) + 1;
+ head = i;
}
+ prev = i;
+ }
+ if (prev != head) {
+ nm = policydb.p_cat_val_to_name[prev];
+ len += strlen(nm) + 1;
}
- /* Handle case where last category is the end of range */
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
-
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
- &context->range.level[1]))
+ &context->range.level[1]))
break;
else
len++;
@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
void mls_sid_to_context(struct context *context,
char **scontext)
{
- char *scontextp;
- int i, l, range, wrote_sep;
+ char *scontextp, *nm;
+ int i, l, head, prev;
+ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
scontextp++;
for (l = 0; l < 2; l++) {
- range = 0;
- wrote_sep = 0;
strcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
- scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+ scontextp += strlen(scontextp);
/* categories */
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
-
- if (!wrote_sep) {
- *scontextp++ = ':';
- wrote_sep = 1;
- } else
- *scontextp++ = ',';
- strcpy(scontextp, policydb.p_cat_val_to_name[i]);
- scontextp += strlen(policydb.p_cat_val_to_name[i]);
- range++;
- } else {
- if (range > 1) {
- if (range > 2)
+ head = -2;
+ prev = -2;
+ e = &context->range.level[l].cat;
+ ebitmap_for_each_positive_bit(e, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped */
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ nm = policydb.p_cat_val_to_name[prev];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
}
- range = 0;
+ if (prev < 0)
+ *scontextp++ = ':';
+ else
+ *scontextp++ = ',';
+ nm = policydb.p_cat_val_to_name[i];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
+ head = i;
}
+ prev = i;
}
- /* Handle case where last category is the end of range */
- if (range > 1) {
- if (range > 2)
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ nm = policydb.p_cat_val_to_name[prev];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
}
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
&context->range.level[1]))
break;
- else {
- *scontextp = '-';
- scontextp++;
- }
+ else
+ *scontextp++ = '-';
}
}
@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (i > p->p_cats.nprim)
- return 0;
- if (!ebitmap_get_bit(&levdatum->level->cat, i))
- /*
- * Category may not be associated with
- * sensitivity in low level.
- */
- return 0;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
+ /*
+ * Category may not be associated with
+ * sensitivity in low level.
+ */
+ return 0;
}
}
@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- int rc;
-
- catdatum = hashtab_search(newp->p_cats.table,
- oldp->p_cat_val_to_name[i]);
- if (!catdatum)
- return -EINVAL;
- rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
- if (rc)
- return rc;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ int rc;
+
+ catdatum = hashtab_search(newp->p_cats.table,
+ oldp->p_cat_val_to_name[i]);
+ if (!catdatum)
+ return -EINVAL;
+ rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
+ if (rc)
+ return rc;
}
ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 6100fc0..19be935 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext,
avkey.specified = AVTAB_AV;
sattr = &policydb.type_attr_map[scontext->type - 1];
tattr = &policydb.type_attr_map[tcontext->type - 1];
- ebitmap_for_each_bit(sattr, snode, i) {
- if (!ebitmap_node_get_bit(snode, i))
- continue;
- ebitmap_for_each_bit(tattr, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(sattr, snode, i) {
+ ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1;
avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid,
goto out_unlock;
}
- ebitmap_for_each_bit(&user->roles, rnode, i) {
- if (!ebitmap_node_get_bit(rnode, i))
- continue;
+ ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
role = policydb.role_val_to_struct[i];
usercon.role = i+1;
- ebitmap_for_each_bit(&role->types, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(&role->types, tnode, j) {
usercon.type = j+1;
if (mls_setup_user_range(fromcon, user, &usercon))
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-27 2:22 ` KaiGai Kohei
@ 2007-09-27 2:43 ` KaiGai Kohei
2007-09-27 20:47 ` James Morris
0 siblings, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-27 2:43 UTC (permalink / raw)
To: Stephen Smalley
Cc: KaiGai Kohei, selinux, Paul Moore, Yuichi Nakamura, James Morris,
Eric Paris
KaiGai Kohei wrote:
>>> I think we have to conform to it, and if it makes it harder to read,
>>> possibly that suggests that we need to rework the code in some way.
>> I'm preparing another version of patch which does not contain any
>> "line over 80 characters" warning. Please wait for a while.
>
> The following part is the patch which does not contain any "line
> over 80 characters" warnings.
The following part is a result of diff between the previous patch
which contains 80-char warnings and the latest one without them.
I think it is better than I expected.
However, there are several ugly manner like as:
-+ c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
++ c_iter->startbit
++ = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
If both side of the formula is in a same line, the width of the line get overs
the 80-char limitation.
++ char *nm;
:
++ if (head != prev) {
++ nm = policydb.p_cat_val_to_name[prev];
++ len += strlen(nm) + 1;
++ }
If the temporary char * variable is named as "cat_name", the above longest
line overs 80-char limitation, so I named it as "nm".
This naming may be unclear for its purpose.
Thanks,
[kaigai@saba ~]$ diff -NU3 ebitmap-bitops.patch ebitmap-bitops.less-than-80char.patch
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
-index ce492a6..3a60186 100644
+index ce492a6..5643bdd 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
@@ -53,7 +59,7 @@
if (e_iter == NULL) {
*catmap = NULL;
-@@ -104,19 +110,21 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
+@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) {
@@ -66,18 +72,24 @@
- c_iter->startbit = e_iter->startbit &
- ~(NETLBL_CATMAP_SIZE - 1);
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
-+ unsigned int e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
++ unsigned int delta, e_startbit, c_endbit;
+
-+ if (e_startbit >= c_iter->startbit + NETLBL_CATMAP_SIZE) {
-+ c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
++ e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
++ c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
++ if (e_startbit >= c_endbit) {
++ c_iter->next
++ = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (c_iter->next == NULL)
+ goto netlbl_export_failure;
+ c_iter = c_iter->next;
-+ c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
++ c_iter->startbit
++ = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
-+ cmap_idx = (e_startbit - c_iter->startbit) / NETLBL_CATMAP_MAPSIZE;
-+ cmap_sft = (e_startbit - c_iter->startbit) % NETLBL_CATMAP_MAPSIZE;
-+ c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft;
++ delta = e_startbit - c_iter->startbit;
++ cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
++ cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
++ c_iter->bitmap[cmap_idx]
++ |= e_iter->maps[cmap_idx] << cmap_sft;
+ e_iter = e_iter->next;
}
- cmap_idx = (e_iter->startbit - c_iter->startbit) /
@@ -87,7 +99,7 @@
}
return 0;
-@@ -128,7 +136,7 @@ netlbl_export_failure:
+@@ -128,7 +142,7 @@ netlbl_export_failure:
/**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
@@ -96,7 +108,7 @@
* @catmap: the NetLabel category bitmap
*
* Description:
-@@ -142,36 +150,45 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
+@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap;
@@ -118,6 +130,7 @@
do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
- if (c_iter->bitmap[c_idx] == 0)
++ unsigned int delta;
+ u64 map = c_iter->bitmap[c_idx];
+
+ if (!map)
@@ -135,20 +148,24 @@
- e_iter->startbit = c_iter->startbit +
- NETLBL_CATMAP_MAPSIZE * c_idx;
- e_iter->map = c_iter->bitmap[c_idx];
-+ c_pos = c_iter->startbit + c_idx * NETLBL_CATMAP_MAPSIZE;
-+ if (!e_iter || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
++ c_pos = c_iter->startbit
++ + c_idx * NETLBL_CATMAP_MAPSIZE;
++ if (!e_iter
++ || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
+ e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+ if (!e_iter)
+ goto netlbl_import_failure;
-+ e_iter->startbit = c_pos - (c_pos % EBITMAP_SIZE);
++ e_iter->startbit
++ = c_pos - (c_pos % EBITMAP_SIZE);
+ if (emap_prev == NULL)
+ ebmap->node = e_iter;
+ else
+ emap_prev->next = e_iter;
+ emap_prev = e_iter;
+ }
-+ e_idx = (c_pos - e_iter->startbit) / EBITMAP_UNIT_SIZE;
-+ e_sft = (c_pos - e_iter->startbit) % EBITMAP_UNIT_SIZE;
++ delta = c_pos - e_iter->startbit;
++ e_idx = delta / EBITMAP_UNIT_SIZE;
++ e_sft = delta % EBITMAP_UNIT_SIZE;
+ while (map) {
+ e_iter->maps[e_idx++] |= map & (-1UL);
+ map >>= EBITMAP_UNIT_SIZE;
@@ -162,7 +179,7 @@
else
ebitmap_destroy(ebmap);
-@@ -186,6 +203,7 @@ netlbl_import_failure:
+@@ -186,6 +214,7 @@ netlbl_import_failure:
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
@@ -170,7 +187,7 @@
if (e1->highbit < e2->highbit)
return 0;
-@@ -197,8 +215,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
+@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next;
continue;
}
@@ -183,7 +200,7 @@
n1 = n1->next;
n2 = n2->next;
-@@ -219,12 +239,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
+@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node;
while (n && (n->startbit <= bit)) {
@@ -198,7 +215,7 @@
n = n->next;
}
-@@ -238,31 +254,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
+@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
@@ -222,9 +239,12 @@
- else
- e->highbit = 0;
- }
++ unsigned int s;
++
+ ebitmap_node_clr_bit(n, bit);
+
-+ if (find_first_bit(n->maps, EBITMAP_SIZE) < EBITMAP_SIZE)
++ s = find_first_bit(n->maps, EBITMAP_SIZE);
++ if (s < EBITMAP_SIZE)
+ return 0;
+
+ /* drop this node from the bitmap */
@@ -235,7 +255,8 @@
+ */
if (prev)
- prev->next = n->next;
-+ e->highbit = prev->startbit + EBITMAP_SIZE;
++ e->highbit = prev->startbit
++ + EBITMAP_SIZE;
else
- e->node = n->next;
-
@@ -250,7 +271,7 @@
}
return 0;
}
-@@ -277,12 +293,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
+@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new)
return -ENOMEM;
@@ -266,7 +287,7 @@
if (prev) {
new->next = prev->next;
-@@ -316,11 +332,11 @@ void ebitmap_destroy(struct ebitmap *e)
+@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
@@ -282,7 +303,7 @@
ebitmap_init(e);
-@@ -328,85 +344,86 @@ int ebitmap_read(struct ebitmap *e, void *fp)
+@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
@@ -354,13 +375,16 @@
+ }
+
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
-+ struct ebitmap_node *_n = kzalloc(sizeof(*_n), GFP_KERNEL);
++ struct ebitmap_node *_n;
++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
+ if (!_n) {
-+ printk(KERN_ERR "security: ebitmap: out of memory\n");
++ printk(KERN_ERR
++ "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
-+ _n->startbit = startbit - (startbit % EBITMAP_SIZE); /* round down */
++ /* round down */
++ _n->startbit = startbit - (startbit % EBITMAP_SIZE);
+ if (n) {
+ n->next = _n;
+ } else {
@@ -417,17 +441,18 @@
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
-index 1270e34..417053e 100644
+index 1270e34..e38a327 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
-@@ -16,14 +16,15 @@
+@@ -16,14 +16,16 @@
#include <net/netlabel.h>
-#define MAPTYPE u64 /* portion of bitmap in each node */
-#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
-#define MAPBIT 1ULL /* a bit in the node bitmap */
-+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
++#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
++ / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1ULL
@@ -441,7 +466,7 @@
};
struct ebitmap {
-@@ -34,11 +35,17 @@ struct ebitmap {
+@@ -34,11 +36,17 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
@@ -463,7 +488,7 @@
}
static inline void ebitmap_init(struct ebitmap *e)
-@@ -46,28 +53,65 @@ static inline void ebitmap_init(struct ebitmap *e)
+@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
@@ -542,56 +567,67 @@
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
-index 4a8bab2..27ef5eb 100644
+index 4a8bab2..9a11dea 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
-@@ -34,7 +34,7 @@
+@@ -34,7 +34,9 @@
*/
int mls_compute_context_len(struct context * context)
{
- int i, l, len, range;
+ int i, l, len, head, prev;
++ char *nm;
++ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
-@@ -42,31 +42,26 @@ int mls_compute_context_len(struct context * context)
+@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) {
- range = 0;
- len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
-
+- len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+-
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
--
-+ /* categories */
-+ head = -2;
-+ prev = -2;
-+ ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
-+ if (i - prev > 1) {
-+ /* one or more negative bits are skipped, at least. */
-+ if (head != prev)
-+ len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
- len += strlen(policydb.p_cat_val_to_name[i]) + 1;
++ int index_sens = context->range.level[l].sens;
++ len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
+
+- len += strlen(policydb.p_cat_val_to_name[i]) + 1;
- range++;
- } else {
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
- range = 0;
++ /* categories */
++ head = -2;
++ prev = -2;
++ e = &context->range.level[l].cat;
++ ebitmap_for_each_positive_bit(e, node, i) {
++ if (i - prev > 1) {
++ /* one or more negative bits are skipped */
++ if (head != prev) {
++ nm = policydb.p_cat_val_to_name[prev];
++ len += strlen(nm) + 1;
++ }
++ nm = policydb.p_cat_val_to_name[i];
++ len += strlen(nm) + 1;
+ head = i;
}
+ prev = i;
++ }
++ if (prev != head) {
++ nm = policydb.p_cat_val_to_name[prev];
++ len += strlen(nm) + 1;
}
- /* Handle case where last category is the end of range */
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
-
-+ if (prev != head)
-+ len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
- &context->range.level[1]))
@@ -599,16 +635,19 @@
break;
else
len++;
-@@ -85,7 +80,7 @@ void mls_sid_to_context(struct context *context,
+@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
+ void mls_sid_to_context(struct context *context,
char **scontext)
{
- char *scontextp;
+- char *scontextp;
- int i, l, range, wrote_sep;
++ char *scontextp, *nm;
+ int i, l, head, prev;
++ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
-@@ -97,61 +92,50 @@ void mls_sid_to_context(struct context *context,
+@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
scontextp++;
for (l = 0; l < 2; l++) {
@@ -640,9 +679,10 @@
- if (range > 2)
+ head = -2;
+ prev = -2;
-+ ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
++ e = &context->range.level[l].cat;
++ ebitmap_for_each_positive_bit(e, node, i) {
+ if (i - prev > 1) {
-+ /* one or more negative bits are skipped, at least. */
++ /* one or more negative bits are skipped */
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
@@ -651,16 +691,18 @@
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
-+ strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
-+ scontextp += strlen(scontextp);
++ nm = policydb.p_cat_val_to_name[prev];
++ strcpy(scontextp, nm);
++ scontextp += strlen(nm);
}
- range = 0;
+ if (prev < 0)
+ *scontextp++ = ':';
+ else
+ *scontextp++ = ',';
-+ strcpy(scontextp, policydb.p_cat_val_to_name[i]);
-+ scontextp += strlen(scontextp);
++ nm = policydb.p_cat_val_to_name[i];
++ strcpy(scontextp, nm);
++ scontextp += strlen(nm);
+ head = i;
}
+ prev = i;
@@ -677,8 +719,9 @@
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
-+ strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
-+ scontextp += strlen(scontextp);
++ nm = policydb.p_cat_val_to_name[prev];
++ strcpy(scontextp, nm);
++ scontextp += strlen(nm);
}
if (l == 0) {
@@ -694,7 +737,7 @@
}
}
-@@ -190,17 +174,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
+@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
@@ -721,7 +764,7 @@
}
}
-@@ -485,18 +467,16 @@ int mls_convert_context(struct policydb *oldp,
+@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-27 2:43 ` KaiGai Kohei
@ 2007-09-27 20:47 ` James Morris
2007-09-28 10:56 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: James Morris @ 2007-09-27 20:47 UTC (permalink / raw)
To: KaiGai Kohei
Cc: Stephen Smalley, selinux, Paul Moore, Yuichi Nakamura, Eric Paris
On Thu, 27 Sep 2007, KaiGai Kohei wrote:
> However, there are several ugly manner like as:
>
> -+ c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
> ++ c_iter->startbit
> ++ = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
> If both side of the formula is in a same line, the width of the line get overs
> the 80-char limitation.
This is pretty common, so don't worry.
>
>
> ++ char *nm;
> :
> ++ if (head != prev) {
> ++ nm = policydb.p_cat_val_to_name[prev];
> ++ len += strlen(nm) + 1;
> ++ }
>
> If the temporary char * variable is named as "cat_name", the above longest
> line overs 80-char limitation, so I named it as "nm".
> This naming may be unclear for its purpose.
I think it's better to keep the 80 column limit here.
> ++ struct ebitmap_node *_n;
> ++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
Leading underscores are usually used to indicate that core code is not
supposed to use the symbol. Please change it to not have a leading
underscore. 'tmp' or 'n2' is probably ok.
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-27 20:47 ` James Morris
@ 2007-09-28 10:56 ` KaiGai Kohei
2007-09-28 14:47 ` Stephen Smalley
0 siblings, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-28 10:56 UTC (permalink / raw)
To: James Morris
Cc: Stephen Smalley, selinux, Paul Moore, Yuichi Nakamura, Eric Paris
James Morris wrote:
>> ++ struct ebitmap_node *_n;
>> ++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
>
> Leading underscores are usually used to indicate that core code is not
> supposed to use the symbol. Please change it to not have a leading
> underscore. 'tmp' or 'n2' is probably ok.
OK, I replaced all of '_n' by 'tmp'.
Rest of the part in the following patch is same as the previous one.
Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
[PATCH] Improve SELinux performance when AVC misses.
* We add ebitmap_for_each_positive_bit() which enables to walk on
any positive bit on the given ebitmap, to improve its performance
using common bit-operations defined in linux/bitops.h.
In the previous version, this logic was implemented using a combination
of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
in performance aspect.
This logic is most frequestly used to compute a new AVC entry,
so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get
suitable for using find_next_bit() which is fasted than iteration of
shift and logical operation, and to maximize memory usage allocated
from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation
in ss/service.c and ss/mls.c. Some of related implementation are
changed, however, there is no incompatibility with the previous
version.
* The width of any new line are less or equal than 80-chars.
The following benchmark shows the effect of this patch, when we
access many files which have different security context one after
another. The number is more than /selinux/avc/cache_threshold, so
any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s]
STD: 0.265 0.019
------------------------------------------
1st: 22.558 [s] 8.786 [s]
2nd: 22.458 [s] 8.750 [s]
3rd: 22.478 [s] 8.754 [s]
4th: 22.724 [s] 8.745 [s]
5th: 22.918 [s] 8.748 [s]
6th: 22.905 [s] 8.764 [s]
7th: 23.238 [s] 8.726 [s]
8th: 22.822 [s] 8.729 [s]
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
---
security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++-----------------
security/selinux/ss/ebitmap.h | 87 ++++++++++---
security/selinux/ss/mls.c | 156 +++++++++++------------
security/selinux/ss/services.c | 16 +--
4 files changed, 303 insertions(+), 237 deletions(-)
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ce492a6..ae44c0c 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/
+/*
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Applied standard bit operations to improve bitmap scanning.
+ */
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
n2 = e2->node;
while (n1 && n2 &&
(n1->startbit == n2->startbit) &&
- (n1->map == n2->map)) {
+ !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
n1 = n1->next;
n2 = n2->next;
}
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
return -ENOMEM;
}
new->startbit = n->startbit;
- new->map = n->map;
+ memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
new->next = NULL;
if (prev)
prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
{
struct ebitmap_node *e_iter = ebmap->node;
struct netlbl_lsm_secattr_catmap *c_iter;
- u32 cmap_idx;
+ u32 cmap_idx, cmap_sft;
+ int i;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
if (e_iter == NULL) {
*catmap = NULL;
@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) {
- if (e_iter->startbit >=
- (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
- c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
- if (c_iter->next == NULL)
- goto netlbl_export_failure;
- c_iter = c_iter->next;
- c_iter->startbit = e_iter->startbit &
- ~(NETLBL_CATMAP_SIZE - 1);
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+ unsigned int delta, e_startbit, c_endbit;
+
+ e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
+ c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
+ if (e_startbit >= c_endbit) {
+ c_iter->next
+ = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (c_iter->next == NULL)
+ goto netlbl_export_failure;
+ c_iter = c_iter->next;
+ c_iter->startbit
+ = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
+ delta = e_startbit - c_iter->startbit;
+ cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
+ cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
+ c_iter->bitmap[cmap_idx]
+ |= e_iter->maps[cmap_idx] << cmap_sft;
+ e_iter = e_iter->next;
}
- cmap_idx = (e_iter->startbit - c_iter->startbit) /
- NETLBL_CATMAP_MAPSIZE;
- c_iter->bitmap[cmap_idx] = e_iter->map;
- e_iter = e_iter->next;
}
return 0;
@@ -128,7 +142,7 @@ netlbl_export_failure:
/**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
- * @ebmap: the ebitmap to export
+ * @ebmap: the ebitmap to import
* @catmap: the NetLabel category bitmap
*
* Description:
@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap;
- u32 c_idx;
+ u32 c_idx, c_pos, e_idx, e_sft;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
- if (c_iter->bitmap[c_idx] == 0)
+ unsigned int delta;
+ u64 map = c_iter->bitmap[c_idx];
+
+ if (!map)
continue;
- e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
- if (e_iter == NULL)
- goto netlbl_import_failure;
- if (emap_prev == NULL)
- ebmap->node = e_iter;
- else
- emap_prev->next = e_iter;
- emap_prev = e_iter;
-
- e_iter->startbit = c_iter->startbit +
- NETLBL_CATMAP_MAPSIZE * c_idx;
- e_iter->map = c_iter->bitmap[c_idx];
+ c_pos = c_iter->startbit
+ + c_idx * NETLBL_CATMAP_MAPSIZE;
+ if (!e_iter
+ || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
+ e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+ if (!e_iter)
+ goto netlbl_import_failure;
+ e_iter->startbit
+ = c_pos - (c_pos % EBITMAP_SIZE);
+ if (emap_prev == NULL)
+ ebmap->node = e_iter;
+ else
+ emap_prev->next = e_iter;
+ emap_prev = e_iter;
+ }
+ delta = c_pos - e_iter->startbit;
+ e_idx = delta / EBITMAP_UNIT_SIZE;
+ e_sft = delta % EBITMAP_UNIT_SIZE;
+ while (map) {
+ e_iter->maps[e_idx++] |= map & (-1UL);
+ map >>= EBITMAP_UNIT_SIZE;
+ }
}
c_iter = c_iter->next;
} while (c_iter != NULL);
if (e_iter != NULL)
- ebmap->highbit = e_iter->startbit + MAPSIZE;
+ ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
else
ebitmap_destroy(ebmap);
@@ -186,6 +214,7 @@ netlbl_import_failure:
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
+ int i;
if (e1->highbit < e2->highbit)
return 0;
@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next;
continue;
}
- if ((n1->map & n2->map) != n2->map)
- return 0;
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+ if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
+ return 0;
+ }
n1 = n1->next;
n2 = n2->next;
@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node;
while (n && (n->startbit <= bit)) {
- if ((n->startbit + MAPSIZE) > bit) {
- if (n->map & (MAPBIT << (bit - n->startbit)))
- return 1;
- else
- return 0;
- }
+ if ((n->startbit + EBITMAP_SIZE) > bit)
+ return ebitmap_node_get_bit(n, bit);
n = n->next;
}
@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
- if ((n->startbit + MAPSIZE) > bit) {
+ if ((n->startbit + EBITMAP_SIZE) > bit) {
if (value) {
- n->map |= (MAPBIT << (bit - n->startbit));
+ ebitmap_node_set_bit(n, bit);
} else {
- n->map &= ~(MAPBIT << (bit - n->startbit));
- if (!n->map) {
- /* drop this node from the bitmap */
-
- if (!n->next) {
- /*
- * this was the highest map
- * within the bitmap
- */
- if (prev)
- e->highbit = prev->startbit + MAPSIZE;
- else
- e->highbit = 0;
- }
+ unsigned int s;
+
+ ebitmap_node_clr_bit(n, bit);
+
+ s = find_first_bit(n->maps, EBITMAP_SIZE);
+ if (s < EBITMAP_SIZE)
+ return 0;
+
+ /* drop this node from the bitmap */
+ if (!n->next) {
+ /*
+ * this was the highest map
+ * within the bitmap
+ */
if (prev)
- prev->next = n->next;
+ e->highbit = prev->startbit
+ + EBITMAP_SIZE;
else
- e->node = n->next;
-
- kfree(n);
+ e->highbit = 0;
}
+ if (prev)
+ prev->next = n->next;
+ else
+ e->node = n->next;
+ kfree(n);
}
return 0;
}
@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new)
return -ENOMEM;
- new->startbit = bit & ~(MAPSIZE - 1);
- new->map = (MAPBIT << (bit - new->startbit));
+ new->startbit = bit - (bit % EBITMAP_SIZE);
+ ebitmap_node_set_bit(new, bit);
if (!n)
/* this node will be the highest map within the bitmap */
- e->highbit = new->startbit + MAPSIZE;
+ e->highbit = new->startbit + EBITMAP_SIZE;
if (prev) {
new->next = prev->next;
@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
- int rc;
- struct ebitmap_node *n, *l;
+ struct ebitmap_node *n = NULL;
+ u32 mapunit, count, startbit, index;
+ u64 map;
__le32 buf[3];
- u32 mapsize, count, i;
- __le64 map;
+ int rc, i;
ebitmap_init(e);
@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
- mapsize = le32_to_cpu(buf[0]);
+ mapunit = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]);
- if (mapsize != MAPSIZE) {
+ if (mapunit != sizeof(u64) * 8) {
printk(KERN_ERR "security: ebitmap: map size %u does not "
- "match my size %Zd (high bit was %d)\n", mapsize,
- MAPSIZE, e->highbit);
+ "match my size %Zd (high bit was %d)\n",
+ mapunit, sizeof(u64) * 8, e->highbit);
goto bad;
}
+
+ /* round up e->highbit */
+ e->highbit += EBITMAP_SIZE - 1;
+ e->highbit -= (e->highbit % EBITMAP_SIZE);
+
if (!e->highbit) {
e->node = NULL;
goto ok;
}
- if (e->highbit & (MAPSIZE - 1)) {
- printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
- "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
- goto bad;
- }
- l = NULL;
+
for (i = 0; i < count; i++) {
- rc = next_entry(buf, fp, sizeof(u32));
+ rc = next_entry(&startbit, fp, sizeof(u32));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad;
}
- n = kzalloc(sizeof(*n), GFP_KERNEL);
- if (!n) {
- printk(KERN_ERR "security: ebitmap: out of memory\n");
- rc = -ENOMEM;
- goto bad;
- }
-
- n->startbit = le32_to_cpu(buf[0]);
+ startbit = le32_to_cpu(startbit);
- if (n->startbit & (MAPSIZE - 1)) {
+ if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map size (%Zd)\n",
- n->startbit, MAPSIZE);
- goto bad_free;
+ "not a multiple of the map unit size (%Zd)\n",
+ startbit, mapunit);
+ goto bad;
}
- if (n->startbit > (e->highbit - MAPSIZE)) {
+ if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%Zd)\n",
- n->startbit, (e->highbit - MAPSIZE));
- goto bad_free;
+ startbit, (e->highbit - mapunit));
+ goto bad;
+ }
+
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
+ struct ebitmap_node *tmp;
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp) {
+ printk(KERN_ERR
+ "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ /* round down */
+ tmp->startbit = startbit - (startbit % EBITMAP_SIZE);
+ if (n) {
+ n->next = tmp;
+ } else {
+ e->node = tmp;
+ }
+ n = tmp;
+ } else if (startbit <= n->startbit) {
+ printk(KERN_ERR "security: ebitmap: start bit %d"
+ " comes after start bit %d\n",
+ startbit, n->startbit);
+ goto bad;
}
+
rc = next_entry(&map, fp, sizeof(u64));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
- goto bad_free;
+ goto bad;
}
- n->map = le64_to_cpu(map);
+ map = le64_to_cpu(map);
- if (!n->map) {
- printk(KERN_ERR "security: ebitmap: null map in "
- "ebitmap (startbit %d)\n", n->startbit);
- goto bad_free;
+ index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
+ while (map) {
+ n->maps[index] = map & (-1UL);
+ map = map >> EBITMAP_UNIT_SIZE;
+ index++;
}
- if (l) {
- if (n->startbit <= l->startbit) {
- printk(KERN_ERR "security: ebitmap: start "
- "bit %d comes after start bit %d\n",
- n->startbit, l->startbit);
- goto bad_free;
- }
- l->next = n;
- } else
- e->node = n;
-
- l = n;
}
-
ok:
rc = 0;
out:
return rc;
-bad_free:
- kfree(n);
bad:
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 1270e34..e38a327 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -16,14 +16,16 @@
#include <net/netlabel.h>
-#define MAPTYPE u64 /* portion of bitmap in each node */
-#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
-#define MAPBIT 1ULL /* a bit in the node bitmap */
+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
+ / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1ULL
struct ebitmap_node {
- u32 startbit; /* starting position in the total bitmap */
- MAPTYPE map; /* this node's portion of the bitmap */
struct ebitmap_node *next;
+ unsigned long maps[EBITMAP_UNIT_NUMS];
+ u32 startbit;
};
struct ebitmap {
@@ -34,11 +36,17 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
-static inline unsigned int ebitmap_start(struct ebitmap *e,
- struct ebitmap_node **n)
+static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+ struct ebitmap_node **n)
{
- *n = e->node;
- return ebitmap_startbit(e);
+ unsigned int ofs;
+
+ for (*n = e->node; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return (*n)->startbit + ofs;
+ }
+ return ebitmap_length(e);
}
static inline void ebitmap_init(struct ebitmap *e)
@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
-static inline unsigned int ebitmap_next(struct ebitmap_node **n,
- unsigned int bit)
+static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
+ struct ebitmap_node **n,
+ unsigned int bit)
{
- if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
- (*n)->next) {
- *n = (*n)->next;
- return (*n)->startbit;
- }
+ unsigned int ofs;
+
+ ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
- return (bit+1);
+ for (*n = (*n)->next; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+ }
+ return ebitmap_length(e);
}
-static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
+#define EBITMAP_NODE_INDEX(node, bit) \
+ (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
+#define EBITMAP_NODE_OFFSET(node, bit) \
+ (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
unsigned int bit)
{
- if (n->map & (MAPBIT << (bit - n->startbit)))
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ if ((n->maps[index] & (EBITMAP_BIT << ofs)))
return 1;
return 0;
}
-#define ebitmap_for_each_bit(e, n, bit) \
- for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for (bit = ebitmap_start_positive(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2..9a11dea 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -34,7 +34,9 @@
*/
int mls_compute_context_len(struct context * context)
{
- int i, l, len, range;
+ int i, l, len, head, prev;
+ char *nm;
+ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) {
- range = 0;
- len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
-
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
+ int index_sens = context->range.level[l].sens;
+ len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
- len += strlen(policydb.p_cat_val_to_name[i]) + 1;
- range++;
- } else {
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
- range = 0;
+ /* categories */
+ head = -2;
+ prev = -2;
+ e = &context->range.level[l].cat;
+ ebitmap_for_each_positive_bit(e, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped */
+ if (head != prev) {
+ nm = policydb.p_cat_val_to_name[prev];
+ len += strlen(nm) + 1;
+ }
+ nm = policydb.p_cat_val_to_name[i];
+ len += strlen(nm) + 1;
+ head = i;
}
+ prev = i;
+ }
+ if (prev != head) {
+ nm = policydb.p_cat_val_to_name[prev];
+ len += strlen(nm) + 1;
}
- /* Handle case where last category is the end of range */
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
-
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
- &context->range.level[1]))
+ &context->range.level[1]))
break;
else
len++;
@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
void mls_sid_to_context(struct context *context,
char **scontext)
{
- char *scontextp;
- int i, l, range, wrote_sep;
+ char *scontextp, *nm;
+ int i, l, head, prev;
+ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
scontextp++;
for (l = 0; l < 2; l++) {
- range = 0;
- wrote_sep = 0;
strcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
- scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+ scontextp += strlen(scontextp);
/* categories */
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
-
- if (!wrote_sep) {
- *scontextp++ = ':';
- wrote_sep = 1;
- } else
- *scontextp++ = ',';
- strcpy(scontextp, policydb.p_cat_val_to_name[i]);
- scontextp += strlen(policydb.p_cat_val_to_name[i]);
- range++;
- } else {
- if (range > 1) {
- if (range > 2)
+ head = -2;
+ prev = -2;
+ e = &context->range.level[l].cat;
+ ebitmap_for_each_positive_bit(e, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped */
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ nm = policydb.p_cat_val_to_name[prev];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
}
- range = 0;
+ if (prev < 0)
+ *scontextp++ = ':';
+ else
+ *scontextp++ = ',';
+ nm = policydb.p_cat_val_to_name[i];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
+ head = i;
}
+ prev = i;
}
- /* Handle case where last category is the end of range */
- if (range > 1) {
- if (range > 2)
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ nm = policydb.p_cat_val_to_name[prev];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
}
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
&context->range.level[1]))
break;
- else {
- *scontextp = '-';
- scontextp++;
- }
+ else
+ *scontextp++ = '-';
}
}
@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (i > p->p_cats.nprim)
- return 0;
- if (!ebitmap_get_bit(&levdatum->level->cat, i))
- /*
- * Category may not be associated with
- * sensitivity in low level.
- */
- return 0;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
+ /*
+ * Category may not be associated with
+ * sensitivity in low level.
+ */
+ return 0;
}
}
@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- int rc;
-
- catdatum = hashtab_search(newp->p_cats.table,
- oldp->p_cat_val_to_name[i]);
- if (!catdatum)
- return -EINVAL;
- rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
- if (rc)
- return rc;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ int rc;
+
+ catdatum = hashtab_search(newp->p_cats.table,
+ oldp->p_cat_val_to_name[i]);
+ if (!catdatum)
+ return -EINVAL;
+ rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
+ if (rc)
+ return rc;
}
ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 6100fc0..19be935 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext,
avkey.specified = AVTAB_AV;
sattr = &policydb.type_attr_map[scontext->type - 1];
tattr = &policydb.type_attr_map[tcontext->type - 1];
- ebitmap_for_each_bit(sattr, snode, i) {
- if (!ebitmap_node_get_bit(snode, i))
- continue;
- ebitmap_for_each_bit(tattr, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(sattr, snode, i) {
+ ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1;
avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid,
goto out_unlock;
}
- ebitmap_for_each_bit(&user->roles, rnode, i) {
- if (!ebitmap_node_get_bit(rnode, i))
- continue;
+ ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
role = policydb.role_val_to_struct[i];
usercon.role = i+1;
- ebitmap_for_each_bit(&role->types, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(&role->types, tnode, j) {
usercon.type = j+1;
if (mls_setup_user_range(fromcon, user, &usercon))
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-28 10:56 ` KaiGai Kohei
@ 2007-09-28 14:47 ` Stephen Smalley
2007-09-28 17:20 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: Stephen Smalley @ 2007-09-28 14:47 UTC (permalink / raw)
To: KaiGai Kohei
Cc: James Morris, selinux, Paul Moore, Yuichi Nakamura, Eric Paris
On Fri, 2007-09-28 at 19:56 +0900, KaiGai Kohei wrote:
> James Morris wrote:
> >> ++ struct ebitmap_node *_n;
> >> ++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
> >
> > Leading underscores are usually used to indicate that core code is not
> > supposed to use the symbol. Please change it to not have a leading
> > underscore. 'tmp' or 'n2' is probably ok.
>
> OK, I replaced all of '_n' by 'tmp'.
> Rest of the part in the following patch is same as the previous one.
Seems to be damaged, or at least doesn't apply for me. What is it
relative to?
>
> Thanks,
> --
> OSS Platform Development Division, NEC
> KaiGai Kohei <kaigai@ak.jp.nec.com>
>
> [PATCH] Improve SELinux performance when AVC misses.
>
> * We add ebitmap_for_each_positive_bit() which enables to walk on
> any positive bit on the given ebitmap, to improve its performance
> using common bit-operations defined in linux/bitops.h.
> In the previous version, this logic was implemented using a combination
> of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
> in performance aspect.
> This logic is most frequestly used to compute a new AVC entry,
> so this patch can improve SELinux performance when AVC misses are happen.
> * struct ebitmap_node is redefined as an array of "unsigned long", to get
> suitable for using find_next_bit() which is fasted than iteration of
> shift and logical operation, and to maximize memory usage allocated
> from general purpose slab.
> * Any ebitmap_for_each_bit() are repleced by the new implementation
> in ss/service.c and ss/mls.c. Some of related implementation are
> changed, however, there is no incompatibility with the previous
> version.
> * The width of any new line are less or equal than 80-chars.
>
> The following benchmark shows the effect of this patch, when we
> access many files which have different security context one after
> another. The number is more than /selinux/avc/cache_threshold, so
> any access always causes AVC misses.
>
> selinux-2.6 selinux-2.6-ebitmap
> AVG: 22.763 [s] 8.750 [s]
> STD: 0.265 0.019
> ------------------------------------------
> 1st: 22.558 [s] 8.786 [s]
> 2nd: 22.458 [s] 8.750 [s]
> 3rd: 22.478 [s] 8.754 [s]
> 4th: 22.724 [s] 8.745 [s]
> 5th: 22.918 [s] 8.748 [s]
> 6th: 22.905 [s] 8.764 [s]
> 7th: 23.238 [s] 8.726 [s]
> 8th: 22.822 [s] 8.729 [s]
>
> Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
> ---
> security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++-----------------
> security/selinux/ss/ebitmap.h | 87 ++++++++++---
> security/selinux/ss/mls.c | 156 +++++++++++------------
> security/selinux/ss/services.c | 16 +--
> 4 files changed, 303 insertions(+), 237 deletions(-)
>
> diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
> index ce492a6..ae44c0c 100644
> --- a/security/selinux/ss/ebitmap.c
> +++ b/security/selinux/ss/ebitmap.c
> @@ -10,6 +10,10 @@
> *
> * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
> */
> +/*
> + * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
> + * Applied standard bit operations to improve bitmap scanning.
> + */
>
> #include <linux/kernel.h>
> #include <linux/slab.h>
> @@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
> n2 = e2->node;
> while (n1 && n2 &&
> (n1->startbit == n2->startbit) &&
> - (n1->map == n2->map)) {
> + !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
> n1 = n1->next;
> n2 = n2->next;
> }
> @@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
> return -ENOMEM;
> }
> new->startbit = n->startbit;
> - new->map = n->map;
> + memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
> new->next = NULL;
> if (prev)
> prev->next = new;
> @@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
> {
> struct ebitmap_node *e_iter = ebmap->node;
> struct netlbl_lsm_secattr_catmap *c_iter;
> - u32 cmap_idx;
> + u32 cmap_idx, cmap_sft;
> + int i;
>
> - /* This function is a much simpler because SELinux's MAPTYPE happens
> - * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
> - * changed from a u64 this function will most likely need to be changed
> - * as well. It's not ideal but I think the tradeoff in terms of
> - * neatness and speed is worth it. */
> + /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
> + * however, it is not always compatible with an array of unsigned long
> + * in ebitmap_node.
> + * In addition, you should pay attention the following implementation
> + * assumes unsigned long has a width equal with or less than 64-bit.
> + */
>
> if (e_iter == NULL) {
> *catmap = NULL;
> @@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
> c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
>
> while (e_iter != NULL) {
> - if (e_iter->startbit >=
> - (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
> - c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
> - if (c_iter->next == NULL)
> - goto netlbl_export_failure;
> - c_iter = c_iter->next;
> - c_iter->startbit = e_iter->startbit &
> - ~(NETLBL_CATMAP_SIZE - 1);
> + for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
> + unsigned int delta, e_startbit, c_endbit;
> +
> + e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
> + c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
> + if (e_startbit >= c_endbit) {
> + c_iter->next
> + = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
> + if (c_iter->next == NULL)
> + goto netlbl_export_failure;
> + c_iter = c_iter->next;
> + c_iter->startbit
> + = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
> + }
> + delta = e_startbit - c_iter->startbit;
> + cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
> + cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
> + c_iter->bitmap[cmap_idx]
> + |= e_iter->maps[cmap_idx] << cmap_sft;
> + e_iter = e_iter->next;
> }
> - cmap_idx = (e_iter->startbit - c_iter->startbit) /
> - NETLBL_CATMAP_MAPSIZE;
> - c_iter->bitmap[cmap_idx] = e_iter->map;
> - e_iter = e_iter->next;
> }
>
> return 0;
> @@ -128,7 +142,7 @@ netlbl_export_failure:
>
> /**
> * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
> - * @ebmap: the ebitmap to export
> + * @ebmap: the ebitmap to import
> * @catmap: the NetLabel category bitmap
> *
> * Description:
> @@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
> struct ebitmap_node *e_iter = NULL;
> struct ebitmap_node *emap_prev = NULL;
> struct netlbl_lsm_secattr_catmap *c_iter = catmap;
> - u32 c_idx;
> + u32 c_idx, c_pos, e_idx, e_sft;
>
> - /* This function is a much simpler because SELinux's MAPTYPE happens
> - * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
> - * changed from a u64 this function will most likely need to be changed
> - * as well. It's not ideal but I think the tradeoff in terms of
> - * neatness and speed is worth it. */
> + /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
> + * however, it is not always compatible with an array of unsigned long
> + * in ebitmap_node.
> + * In addition, you should pay attention the following implementation
> + * assumes unsigned long has a width equal with or less than 64-bit.
> + */
>
> do {
> for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
> - if (c_iter->bitmap[c_idx] == 0)
> + unsigned int delta;
> + u64 map = c_iter->bitmap[c_idx];
> +
> + if (!map)
> continue;
>
> - e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
> - if (e_iter == NULL)
> - goto netlbl_import_failure;
> - if (emap_prev == NULL)
> - ebmap->node = e_iter;
> - else
> - emap_prev->next = e_iter;
> - emap_prev = e_iter;
> -
> - e_iter->startbit = c_iter->startbit +
> - NETLBL_CATMAP_MAPSIZE * c_idx;
> - e_iter->map = c_iter->bitmap[c_idx];
> + c_pos = c_iter->startbit
> + + c_idx * NETLBL_CATMAP_MAPSIZE;
> + if (!e_iter
> + || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
> + e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
> + if (!e_iter)
> + goto netlbl_import_failure;
> + e_iter->startbit
> + = c_pos - (c_pos % EBITMAP_SIZE);
> + if (emap_prev == NULL)
> + ebmap->node = e_iter;
> + else
> + emap_prev->next = e_iter;
> + emap_prev = e_iter;
> + }
> + delta = c_pos - e_iter->startbit;
> + e_idx = delta / EBITMAP_UNIT_SIZE;
> + e_sft = delta % EBITMAP_UNIT_SIZE;
> + while (map) {
> + e_iter->maps[e_idx++] |= map & (-1UL);
> + map >>= EBITMAP_UNIT_SIZE;
> + }
> }
> c_iter = c_iter->next;
> } while (c_iter != NULL);
> if (e_iter != NULL)
> - ebmap->highbit = e_iter->startbit + MAPSIZE;
> + ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
> else
> ebitmap_destroy(ebmap);
>
> @@ -186,6 +214,7 @@ netlbl_import_failure:
> int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
> {
> struct ebitmap_node *n1, *n2;
> + int i;
>
> if (e1->highbit < e2->highbit)
> return 0;
> @@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
> n1 = n1->next;
> continue;
> }
> - if ((n1->map & n2->map) != n2->map)
> - return 0;
> + for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
> + if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
> + return 0;
> + }
>
> n1 = n1->next;
> n2 = n2->next;
> @@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
>
> n = e->node;
> while (n && (n->startbit <= bit)) {
> - if ((n->startbit + MAPSIZE) > bit) {
> - if (n->map & (MAPBIT << (bit - n->startbit)))
> - return 1;
> - else
> - return 0;
> - }
> + if ((n->startbit + EBITMAP_SIZE) > bit)
> + return ebitmap_node_get_bit(n, bit);
> n = n->next;
> }
>
> @@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
> prev = NULL;
> n = e->node;
> while (n && n->startbit <= bit) {
> - if ((n->startbit + MAPSIZE) > bit) {
> + if ((n->startbit + EBITMAP_SIZE) > bit) {
> if (value) {
> - n->map |= (MAPBIT << (bit - n->startbit));
> + ebitmap_node_set_bit(n, bit);
> } else {
> - n->map &= ~(MAPBIT << (bit - n->startbit));
> - if (!n->map) {
> - /* drop this node from the bitmap */
> -
> - if (!n->next) {
> - /*
> - * this was the highest map
> - * within the bitmap
> - */
> - if (prev)
> - e->highbit = prev->startbit + MAPSIZE;
> - else
> - e->highbit = 0;
> - }
> + unsigned int s;
> +
> + ebitmap_node_clr_bit(n, bit);
> +
> + s = find_first_bit(n->maps, EBITMAP_SIZE);
> + if (s < EBITMAP_SIZE)
> + return 0;
> +
> + /* drop this node from the bitmap */
> + if (!n->next) {
> + /*
> + * this was the highest map
> + * within the bitmap
> + */
> if (prev)
> - prev->next = n->next;
> + e->highbit = prev->startbit
> + + EBITMAP_SIZE;
> else
> - e->node = n->next;
> -
> - kfree(n);
> + e->highbit = 0;
> }
> + if (prev)
> + prev->next = n->next;
> + else
> + e->node = n->next;
> + kfree(n);
> }
> return 0;
> }
> @@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
> if (!new)
> return -ENOMEM;
>
> - new->startbit = bit & ~(MAPSIZE - 1);
> - new->map = (MAPBIT << (bit - new->startbit));
> + new->startbit = bit - (bit % EBITMAP_SIZE);
> + ebitmap_node_set_bit(new, bit);
>
> if (!n)
> /* this node will be the highest map within the bitmap */
> - e->highbit = new->startbit + MAPSIZE;
> + e->highbit = new->startbit + EBITMAP_SIZE;
>
> if (prev) {
> new->next = prev->next;
> @@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
>
> int ebitmap_read(struct ebitmap *e, void *fp)
> {
> - int rc;
> - struct ebitmap_node *n, *l;
> + struct ebitmap_node *n = NULL;
> + u32 mapunit, count, startbit, index;
> + u64 map;
> __le32 buf[3];
> - u32 mapsize, count, i;
> - __le64 map;
> + int rc, i;
>
> ebitmap_init(e);
>
> @@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
> if (rc < 0)
> goto out;
>
> - mapsize = le32_to_cpu(buf[0]);
> + mapunit = le32_to_cpu(buf[0]);
> e->highbit = le32_to_cpu(buf[1]);
> count = le32_to_cpu(buf[2]);
>
> - if (mapsize != MAPSIZE) {
> + if (mapunit != sizeof(u64) * 8) {
> printk(KERN_ERR "security: ebitmap: map size %u does not "
> - "match my size %Zd (high bit was %d)\n", mapsize,
> - MAPSIZE, e->highbit);
> + "match my size %Zd (high bit was %d)\n",
> + mapunit, sizeof(u64) * 8, e->highbit);
> goto bad;
> }
> +
> + /* round up e->highbit */
> + e->highbit += EBITMAP_SIZE - 1;
> + e->highbit -= (e->highbit % EBITMAP_SIZE);
> +
> if (!e->highbit) {
> e->node = NULL;
> goto ok;
> }
> - if (e->highbit & (MAPSIZE - 1)) {
> - printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
> - "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
> - goto bad;
> - }
> - l = NULL;
> +
> for (i = 0; i < count; i++) {
> - rc = next_entry(buf, fp, sizeof(u32));
> + rc = next_entry(&startbit, fp, sizeof(u32));
> if (rc < 0) {
> printk(KERN_ERR "security: ebitmap: truncated map\n");
> goto bad;
> }
> - n = kzalloc(sizeof(*n), GFP_KERNEL);
> - if (!n) {
> - printk(KERN_ERR "security: ebitmap: out of memory\n");
> - rc = -ENOMEM;
> - goto bad;
> - }
> -
> - n->startbit = le32_to_cpu(buf[0]);
> + startbit = le32_to_cpu(startbit);
>
> - if (n->startbit & (MAPSIZE - 1)) {
> + if (startbit & (mapunit - 1)) {
> printk(KERN_ERR "security: ebitmap start bit (%d) is "
> - "not a multiple of the map size (%Zd)\n",
> - n->startbit, MAPSIZE);
> - goto bad_free;
> + "not a multiple of the map unit size (%Zd)\n",
> + startbit, mapunit);
> + goto bad;
> }
> - if (n->startbit > (e->highbit - MAPSIZE)) {
> + if (startbit > e->highbit - mapunit) {
> printk(KERN_ERR "security: ebitmap start bit (%d) is "
> "beyond the end of the bitmap (%Zd)\n",
> - n->startbit, (e->highbit - MAPSIZE));
> - goto bad_free;
> + startbit, (e->highbit - mapunit));
> + goto bad;
> + }
> +
> + if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
> + struct ebitmap_node *tmp;
> + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
> + if (!tmp) {
> + printk(KERN_ERR
> + "security: ebitmap: out of memory\n");
> + rc = -ENOMEM;
> + goto bad;
> + }
> + /* round down */
> + tmp->startbit = startbit - (startbit % EBITMAP_SIZE);
> + if (n) {
> + n->next = tmp;
> + } else {
> + e->node = tmp;
> + }
> + n = tmp;
> + } else if (startbit <= n->startbit) {
> + printk(KERN_ERR "security: ebitmap: start bit %d"
> + " comes after start bit %d\n",
> + startbit, n->startbit);
> + goto bad;
> }
> +
> rc = next_entry(&map, fp, sizeof(u64));
> if (rc < 0) {
> printk(KERN_ERR "security: ebitmap: truncated map\n");
> - goto bad_free;
> + goto bad;
> }
> - n->map = le64_to_cpu(map);
> + map = le64_to_cpu(map);
>
> - if (!n->map) {
> - printk(KERN_ERR "security: ebitmap: null map in "
> - "ebitmap (startbit %d)\n", n->startbit);
> - goto bad_free;
> + index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
> + while (map) {
> + n->maps[index] = map & (-1UL);
> + map = map >> EBITMAP_UNIT_SIZE;
> + index++;
> }
> - if (l) {
> - if (n->startbit <= l->startbit) {
> - printk(KERN_ERR "security: ebitmap: start "
> - "bit %d comes after start bit %d\n",
> - n->startbit, l->startbit);
> - goto bad_free;
> - }
> - l->next = n;
> - } else
> - e->node = n;
> -
> - l = n;
> }
> -
> ok:
> rc = 0;
> out:
> return rc;
> -bad_free:
> - kfree(n);
> bad:
> if (!rc)
> rc = -EINVAL;
> diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
> index 1270e34..e38a327 100644
> --- a/security/selinux/ss/ebitmap.h
> +++ b/security/selinux/ss/ebitmap.h
> @@ -16,14 +16,16 @@
>
> #include <net/netlabel.h>
>
> -#define MAPTYPE u64 /* portion of bitmap in each node */
> -#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
> -#define MAPBIT 1ULL /* a bit in the node bitmap */
> +#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
> + / sizeof(unsigned long))
> +#define EBITMAP_UNIT_SIZE BITS_PER_LONG
> +#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
> +#define EBITMAP_BIT 1ULL
>
> struct ebitmap_node {
> - u32 startbit; /* starting position in the total bitmap */
> - MAPTYPE map; /* this node's portion of the bitmap */
> struct ebitmap_node *next;
> + unsigned long maps[EBITMAP_UNIT_NUMS];
> + u32 startbit;
> };
>
> struct ebitmap {
> @@ -34,11 +36,17 @@ struct ebitmap {
> #define ebitmap_length(e) ((e)->highbit)
> #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
>
> -static inline unsigned int ebitmap_start(struct ebitmap *e,
> - struct ebitmap_node **n)
> +static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
> + struct ebitmap_node **n)
> {
> - *n = e->node;
> - return ebitmap_startbit(e);
> + unsigned int ofs;
> +
> + for (*n = e->node; *n; *n = (*n)->next) {
> + ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
> + if (ofs < EBITMAP_SIZE)
> + return (*n)->startbit + ofs;
> + }
> + return ebitmap_length(e);
> }
>
> static inline void ebitmap_init(struct ebitmap *e)
> @@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
> memset(e, 0, sizeof(*e));
> }
>
> -static inline unsigned int ebitmap_next(struct ebitmap_node **n,
> - unsigned int bit)
> +static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
> + struct ebitmap_node **n,
> + unsigned int bit)
> {
> - if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
> - (*n)->next) {
> - *n = (*n)->next;
> - return (*n)->startbit;
> - }
> + unsigned int ofs;
> +
> + ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
> + if (ofs < EBITMAP_SIZE)
> + return ofs + (*n)->startbit;
>
> - return (bit+1);
> + for (*n = (*n)->next; *n; *n = (*n)->next) {
> + ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
> + if (ofs < EBITMAP_SIZE)
> + return ofs + (*n)->startbit;
> + }
> + return ebitmap_length(e);
> }
>
> -static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
> +#define EBITMAP_NODE_INDEX(node, bit) \
> + (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
> +#define EBITMAP_NODE_OFFSET(node, bit) \
> + (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
> +
> +static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
> unsigned int bit)
> {
> - if (n->map & (MAPBIT << (bit - n->startbit)))
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + if ((n->maps[index] & (EBITMAP_BIT << ofs)))
> return 1;
> return 0;
> }
>
> -#define ebitmap_for_each_bit(e, n, bit) \
> - for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
> +static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
> + unsigned int bit)
> +{
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + n->maps[index] |= (EBITMAP_BIT << ofs);
> +}
> +
> +static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
> + unsigned int bit)
> +{
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + n->maps[index] &= ~(EBITMAP_BIT << ofs);
> +}
> +
> +#define ebitmap_for_each_positive_bit(e, n, bit) \
> + for (bit = ebitmap_start_positive(e, &n); \
> + bit < ebitmap_length(e); \
> + bit = ebitmap_next_positive(e, &n, bit)) \
>
> int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
> int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
> diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
> index 4a8bab2..9a11dea 100644
> --- a/security/selinux/ss/mls.c
> +++ b/security/selinux/ss/mls.c
> @@ -34,7 +34,9 @@
> */
> int mls_compute_context_len(struct context * context)
> {
> - int i, l, len, range;
> + int i, l, len, head, prev;
> + char *nm;
> + struct ebitmap *e;
> struct ebitmap_node *node;
>
> if (!selinux_mls_enabled)
> @@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
>
> len = 1; /* for the beginning ":" */
> for (l = 0; l < 2; l++) {
> - range = 0;
> - len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
> -
> - ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (range) {
> - range++;
> - continue;
> - }
> + int index_sens = context->range.level[l].sens;
> + len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
>
> - len += strlen(policydb.p_cat_val_to_name[i]) + 1;
> - range++;
> - } else {
> - if (range > 1)
> - len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
> - range = 0;
> + /* categories */
> + head = -2;
> + prev = -2;
> + e = &context->range.level[l].cat;
> + ebitmap_for_each_positive_bit(e, node, i) {
> + if (i - prev > 1) {
> + /* one or more negative bits are skipped */
> + if (head != prev) {
> + nm = policydb.p_cat_val_to_name[prev];
> + len += strlen(nm) + 1;
> + }
> + nm = policydb.p_cat_val_to_name[i];
> + len += strlen(nm) + 1;
> + head = i;
> }
> + prev = i;
> + }
> + if (prev != head) {
> + nm = policydb.p_cat_val_to_name[prev];
> + len += strlen(nm) + 1;
> }
> - /* Handle case where last category is the end of range */
> - if (range > 1)
> - len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
> -
> if (l == 0) {
> if (mls_level_eq(&context->range.level[0],
> - &context->range.level[1]))
> + &context->range.level[1]))
> break;
> else
> len++;
> @@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
> void mls_sid_to_context(struct context *context,
> char **scontext)
> {
> - char *scontextp;
> - int i, l, range, wrote_sep;
> + char *scontextp, *nm;
> + int i, l, head, prev;
> + struct ebitmap *e;
> struct ebitmap_node *node;
>
> if (!selinux_mls_enabled)
> @@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
> scontextp++;
>
> for (l = 0; l < 2; l++) {
> - range = 0;
> - wrote_sep = 0;
> strcpy(scontextp,
> policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
> - scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
> + scontextp += strlen(scontextp);
>
> /* categories */
> - ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (range) {
> - range++;
> - continue;
> - }
> -
> - if (!wrote_sep) {
> - *scontextp++ = ':';
> - wrote_sep = 1;
> - } else
> - *scontextp++ = ',';
> - strcpy(scontextp, policydb.p_cat_val_to_name[i]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i]);
> - range++;
> - } else {
> - if (range > 1) {
> - if (range > 2)
> + head = -2;
> + prev = -2;
> + e = &context->range.level[l].cat;
> + ebitmap_for_each_positive_bit(e, node, i) {
> + if (i - prev > 1) {
> + /* one or more negative bits are skipped */
> + if (prev != head) {
> + if (prev - head > 1)
> *scontextp++ = '.';
> else
> *scontextp++ = ',';
> -
> - strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
> + nm = policydb.p_cat_val_to_name[prev];
> + strcpy(scontextp, nm);
> + scontextp += strlen(nm);
> }
> - range = 0;
> + if (prev < 0)
> + *scontextp++ = ':';
> + else
> + *scontextp++ = ',';
> + nm = policydb.p_cat_val_to_name[i];
> + strcpy(scontextp, nm);
> + scontextp += strlen(nm);
> + head = i;
> }
> + prev = i;
> }
>
> - /* Handle case where last category is the end of range */
> - if (range > 1) {
> - if (range > 2)
> + if (prev != head) {
> + if (prev - head > 1)
> *scontextp++ = '.';
> else
> *scontextp++ = ',';
> -
> - strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
> + nm = policydb.p_cat_val_to_name[prev];
> + strcpy(scontextp, nm);
> + scontextp += strlen(nm);
> }
>
> if (l == 0) {
> if (mls_level_eq(&context->range.level[0],
> &context->range.level[1]))
> break;
> - else {
> - *scontextp = '-';
> - scontextp++;
> - }
> + else
> + *scontextp++ = '-';
> }
> }
>
> @@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
> if (!levdatum)
> return 0;
>
> - ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (i > p->p_cats.nprim)
> - return 0;
> - if (!ebitmap_get_bit(&levdatum->level->cat, i))
> - /*
> - * Category may not be associated with
> - * sensitivity in low level.
> - */
> - return 0;
> - }
> + ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
> + if (i > p->p_cats.nprim)
> + return 0;
> + if (!ebitmap_get_bit(&levdatum->level->cat, i))
> + /*
> + * Category may not be associated with
> + * sensitivity in low level.
> + */
> + return 0;
> }
> }
>
> @@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
> c->range.level[l].sens = levdatum->level->sens;
>
> ebitmap_init(&bitmap);
> - ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - int rc;
> -
> - catdatum = hashtab_search(newp->p_cats.table,
> - oldp->p_cat_val_to_name[i]);
> - if (!catdatum)
> - return -EINVAL;
> - rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
> - if (rc)
> - return rc;
> - }
> + ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
> + int rc;
> +
> + catdatum = hashtab_search(newp->p_cats.table,
> + oldp->p_cat_val_to_name[i]);
> + if (!catdatum)
> + return -EINVAL;
> + rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
> + if (rc)
> + return rc;
> }
> ebitmap_destroy(&c->range.level[l].cat);
> c->range.level[l].cat = bitmap;
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index 6100fc0..19be935 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext,
> avkey.specified = AVTAB_AV;
> sattr = &policydb.type_attr_map[scontext->type - 1];
> tattr = &policydb.type_attr_map[tcontext->type - 1];
> - ebitmap_for_each_bit(sattr, snode, i) {
> - if (!ebitmap_node_get_bit(snode, i))
> - continue;
> - ebitmap_for_each_bit(tattr, tnode, j) {
> - if (!ebitmap_node_get_bit(tnode, j))
> - continue;
> + ebitmap_for_each_positive_bit(sattr, snode, i) {
> + ebitmap_for_each_positive_bit(tattr, tnode, j) {
> avkey.source_type = i + 1;
> avkey.target_type = j + 1;
> for (node = avtab_search_node(&policydb.te_avtab, &avkey);
> @@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid,
> goto out_unlock;
> }
>
> - ebitmap_for_each_bit(&user->roles, rnode, i) {
> - if (!ebitmap_node_get_bit(rnode, i))
> - continue;
> + ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
> role = policydb.role_val_to_struct[i];
> usercon.role = i+1;
> - ebitmap_for_each_bit(&role->types, tnode, j) {
> - if (!ebitmap_node_get_bit(tnode, j))
> - continue;
> + ebitmap_for_each_positive_bit(&role->types, tnode, j) {
> usercon.type = j+1;
>
> if (mls_setup_user_range(fromcon, user, &usercon))
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-28 14:47 ` Stephen Smalley
@ 2007-09-28 17:20 ` KaiGai Kohei
2007-09-28 18:40 ` Stephen Smalley
2007-09-28 21:09 ` James Morris
0 siblings, 2 replies; 52+ messages in thread
From: KaiGai Kohei @ 2007-09-28 17:20 UTC (permalink / raw)
To: Stephen Smalley
Cc: James Morris, selinux, Paul Moore, Yuichi Nakamura, Eric Paris
Stephen Smalley wrote:
> On Fri, 2007-09-28 at 19:56 +0900, KaiGai Kohei wrote:
>> James Morris wrote:
>>>> ++ struct ebitmap_node *_n;
>>>> ++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
>>> Leading underscores are usually used to indicate that core code is not
>>> supposed to use the symbol. Please change it to not have a leading
>>> underscore. 'tmp' or 'n2' is probably ok.
>> OK, I replaced all of '_n' by 'tmp'.
>> Rest of the part in the following patch is same as the previous one.
>
> Seems to be damaged, or at least doesn't apply for me. What is it
> relative to?
I generated the patch against to the latest of James's git tree
But it seems to me that all tab chatacters are translated into
four white spaces, when I copied and pasted the patch.
I'm sorry, it was my misoperation.
Can you receive it with tab kept in this time?
Thanks,
--------
[PATCH] Improve SELinux performance when AVC misses.
* We add ebitmap_for_each_positive_bit() which enables to walk on
any positive bit on the given ebitmap, to improve its performance
using common bit-operations defined in linux/bitops.h.
In the previous version, this logic was implemented using a combination
of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
in performance aspect.
This logic is most frequestly used to compute a new AVC entry,
so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get
suitable for using find_next_bit() which is fasted than iteration of
shift and logical operation, and to maximize memory usage allocated
from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation
in ss/service.c and ss/mls.c. Some of related implementation are
changed, however, there is no incompatibility with the previous
version.
* The width of any new line are less or equal than 80-chars.
The following benchmark shows the effect of this patch, when we
access many files which have different security context one after
another. The number is more than /selinux/avc/cache_threshold, so
any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s]
STD: 0.265 0.019
------------------------------------------
1st: 22.558 [s] 8.786 [s]
2nd: 22.458 [s] 8.750 [s]
3rd: 22.478 [s] 8.754 [s]
4th: 22.724 [s] 8.745 [s]
5th: 22.918 [s] 8.748 [s]
6th: 22.905 [s] 8.764 [s]
7th: 23.238 [s] 8.726 [s]
8th: 22.822 [s] 8.729 [s]
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
---
security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++-----------------
security/selinux/ss/ebitmap.h | 87 ++++++++++---
security/selinux/ss/mls.c | 156 +++++++++++------------
security/selinux/ss/services.c | 16 +--
4 files changed, 303 insertions(+), 237 deletions(-)
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ce492a6..ae44c0c 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/
+/*
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Applied standard bit operations to improve bitmap scanning.
+ */
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
n2 = e2->node;
while (n1 && n2 &&
(n1->startbit == n2->startbit) &&
- (n1->map == n2->map)) {
+ !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
n1 = n1->next;
n2 = n2->next;
}
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
return -ENOMEM;
}
new->startbit = n->startbit;
- new->map = n->map;
+ memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
new->next = NULL;
if (prev)
prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
{
struct ebitmap_node *e_iter = ebmap->node;
struct netlbl_lsm_secattr_catmap *c_iter;
- u32 cmap_idx;
+ u32 cmap_idx, cmap_sft;
+ int i;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
if (e_iter == NULL) {
*catmap = NULL;
@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) {
- if (e_iter->startbit >=
- (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
- c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
- if (c_iter->next == NULL)
- goto netlbl_export_failure;
- c_iter = c_iter->next;
- c_iter->startbit = e_iter->startbit &
- ~(NETLBL_CATMAP_SIZE - 1);
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+ unsigned int delta, e_startbit, c_endbit;
+
+ e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
+ c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
+ if (e_startbit >= c_endbit) {
+ c_iter->next
+ = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (c_iter->next == NULL)
+ goto netlbl_export_failure;
+ c_iter = c_iter->next;
+ c_iter->startbit
+ = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
+ delta = e_startbit - c_iter->startbit;
+ cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
+ cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
+ c_iter->bitmap[cmap_idx]
+ |= e_iter->maps[cmap_idx] << cmap_sft;
+ e_iter = e_iter->next;
}
- cmap_idx = (e_iter->startbit - c_iter->startbit) /
- NETLBL_CATMAP_MAPSIZE;
- c_iter->bitmap[cmap_idx] = e_iter->map;
- e_iter = e_iter->next;
}
return 0;
@@ -128,7 +142,7 @@ netlbl_export_failure:
/**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
- * @ebmap: the ebitmap to export
+ * @ebmap: the ebitmap to import
* @catmap: the NetLabel category bitmap
*
* Description:
@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap;
- u32 c_idx;
+ u32 c_idx, c_pos, e_idx, e_sft;
- /* This function is a much simpler because SELinux's MAPTYPE happens
- * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
- * changed from a u64 this function will most likely need to be changed
- * as well. It's not ideal but I think the tradeoff in terms of
- * neatness and speed is worth it. */
+ /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
+ * however, it is not always compatible with an array of unsigned long
+ * in ebitmap_node.
+ * In addition, you should pay attention the following implementation
+ * assumes unsigned long has a width equal with or less than 64-bit.
+ */
do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
- if (c_iter->bitmap[c_idx] == 0)
+ unsigned int delta;
+ u64 map = c_iter->bitmap[c_idx];
+
+ if (!map)
continue;
- e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
- if (e_iter == NULL)
- goto netlbl_import_failure;
- if (emap_prev == NULL)
- ebmap->node = e_iter;
- else
- emap_prev->next = e_iter;
- emap_prev = e_iter;
-
- e_iter->startbit = c_iter->startbit +
- NETLBL_CATMAP_MAPSIZE * c_idx;
- e_iter->map = c_iter->bitmap[c_idx];
+ c_pos = c_iter->startbit
+ + c_idx * NETLBL_CATMAP_MAPSIZE;
+ if (!e_iter
+ || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
+ e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+ if (!e_iter)
+ goto netlbl_import_failure;
+ e_iter->startbit
+ = c_pos - (c_pos % EBITMAP_SIZE);
+ if (emap_prev == NULL)
+ ebmap->node = e_iter;
+ else
+ emap_prev->next = e_iter;
+ emap_prev = e_iter;
+ }
+ delta = c_pos - e_iter->startbit;
+ e_idx = delta / EBITMAP_UNIT_SIZE;
+ e_sft = delta % EBITMAP_UNIT_SIZE;
+ while (map) {
+ e_iter->maps[e_idx++] |= map & (-1UL);
+ map >>= EBITMAP_UNIT_SIZE;
+ }
}
c_iter = c_iter->next;
} while (c_iter != NULL);
if (e_iter != NULL)
- ebmap->highbit = e_iter->startbit + MAPSIZE;
+ ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
else
ebitmap_destroy(ebmap);
@@ -186,6 +214,7 @@ netlbl_import_failure:
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
+ int i;
if (e1->highbit < e2->highbit)
return 0;
@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next;
continue;
}
- if ((n1->map & n2->map) != n2->map)
- return 0;
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+ if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
+ return 0;
+ }
n1 = n1->next;
n2 = n2->next;
@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node;
while (n && (n->startbit <= bit)) {
- if ((n->startbit + MAPSIZE) > bit) {
- if (n->map & (MAPBIT << (bit - n->startbit)))
- return 1;
- else
- return 0;
- }
+ if ((n->startbit + EBITMAP_SIZE) > bit)
+ return ebitmap_node_get_bit(n, bit);
n = n->next;
}
@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
- if ((n->startbit + MAPSIZE) > bit) {
+ if ((n->startbit + EBITMAP_SIZE) > bit) {
if (value) {
- n->map |= (MAPBIT << (bit - n->startbit));
+ ebitmap_node_set_bit(n, bit);
} else {
- n->map &= ~(MAPBIT << (bit - n->startbit));
- if (!n->map) {
- /* drop this node from the bitmap */
-
- if (!n->next) {
- /*
- * this was the highest map
- * within the bitmap
- */
- if (prev)
- e->highbit = prev->startbit + MAPSIZE;
- else
- e->highbit = 0;
- }
+ unsigned int s;
+
+ ebitmap_node_clr_bit(n, bit);
+
+ s = find_first_bit(n->maps, EBITMAP_SIZE);
+ if (s < EBITMAP_SIZE)
+ return 0;
+
+ /* drop this node from the bitmap */
+ if (!n->next) {
+ /*
+ * this was the highest map
+ * within the bitmap
+ */
if (prev)
- prev->next = n->next;
+ e->highbit = prev->startbit
+ + EBITMAP_SIZE;
else
- e->node = n->next;
-
- kfree(n);
+ e->highbit = 0;
}
+ if (prev)
+ prev->next = n->next;
+ else
+ e->node = n->next;
+ kfree(n);
}
return 0;
}
@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new)
return -ENOMEM;
- new->startbit = bit & ~(MAPSIZE - 1);
- new->map = (MAPBIT << (bit - new->startbit));
+ new->startbit = bit - (bit % EBITMAP_SIZE);
+ ebitmap_node_set_bit(new, bit);
if (!n)
/* this node will be the highest map within the bitmap */
- e->highbit = new->startbit + MAPSIZE;
+ e->highbit = new->startbit + EBITMAP_SIZE;
if (prev) {
new->next = prev->next;
@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
- int rc;
- struct ebitmap_node *n, *l;
+ struct ebitmap_node *n = NULL;
+ u32 mapunit, count, startbit, index;
+ u64 map;
__le32 buf[3];
- u32 mapsize, count, i;
- __le64 map;
+ int rc, i;
ebitmap_init(e);
@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
- mapsize = le32_to_cpu(buf[0]);
+ mapunit = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]);
- if (mapsize != MAPSIZE) {
+ if (mapunit != sizeof(u64) * 8) {
printk(KERN_ERR "security: ebitmap: map size %u does not "
- "match my size %Zd (high bit was %d)\n", mapsize,
- MAPSIZE, e->highbit);
+ "match my size %Zd (high bit was %d)\n",
+ mapunit, sizeof(u64) * 8, e->highbit);
goto bad;
}
+
+ /* round up e->highbit */
+ e->highbit += EBITMAP_SIZE - 1;
+ e->highbit -= (e->highbit % EBITMAP_SIZE);
+
if (!e->highbit) {
e->node = NULL;
goto ok;
}
- if (e->highbit & (MAPSIZE - 1)) {
- printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
- "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
- goto bad;
- }
- l = NULL;
+
for (i = 0; i < count; i++) {
- rc = next_entry(buf, fp, sizeof(u32));
+ rc = next_entry(&startbit, fp, sizeof(u32));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad;
}
- n = kzalloc(sizeof(*n), GFP_KERNEL);
- if (!n) {
- printk(KERN_ERR "security: ebitmap: out of memory\n");
- rc = -ENOMEM;
- goto bad;
- }
-
- n->startbit = le32_to_cpu(buf[0]);
+ startbit = le32_to_cpu(startbit);
- if (n->startbit & (MAPSIZE - 1)) {
+ if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map size (%Zd)\n",
- n->startbit, MAPSIZE);
- goto bad_free;
+ "not a multiple of the map unit size (%Zd)\n",
+ startbit, mapunit);
+ goto bad;
}
- if (n->startbit > (e->highbit - MAPSIZE)) {
+ if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%Zd)\n",
- n->startbit, (e->highbit - MAPSIZE));
- goto bad_free;
+ startbit, (e->highbit - mapunit));
+ goto bad;
+ }
+
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
+ struct ebitmap_node *tmp;
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp) {
+ printk(KERN_ERR
+ "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ /* round down */
+ tmp->startbit = startbit - (startbit % EBITMAP_SIZE);
+ if (n) {
+ n->next = tmp;
+ } else {
+ e->node = tmp;
+ }
+ n = tmp;
+ } else if (startbit <= n->startbit) {
+ printk(KERN_ERR "security: ebitmap: start bit %d"
+ " comes after start bit %d\n",
+ startbit, n->startbit);
+ goto bad;
}
+
rc = next_entry(&map, fp, sizeof(u64));
if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
- goto bad_free;
+ goto bad;
}
- n->map = le64_to_cpu(map);
+ map = le64_to_cpu(map);
- if (!n->map) {
- printk(KERN_ERR "security: ebitmap: null map in "
- "ebitmap (startbit %d)\n", n->startbit);
- goto bad_free;
+ index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
+ while (map) {
+ n->maps[index] = map & (-1UL);
+ map = map >> EBITMAP_UNIT_SIZE;
+ index++;
}
- if (l) {
- if (n->startbit <= l->startbit) {
- printk(KERN_ERR "security: ebitmap: start "
- "bit %d comes after start bit %d\n",
- n->startbit, l->startbit);
- goto bad_free;
- }
- l->next = n;
- } else
- e->node = n;
-
- l = n;
}
-
ok:
rc = 0;
out:
return rc;
-bad_free:
- kfree(n);
bad:
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 1270e34..e38a327 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -16,14 +16,16 @@
#include <net/netlabel.h>
-#define MAPTYPE u64 /* portion of bitmap in each node */
-#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
-#define MAPBIT 1ULL /* a bit in the node bitmap */
+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
+ / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1ULL
struct ebitmap_node {
- u32 startbit; /* starting position in the total bitmap */
- MAPTYPE map; /* this node's portion of the bitmap */
struct ebitmap_node *next;
+ unsigned long maps[EBITMAP_UNIT_NUMS];
+ u32 startbit;
};
struct ebitmap {
@@ -34,11 +36,17 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
-static inline unsigned int ebitmap_start(struct ebitmap *e,
- struct ebitmap_node **n)
+static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+ struct ebitmap_node **n)
{
- *n = e->node;
- return ebitmap_startbit(e);
+ unsigned int ofs;
+
+ for (*n = e->node; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return (*n)->startbit + ofs;
+ }
+ return ebitmap_length(e);
}
static inline void ebitmap_init(struct ebitmap *e)
@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
-static inline unsigned int ebitmap_next(struct ebitmap_node **n,
- unsigned int bit)
+static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
+ struct ebitmap_node **n,
+ unsigned int bit)
{
- if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
- (*n)->next) {
- *n = (*n)->next;
- return (*n)->startbit;
- }
+ unsigned int ofs;
+
+ ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
- return (bit+1);
+ for (*n = (*n)->next; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+ }
+ return ebitmap_length(e);
}
-static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
+#define EBITMAP_NODE_INDEX(node, bit) \
+ (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
+#define EBITMAP_NODE_OFFSET(node, bit) \
+ (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
unsigned int bit)
{
- if (n->map & (MAPBIT << (bit - n->startbit)))
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ if ((n->maps[index] & (EBITMAP_BIT << ofs)))
return 1;
return 0;
}
-#define ebitmap_for_each_bit(e, n, bit) \
- for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
+ unsigned int bit)
+{
+ unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+ unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for (bit = ebitmap_start_positive(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2..9a11dea 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -34,7 +34,9 @@
*/
int mls_compute_context_len(struct context * context)
{
- int i, l, len, range;
+ int i, l, len, head, prev;
+ char *nm;
+ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) {
- range = 0;
- len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
-
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
+ int index_sens = context->range.level[l].sens;
+ len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
- len += strlen(policydb.p_cat_val_to_name[i]) + 1;
- range++;
- } else {
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
- range = 0;
+ /* categories */
+ head = -2;
+ prev = -2;
+ e = &context->range.level[l].cat;
+ ebitmap_for_each_positive_bit(e, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped */
+ if (head != prev) {
+ nm = policydb.p_cat_val_to_name[prev];
+ len += strlen(nm) + 1;
+ }
+ nm = policydb.p_cat_val_to_name[i];
+ len += strlen(nm) + 1;
+ head = i;
}
+ prev = i;
+ }
+ if (prev != head) {
+ nm = policydb.p_cat_val_to_name[prev];
+ len += strlen(nm) + 1;
}
- /* Handle case where last category is the end of range */
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
-
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
- &context->range.level[1]))
+ &context->range.level[1]))
break;
else
len++;
@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
void mls_sid_to_context(struct context *context,
char **scontext)
{
- char *scontextp;
- int i, l, range, wrote_sep;
+ char *scontextp, *nm;
+ int i, l, head, prev;
+ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
scontextp++;
for (l = 0; l < 2; l++) {
- range = 0;
- wrote_sep = 0;
strcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
- scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+ scontextp += strlen(scontextp);
/* categories */
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
-
- if (!wrote_sep) {
- *scontextp++ = ':';
- wrote_sep = 1;
- } else
- *scontextp++ = ',';
- strcpy(scontextp, policydb.p_cat_val_to_name[i]);
- scontextp += strlen(policydb.p_cat_val_to_name[i]);
- range++;
- } else {
- if (range > 1) {
- if (range > 2)
+ head = -2;
+ prev = -2;
+ e = &context->range.level[l].cat;
+ ebitmap_for_each_positive_bit(e, node, i) {
+ if (i - prev > 1) {
+ /* one or more negative bits are skipped */
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ nm = policydb.p_cat_val_to_name[prev];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
}
- range = 0;
+ if (prev < 0)
+ *scontextp++ = ':';
+ else
+ *scontextp++ = ',';
+ nm = policydb.p_cat_val_to_name[i];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
+ head = i;
}
+ prev = i;
}
- /* Handle case where last category is the end of range */
- if (range > 1) {
- if (range > 2)
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
else
*scontextp++ = ',';
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ nm = policydb.p_cat_val_to_name[prev];
+ strcpy(scontextp, nm);
+ scontextp += strlen(nm);
}
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
&context->range.level[1]))
break;
- else {
- *scontextp = '-';
- scontextp++;
- }
+ else
+ *scontextp++ = '-';
}
}
@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (i > p->p_cats.nprim)
- return 0;
- if (!ebitmap_get_bit(&levdatum->level->cat, i))
- /*
- * Category may not be associated with
- * sensitivity in low level.
- */
- return 0;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
+ /*
+ * Category may not be associated with
+ * sensitivity in low level.
+ */
+ return 0;
}
}
@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
- ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- int rc;
-
- catdatum = hashtab_search(newp->p_cats.table,
- oldp->p_cat_val_to_name[i]);
- if (!catdatum)
- return -EINVAL;
- rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
- if (rc)
- return rc;
- }
+ ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
+ int rc;
+
+ catdatum = hashtab_search(newp->p_cats.table,
+ oldp->p_cat_val_to_name[i]);
+ if (!catdatum)
+ return -EINVAL;
+ rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
+ if (rc)
+ return rc;
}
ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 6100fc0..19be935 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext,
avkey.specified = AVTAB_AV;
sattr = &policydb.type_attr_map[scontext->type - 1];
tattr = &policydb.type_attr_map[tcontext->type - 1];
- ebitmap_for_each_bit(sattr, snode, i) {
- if (!ebitmap_node_get_bit(snode, i))
- continue;
- ebitmap_for_each_bit(tattr, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(sattr, snode, i) {
+ ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1;
avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid,
goto out_unlock;
}
- ebitmap_for_each_bit(&user->roles, rnode, i) {
- if (!ebitmap_node_get_bit(rnode, i))
- continue;
+ ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
role = policydb.role_val_to_struct[i];
usercon.role = i+1;
- ebitmap_for_each_bit(&role->types, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(&role->types, tnode, j) {
usercon.type = j+1;
if (mls_setup_user_range(fromcon, user, &usercon))
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-28 17:20 ` KaiGai Kohei
@ 2007-09-28 18:40 ` Stephen Smalley
2007-09-28 21:09 ` James Morris
1 sibling, 0 replies; 52+ messages in thread
From: Stephen Smalley @ 2007-09-28 18:40 UTC (permalink / raw)
To: KaiGai Kohei
Cc: James Morris, selinux, Paul Moore, Yuichi Nakamura, Eric Paris
On Sat, 2007-09-29 at 02:20 +0900, KaiGai Kohei wrote:
> Stephen Smalley wrote:
> > On Fri, 2007-09-28 at 19:56 +0900, KaiGai Kohei wrote:
> >> James Morris wrote:
> >>>> ++ struct ebitmap_node *_n;
> >>>> ++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
> >>> Leading underscores are usually used to indicate that core code is not
> >>> supposed to use the symbol. Please change it to not have a leading
> >>> underscore. 'tmp' or 'n2' is probably ok.
> >> OK, I replaced all of '_n' by 'tmp'.
> >> Rest of the part in the following patch is same as the previous one.
> >
> > Seems to be damaged, or at least doesn't apply for me. What is it
> > relative to?
>
> I generated the patch against to the latest of James's git tree
> But it seems to me that all tab chatacters are translated into
> four white spaces, when I copied and pasted the patch.
> I'm sorry, it was my misoperation.
>
> Can you receive it with tab kept in this time?
>
> Thanks,
>
> --------
> [PATCH] Improve SELinux performance when AVC misses.
>
> * We add ebitmap_for_each_positive_bit() which enables to walk on
> any positive bit on the given ebitmap, to improve its performance
> using common bit-operations defined in linux/bitops.h.
> In the previous version, this logic was implemented using a combination
> of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
> in performance aspect.
> This logic is most frequestly used to compute a new AVC entry,
> so this patch can improve SELinux performance when AVC misses are happen.
> * struct ebitmap_node is redefined as an array of "unsigned long", to get
> suitable for using find_next_bit() which is fasted than iteration of
> shift and logical operation, and to maximize memory usage allocated
> from general purpose slab.
> * Any ebitmap_for_each_bit() are repleced by the new implementation
> in ss/service.c and ss/mls.c. Some of related implementation are
> changed, however, there is no incompatibility with the previous
> version.
> * The width of any new line are less or equal than 80-chars.
>
> The following benchmark shows the effect of this patch, when we
> access many files which have different security context one after
> another. The number is more than /selinux/avc/cache_threshold, so
> any access always causes AVC misses.
>
> selinux-2.6 selinux-2.6-ebitmap
> AVG: 22.763 [s] 8.750 [s]
> STD: 0.265 0.019
> ------------------------------------------
> 1st: 22.558 [s] 8.786 [s]
> 2nd: 22.458 [s] 8.750 [s]
> 3rd: 22.478 [s] 8.754 [s]
> 4th: 22.724 [s] 8.745 [s]
> 5th: 22.918 [s] 8.748 [s]
> 6th: 22.905 [s] 8.764 [s]
> 7th: 23.238 [s] 8.726 [s]
> 8th: 22.822 [s] 8.729 [s]
>
> Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
> ---
> security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++-----------------
> security/selinux/ss/ebitmap.h | 87 ++++++++++---
> security/selinux/ss/mls.c | 156 +++++++++++------------
> security/selinux/ss/services.c | 16 +--
> 4 files changed, 303 insertions(+), 237 deletions(-)
>
> diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
> index ce492a6..ae44c0c 100644
> --- a/security/selinux/ss/ebitmap.c
> +++ b/security/selinux/ss/ebitmap.c
> @@ -10,6 +10,10 @@
> *
> * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
> */
> +/*
> + * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
> + * Applied standard bit operations to improve bitmap scanning.
> + */
>
> #include <linux/kernel.h>
> #include <linux/slab.h>
> @@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
> n2 = e2->node;
> while (n1 && n2 &&
> (n1->startbit == n2->startbit) &&
> - (n1->map == n2->map)) {
> + !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
> n1 = n1->next;
> n2 = n2->next;
> }
> @@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
> return -ENOMEM;
> }
> new->startbit = n->startbit;
> - new->map = n->map;
> + memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
> new->next = NULL;
> if (prev)
> prev->next = new;
> @@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
> {
> struct ebitmap_node *e_iter = ebmap->node;
> struct netlbl_lsm_secattr_catmap *c_iter;
> - u32 cmap_idx;
> + u32 cmap_idx, cmap_sft;
> + int i;
>
> - /* This function is a much simpler because SELinux's MAPTYPE happens
> - * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
> - * changed from a u64 this function will most likely need to be changed
> - * as well. It's not ideal but I think the tradeoff in terms of
> - * neatness and speed is worth it. */
> + /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
> + * however, it is not always compatible with an array of unsigned long
> + * in ebitmap_node.
> + * In addition, you should pay attention the following implementation
> + * assumes unsigned long has a width equal with or less than 64-bit.
> + */
>
> if (e_iter == NULL) {
> *catmap = NULL;
> @@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
> c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
>
> while (e_iter != NULL) {
> - if (e_iter->startbit >=
> - (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
> - c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
> - if (c_iter->next == NULL)
> - goto netlbl_export_failure;
> - c_iter = c_iter->next;
> - c_iter->startbit = e_iter->startbit &
> - ~(NETLBL_CATMAP_SIZE - 1);
> + for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
> + unsigned int delta, e_startbit, c_endbit;
> +
> + e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
> + c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
> + if (e_startbit >= c_endbit) {
> + c_iter->next
> + = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
> + if (c_iter->next == NULL)
> + goto netlbl_export_failure;
> + c_iter = c_iter->next;
> + c_iter->startbit
> + = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
> + }
> + delta = e_startbit - c_iter->startbit;
> + cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
> + cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
> + c_iter->bitmap[cmap_idx]
> + |= e_iter->maps[cmap_idx] << cmap_sft;
> + e_iter = e_iter->next;
> }
> - cmap_idx = (e_iter->startbit - c_iter->startbit) /
> - NETLBL_CATMAP_MAPSIZE;
> - c_iter->bitmap[cmap_idx] = e_iter->map;
> - e_iter = e_iter->next;
> }
>
> return 0;
> @@ -128,7 +142,7 @@ netlbl_export_failure:
>
> /**
> * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
> - * @ebmap: the ebitmap to export
> + * @ebmap: the ebitmap to import
> * @catmap: the NetLabel category bitmap
> *
> * Description:
> @@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
> struct ebitmap_node *e_iter = NULL;
> struct ebitmap_node *emap_prev = NULL;
> struct netlbl_lsm_secattr_catmap *c_iter = catmap;
> - u32 c_idx;
> + u32 c_idx, c_pos, e_idx, e_sft;
>
> - /* This function is a much simpler because SELinux's MAPTYPE happens
> - * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
> - * changed from a u64 this function will most likely need to be changed
> - * as well. It's not ideal but I think the tradeoff in terms of
> - * neatness and speed is worth it. */
> + /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
> + * however, it is not always compatible with an array of unsigned long
> + * in ebitmap_node.
> + * In addition, you should pay attention the following implementation
> + * assumes unsigned long has a width equal with or less than 64-bit.
> + */
>
> do {
> for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
> - if (c_iter->bitmap[c_idx] == 0)
> + unsigned int delta;
> + u64 map = c_iter->bitmap[c_idx];
> +
> + if (!map)
> continue;
>
> - e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
> - if (e_iter == NULL)
> - goto netlbl_import_failure;
> - if (emap_prev == NULL)
> - ebmap->node = e_iter;
> - else
> - emap_prev->next = e_iter;
> - emap_prev = e_iter;
> -
> - e_iter->startbit = c_iter->startbit +
> - NETLBL_CATMAP_MAPSIZE * c_idx;
> - e_iter->map = c_iter->bitmap[c_idx];
> + c_pos = c_iter->startbit
> + + c_idx * NETLBL_CATMAP_MAPSIZE;
> + if (!e_iter
> + || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
> + e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
> + if (!e_iter)
> + goto netlbl_import_failure;
> + e_iter->startbit
> + = c_pos - (c_pos % EBITMAP_SIZE);
> + if (emap_prev == NULL)
> + ebmap->node = e_iter;
> + else
> + emap_prev->next = e_iter;
> + emap_prev = e_iter;
> + }
> + delta = c_pos - e_iter->startbit;
> + e_idx = delta / EBITMAP_UNIT_SIZE;
> + e_sft = delta % EBITMAP_UNIT_SIZE;
> + while (map) {
> + e_iter->maps[e_idx++] |= map & (-1UL);
> + map >>= EBITMAP_UNIT_SIZE;
> + }
> }
> c_iter = c_iter->next;
> } while (c_iter != NULL);
> if (e_iter != NULL)
> - ebmap->highbit = e_iter->startbit + MAPSIZE;
> + ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
> else
> ebitmap_destroy(ebmap);
>
> @@ -186,6 +214,7 @@ netlbl_import_failure:
> int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
> {
> struct ebitmap_node *n1, *n2;
> + int i;
>
> if (e1->highbit < e2->highbit)
> return 0;
> @@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
> n1 = n1->next;
> continue;
> }
> - if ((n1->map & n2->map) != n2->map)
> - return 0;
> + for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
> + if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
> + return 0;
> + }
>
> n1 = n1->next;
> n2 = n2->next;
> @@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
>
> n = e->node;
> while (n && (n->startbit <= bit)) {
> - if ((n->startbit + MAPSIZE) > bit) {
> - if (n->map & (MAPBIT << (bit - n->startbit)))
> - return 1;
> - else
> - return 0;
> - }
> + if ((n->startbit + EBITMAP_SIZE) > bit)
> + return ebitmap_node_get_bit(n, bit);
> n = n->next;
> }
>
> @@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
> prev = NULL;
> n = e->node;
> while (n && n->startbit <= bit) {
> - if ((n->startbit + MAPSIZE) > bit) {
> + if ((n->startbit + EBITMAP_SIZE) > bit) {
> if (value) {
> - n->map |= (MAPBIT << (bit - n->startbit));
> + ebitmap_node_set_bit(n, bit);
> } else {
> - n->map &= ~(MAPBIT << (bit - n->startbit));
> - if (!n->map) {
> - /* drop this node from the bitmap */
> -
> - if (!n->next) {
> - /*
> - * this was the highest map
> - * within the bitmap
> - */
> - if (prev)
> - e->highbit = prev->startbit + MAPSIZE;
> - else
> - e->highbit = 0;
> - }
> + unsigned int s;
> +
> + ebitmap_node_clr_bit(n, bit);
> +
> + s = find_first_bit(n->maps, EBITMAP_SIZE);
> + if (s < EBITMAP_SIZE)
> + return 0;
> +
> + /* drop this node from the bitmap */
> + if (!n->next) {
> + /*
> + * this was the highest map
> + * within the bitmap
> + */
> if (prev)
> - prev->next = n->next;
> + e->highbit = prev->startbit
> + + EBITMAP_SIZE;
> else
> - e->node = n->next;
> -
> - kfree(n);
> + e->highbit = 0;
> }
> + if (prev)
> + prev->next = n->next;
> + else
> + e->node = n->next;
> + kfree(n);
> }
> return 0;
> }
> @@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
> if (!new)
> return -ENOMEM;
>
> - new->startbit = bit & ~(MAPSIZE - 1);
> - new->map = (MAPBIT << (bit - new->startbit));
> + new->startbit = bit - (bit % EBITMAP_SIZE);
> + ebitmap_node_set_bit(new, bit);
>
> if (!n)
> /* this node will be the highest map within the bitmap */
> - e->highbit = new->startbit + MAPSIZE;
> + e->highbit = new->startbit + EBITMAP_SIZE;
>
> if (prev) {
> new->next = prev->next;
> @@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
>
> int ebitmap_read(struct ebitmap *e, void *fp)
> {
> - int rc;
> - struct ebitmap_node *n, *l;
> + struct ebitmap_node *n = NULL;
> + u32 mapunit, count, startbit, index;
> + u64 map;
> __le32 buf[3];
> - u32 mapsize, count, i;
> - __le64 map;
> + int rc, i;
>
> ebitmap_init(e);
>
> @@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
> if (rc < 0)
> goto out;
>
> - mapsize = le32_to_cpu(buf[0]);
> + mapunit = le32_to_cpu(buf[0]);
> e->highbit = le32_to_cpu(buf[1]);
> count = le32_to_cpu(buf[2]);
>
> - if (mapsize != MAPSIZE) {
> + if (mapunit != sizeof(u64) * 8) {
> printk(KERN_ERR "security: ebitmap: map size %u does not "
> - "match my size %Zd (high bit was %d)\n", mapsize,
> - MAPSIZE, e->highbit);
> + "match my size %Zd (high bit was %d)\n",
> + mapunit, sizeof(u64) * 8, e->highbit);
> goto bad;
> }
> +
> + /* round up e->highbit */
> + e->highbit += EBITMAP_SIZE - 1;
> + e->highbit -= (e->highbit % EBITMAP_SIZE);
> +
> if (!e->highbit) {
> e->node = NULL;
> goto ok;
> }
> - if (e->highbit & (MAPSIZE - 1)) {
> - printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
> - "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
> - goto bad;
> - }
> - l = NULL;
> +
> for (i = 0; i < count; i++) {
> - rc = next_entry(buf, fp, sizeof(u32));
> + rc = next_entry(&startbit, fp, sizeof(u32));
> if (rc < 0) {
> printk(KERN_ERR "security: ebitmap: truncated map\n");
> goto bad;
> }
> - n = kzalloc(sizeof(*n), GFP_KERNEL);
> - if (!n) {
> - printk(KERN_ERR "security: ebitmap: out of memory\n");
> - rc = -ENOMEM;
> - goto bad;
> - }
> -
> - n->startbit = le32_to_cpu(buf[0]);
> + startbit = le32_to_cpu(startbit);
>
> - if (n->startbit & (MAPSIZE - 1)) {
> + if (startbit & (mapunit - 1)) {
> printk(KERN_ERR "security: ebitmap start bit (%d) is "
> - "not a multiple of the map size (%Zd)\n",
> - n->startbit, MAPSIZE);
> - goto bad_free;
> + "not a multiple of the map unit size (%Zd)\n",
> + startbit, mapunit);
> + goto bad;
> }
> - if (n->startbit > (e->highbit - MAPSIZE)) {
> + if (startbit > e->highbit - mapunit) {
> printk(KERN_ERR "security: ebitmap start bit (%d) is "
> "beyond the end of the bitmap (%Zd)\n",
> - n->startbit, (e->highbit - MAPSIZE));
> - goto bad_free;
> + startbit, (e->highbit - mapunit));
> + goto bad;
> + }
> +
> + if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
> + struct ebitmap_node *tmp;
> + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
> + if (!tmp) {
> + printk(KERN_ERR
> + "security: ebitmap: out of memory\n");
> + rc = -ENOMEM;
> + goto bad;
> + }
> + /* round down */
> + tmp->startbit = startbit - (startbit % EBITMAP_SIZE);
> + if (n) {
> + n->next = tmp;
> + } else {
> + e->node = tmp;
> + }
> + n = tmp;
> + } else if (startbit <= n->startbit) {
> + printk(KERN_ERR "security: ebitmap: start bit %d"
> + " comes after start bit %d\n",
> + startbit, n->startbit);
> + goto bad;
> }
> +
> rc = next_entry(&map, fp, sizeof(u64));
> if (rc < 0) {
> printk(KERN_ERR "security: ebitmap: truncated map\n");
> - goto bad_free;
> + goto bad;
> }
> - n->map = le64_to_cpu(map);
> + map = le64_to_cpu(map);
>
> - if (!n->map) {
> - printk(KERN_ERR "security: ebitmap: null map in "
> - "ebitmap (startbit %d)\n", n->startbit);
> - goto bad_free;
> + index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
> + while (map) {
> + n->maps[index] = map & (-1UL);
> + map = map >> EBITMAP_UNIT_SIZE;
> + index++;
> }
> - if (l) {
> - if (n->startbit <= l->startbit) {
> - printk(KERN_ERR "security: ebitmap: start "
> - "bit %d comes after start bit %d\n",
> - n->startbit, l->startbit);
> - goto bad_free;
> - }
> - l->next = n;
> - } else
> - e->node = n;
> -
> - l = n;
> }
> -
> ok:
> rc = 0;
> out:
> return rc;
> -bad_free:
> - kfree(n);
> bad:
> if (!rc)
> rc = -EINVAL;
> diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
> index 1270e34..e38a327 100644
> --- a/security/selinux/ss/ebitmap.h
> +++ b/security/selinux/ss/ebitmap.h
> @@ -16,14 +16,16 @@
>
> #include <net/netlabel.h>
>
> -#define MAPTYPE u64 /* portion of bitmap in each node */
> -#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
> -#define MAPBIT 1ULL /* a bit in the node bitmap */
> +#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
> + / sizeof(unsigned long))
> +#define EBITMAP_UNIT_SIZE BITS_PER_LONG
> +#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
> +#define EBITMAP_BIT 1ULL
>
> struct ebitmap_node {
> - u32 startbit; /* starting position in the total bitmap */
> - MAPTYPE map; /* this node's portion of the bitmap */
> struct ebitmap_node *next;
> + unsigned long maps[EBITMAP_UNIT_NUMS];
> + u32 startbit;
> };
>
> struct ebitmap {
> @@ -34,11 +36,17 @@ struct ebitmap {
> #define ebitmap_length(e) ((e)->highbit)
> #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
>
> -static inline unsigned int ebitmap_start(struct ebitmap *e,
> - struct ebitmap_node **n)
> +static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
> + struct ebitmap_node **n)
> {
> - *n = e->node;
> - return ebitmap_startbit(e);
> + unsigned int ofs;
> +
> + for (*n = e->node; *n; *n = (*n)->next) {
> + ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
> + if (ofs < EBITMAP_SIZE)
> + return (*n)->startbit + ofs;
> + }
> + return ebitmap_length(e);
> }
>
> static inline void ebitmap_init(struct ebitmap *e)
> @@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
> memset(e, 0, sizeof(*e));
> }
>
> -static inline unsigned int ebitmap_next(struct ebitmap_node **n,
> - unsigned int bit)
> +static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
> + struct ebitmap_node **n,
> + unsigned int bit)
> {
> - if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
> - (*n)->next) {
> - *n = (*n)->next;
> - return (*n)->startbit;
> - }
> + unsigned int ofs;
> +
> + ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
> + if (ofs < EBITMAP_SIZE)
> + return ofs + (*n)->startbit;
>
> - return (bit+1);
> + for (*n = (*n)->next; *n; *n = (*n)->next) {
> + ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
> + if (ofs < EBITMAP_SIZE)
> + return ofs + (*n)->startbit;
> + }
> + return ebitmap_length(e);
> }
>
> -static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
> +#define EBITMAP_NODE_INDEX(node, bit) \
> + (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
> +#define EBITMAP_NODE_OFFSET(node, bit) \
> + (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
> +
> +static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
> unsigned int bit)
> {
> - if (n->map & (MAPBIT << (bit - n->startbit)))
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + if ((n->maps[index] & (EBITMAP_BIT << ofs)))
> return 1;
> return 0;
> }
>
> -#define ebitmap_for_each_bit(e, n, bit) \
> - for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
> +static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
> + unsigned int bit)
> +{
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + n->maps[index] |= (EBITMAP_BIT << ofs);
> +}
> +
> +static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
> + unsigned int bit)
> +{
> + unsigned int index = EBITMAP_NODE_INDEX(n, bit);
> + unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
> +
> + BUG_ON(index >= EBITMAP_UNIT_NUMS);
> + n->maps[index] &= ~(EBITMAP_BIT << ofs);
> +}
> +
> +#define ebitmap_for_each_positive_bit(e, n, bit) \
> + for (bit = ebitmap_start_positive(e, &n); \
> + bit < ebitmap_length(e); \
> + bit = ebitmap_next_positive(e, &n, bit)) \
>
> int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
> int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
> diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
> index 4a8bab2..9a11dea 100644
> --- a/security/selinux/ss/mls.c
> +++ b/security/selinux/ss/mls.c
> @@ -34,7 +34,9 @@
> */
> int mls_compute_context_len(struct context * context)
> {
> - int i, l, len, range;
> + int i, l, len, head, prev;
> + char *nm;
> + struct ebitmap *e;
> struct ebitmap_node *node;
>
> if (!selinux_mls_enabled)
> @@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
>
> len = 1; /* for the beginning ":" */
> for (l = 0; l < 2; l++) {
> - range = 0;
> - len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
> -
> - ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (range) {
> - range++;
> - continue;
> - }
> + int index_sens = context->range.level[l].sens;
> + len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
>
> - len += strlen(policydb.p_cat_val_to_name[i]) + 1;
> - range++;
> - } else {
> - if (range > 1)
> - len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
> - range = 0;
> + /* categories */
> + head = -2;
> + prev = -2;
> + e = &context->range.level[l].cat;
> + ebitmap_for_each_positive_bit(e, node, i) {
> + if (i - prev > 1) {
> + /* one or more negative bits are skipped */
> + if (head != prev) {
> + nm = policydb.p_cat_val_to_name[prev];
> + len += strlen(nm) + 1;
> + }
> + nm = policydb.p_cat_val_to_name[i];
> + len += strlen(nm) + 1;
> + head = i;
> }
> + prev = i;
> + }
> + if (prev != head) {
> + nm = policydb.p_cat_val_to_name[prev];
> + len += strlen(nm) + 1;
> }
> - /* Handle case where last category is the end of range */
> - if (range > 1)
> - len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
> -
> if (l == 0) {
> if (mls_level_eq(&context->range.level[0],
> - &context->range.level[1]))
> + &context->range.level[1]))
> break;
> else
> len++;
> @@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
> void mls_sid_to_context(struct context *context,
> char **scontext)
> {
> - char *scontextp;
> - int i, l, range, wrote_sep;
> + char *scontextp, *nm;
> + int i, l, head, prev;
> + struct ebitmap *e;
> struct ebitmap_node *node;
>
> if (!selinux_mls_enabled)
> @@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
> scontextp++;
>
> for (l = 0; l < 2; l++) {
> - range = 0;
> - wrote_sep = 0;
> strcpy(scontextp,
> policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
> - scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
> + scontextp += strlen(scontextp);
>
> /* categories */
> - ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (range) {
> - range++;
> - continue;
> - }
> -
> - if (!wrote_sep) {
> - *scontextp++ = ':';
> - wrote_sep = 1;
> - } else
> - *scontextp++ = ',';
> - strcpy(scontextp, policydb.p_cat_val_to_name[i]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i]);
> - range++;
> - } else {
> - if (range > 1) {
> - if (range > 2)
> + head = -2;
> + prev = -2;
> + e = &context->range.level[l].cat;
> + ebitmap_for_each_positive_bit(e, node, i) {
> + if (i - prev > 1) {
> + /* one or more negative bits are skipped */
> + if (prev != head) {
> + if (prev - head > 1)
> *scontextp++ = '.';
> else
> *scontextp++ = ',';
> -
> - strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
> + nm = policydb.p_cat_val_to_name[prev];
> + strcpy(scontextp, nm);
> + scontextp += strlen(nm);
> }
> - range = 0;
> + if (prev < 0)
> + *scontextp++ = ':';
> + else
> + *scontextp++ = ',';
> + nm = policydb.p_cat_val_to_name[i];
> + strcpy(scontextp, nm);
> + scontextp += strlen(nm);
> + head = i;
> }
> + prev = i;
> }
>
> - /* Handle case where last category is the end of range */
> - if (range > 1) {
> - if (range > 2)
> + if (prev != head) {
> + if (prev - head > 1)
> *scontextp++ = '.';
> else
> *scontextp++ = ',';
> -
> - strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
> - scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
> + nm = policydb.p_cat_val_to_name[prev];
> + strcpy(scontextp, nm);
> + scontextp += strlen(nm);
> }
>
> if (l == 0) {
> if (mls_level_eq(&context->range.level[0],
> &context->range.level[1]))
> break;
> - else {
> - *scontextp = '-';
> - scontextp++;
> - }
> + else
> + *scontextp++ = '-';
> }
> }
>
> @@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
> if (!levdatum)
> return 0;
>
> - ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - if (i > p->p_cats.nprim)
> - return 0;
> - if (!ebitmap_get_bit(&levdatum->level->cat, i))
> - /*
> - * Category may not be associated with
> - * sensitivity in low level.
> - */
> - return 0;
> - }
> + ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
> + if (i > p->p_cats.nprim)
> + return 0;
> + if (!ebitmap_get_bit(&levdatum->level->cat, i))
> + /*
> + * Category may not be associated with
> + * sensitivity in low level.
> + */
> + return 0;
> }
> }
>
> @@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
> c->range.level[l].sens = levdatum->level->sens;
>
> ebitmap_init(&bitmap);
> - ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
> - if (ebitmap_node_get_bit(node, i)) {
> - int rc;
> -
> - catdatum = hashtab_search(newp->p_cats.table,
> - oldp->p_cat_val_to_name[i]);
> - if (!catdatum)
> - return -EINVAL;
> - rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
> - if (rc)
> - return rc;
> - }
> + ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
> + int rc;
> +
> + catdatum = hashtab_search(newp->p_cats.table,
> + oldp->p_cat_val_to_name[i]);
> + if (!catdatum)
> + return -EINVAL;
> + rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
> + if (rc)
> + return rc;
> }
> ebitmap_destroy(&c->range.level[l].cat);
> c->range.level[l].cat = bitmap;
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index 6100fc0..19be935 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext,
> avkey.specified = AVTAB_AV;
> sattr = &policydb.type_attr_map[scontext->type - 1];
> tattr = &policydb.type_attr_map[tcontext->type - 1];
> - ebitmap_for_each_bit(sattr, snode, i) {
> - if (!ebitmap_node_get_bit(snode, i))
> - continue;
> - ebitmap_for_each_bit(tattr, tnode, j) {
> - if (!ebitmap_node_get_bit(tnode, j))
> - continue;
> + ebitmap_for_each_positive_bit(sattr, snode, i) {
> + ebitmap_for_each_positive_bit(tattr, tnode, j) {
> avkey.source_type = i + 1;
> avkey.target_type = j + 1;
> for (node = avtab_search_node(&policydb.te_avtab, &avkey);
> @@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid,
> goto out_unlock;
> }
>
> - ebitmap_for_each_bit(&user->roles, rnode, i) {
> - if (!ebitmap_node_get_bit(rnode, i))
> - continue;
> + ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
> role = policydb.role_val_to_struct[i];
> usercon.role = i+1;
> - ebitmap_for_each_bit(&role->types, tnode, j) {
> - if (!ebitmap_node_get_bit(tnode, j))
> - continue;
> + ebitmap_for_each_positive_bit(&role->types, tnode, j) {
> usercon.type = j+1;
>
> if (mls_setup_user_range(fromcon, user, &usercon))
>
>
>
>
>
>
>
>
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-28 17:20 ` KaiGai Kohei
2007-09-28 18:40 ` Stephen Smalley
@ 2007-09-28 21:09 ` James Morris
2007-10-02 15:12 ` KaiGai Kohei
1 sibling, 1 reply; 52+ messages in thread
From: James Morris @ 2007-09-28 21:09 UTC (permalink / raw)
To: KaiGai Kohei
Cc: Stephen Smalley, selinux, Paul Moore, Yuichi Nakamura, Eric Paris
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1792 bytes --]
On Sat, 29 Sep 2007, KaiGai Kohei wrote:
> Stephen Smalley wrote:
> > On Fri, 2007-09-28 at 19:56 +0900, KaiGai Kohei wrote:
> >> James Morris wrote:
> >>>> ++ struct ebitmap_node *_n;
> >>>> ++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
> >>> Leading underscores are usually used to indicate that core code is not
> >>> supposed to use the symbol. Please change it to not have a leading
> >>> underscore. 'tmp' or 'n2' is probably ok.
> >> OK, I replaced all of '_n' by 'tmp'.
> >> Rest of the part in the following patch is same as the previous one.
> >
> > Seems to be damaged, or at least doesn't apply for me. What is it
> > relative to?
>
> I generated the patch against to the latest of James's git tree
> But it seems to me that all tab chatacters are translated into
> four white spaces, when I copied and pasted the patch.
> I'm sorry, it was my misoperation.
>
> Can you receive it with tab kept in this time?
Yes, but there are compiler warnings on 64-bit.
Please test it on a 64-bit machine.
$ make -j3 SUBDIRS=security
CC security/selinux/ss/ebitmap.o
CC security/selinux/ss/sidtab.o
CC security/selinux/ss/avtab.o
security/selinux/ss/ebitmap.c: In function âebitmap_netlbl_importâ:
security/selinux/ss/ebitmap.c:196: warning: right shift count >= width of type
security/selinux/ss/ebitmap.c: In function âebitmap_readâ:
security/selinux/ss/ebitmap.c:393: warning: format â%Zdâ expects type âsigned size_tâ, but argument 3 has type âu32â
security/selinux/ss/ebitmap.c:399: warning: format â%Zdâ expects type âsigned size_tâ, but argument 3 has type âu32â
security/selinux/ss/ebitmap.c:437: warning: right shift count >= width of type
--
James Morris
<jmorris@namei.org>
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-09-28 21:09 ` James Morris
@ 2007-10-02 15:12 ` KaiGai Kohei
2007-10-02 15:28 ` Stephen Smalley
0 siblings, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-10-02 15:12 UTC (permalink / raw)
To: James Morris
Cc: KaiGai Kohei, Stephen Smalley, selinux, Paul Moore,
Yuichi Nakamura, Eric Paris
James Morris wrote:
> On Sat, 29 Sep 2007, KaiGai Kohei wrote:
>
>> Stephen Smalley wrote:
>>> On Fri, 2007-09-28 at 19:56 +0900, KaiGai Kohei wrote:
>>>> James Morris wrote:
>>>>>> ++ struct ebitmap_node *_n;
>>>>>> ++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
>>>>> Leading underscores are usually used to indicate that core code is not
>>>>> supposed to use the symbol. Please change it to not have a leading
>>>>> underscore. 'tmp' or 'n2' is probably ok.
>>>> OK, I replaced all of '_n' by 'tmp'.
>>>> Rest of the part in the following patch is same as the previous one.
>>> Seems to be damaged, or at least doesn't apply for me. What is it
>>> relative to?
>> I generated the patch against to the latest of James's git tree
>> But it seems to me that all tab chatacters are translated into
>> four white spaces, when I copied and pasted the patch.
>> I'm sorry, it was my misoperation.
>>
>> Can you receive it with tab kept in this time?
>
> Yes, but there are compiler warnings on 64-bit.
>
> Please test it on a 64-bit machine.
>
> $ make -j3 SUBDIRS=security
> CC security/selinux/ss/ebitmap.o
> CC security/selinux/ss/sidtab.o
> CC security/selinux/ss/avtab.o
> security/selinux/ss/ebitmap.c: In function ‘ebitmap_netlbl_import’:
> security/selinux/ss/ebitmap.c:196: warning: right shift count >= width of type
> security/selinux/ss/ebitmap.c: In function ‘ebitmap_read’:
> security/selinux/ss/ebitmap.c:393: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’
> security/selinux/ss/ebitmap.c:399: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’
> security/selinux/ss/ebitmap.c:437: warning: right shift count >= width of type
The attached patch kills these warnings.
While killing them, I faced to a serious bug.
At first, I expected the following while { ... } block is never looped
multiple time in 64-bit architecture.
--------
+#if EBITMAP_UNIT_SIZE == 64
+ n->maps[index] = map;
+#else
while (map) {
n->maps[index] = map & (-1UL);
map = map >> EBITMAP_UNIT_SIZE;
index++;
}
+#endif
--------
However, I might misunderstand about the works of shift operations.
When we tries to shift a variable with the width of it, this operation
does not give us any effect.
See the following small code.
[kaigai@masu ~]$ cat hoge.c
#include <stdio.h>
int main(int argc, char *argv[]) {
unsigned long code = -1UL;
printf("code = %016lx\n", code);
printf("code >> 16 = %016lx\n", code >> 16);
printf("code >> 63 = %016lx\n", code >> 63);
printf("code >> 64 = %016lx\n", code >> 64);
printf("code >> 65 = %016lx\n", code >> 65);
return 0;
}
[kaigai@masu ~]$ env LANG=C gcc hoge.c
hoge.c: In function 'main':
hoge.c:9: warning: right shift count >= width of type
hoge.c:10: warning: right shift count >= width of type
[kaigai@masu ~]$ ./a.out
code = ffffffffffffffff
code >> 16 = 0000ffffffffffff
code >> 63 = 0000000000000001
code >> 64 = ffffffffffffffff
code >> 65 = 7fffffffffffffff
[kaigai@masu ~]$ uname -m
x86_64
I was suprised at. :-)
It is the reason why I put #if block to separate 64bit/32bit cases.
Do you have any idea to write it more simply?
----------------------------------------
[PATCH] kills warnings in Improve SELinux performance when AVC misses
This patch kills ugly warnings when the "Improve SELinux performance
when ACV misses" patch.
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
---
security/selinux/ss/ebitmap.c | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ae44c0c..2e21ca1 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -191,10 +191,14 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
delta = c_pos - e_iter->startbit;
e_idx = delta / EBITMAP_UNIT_SIZE;
e_sft = delta % EBITMAP_UNIT_SIZE;
+#if EBITMAP_UNIT_SIZE == 64
+ e_iter->maps[e_idx] |= map;
+#else
while (map) {
e_iter->maps[e_idx++] |= map & (-1UL);
map >>= EBITMAP_UNIT_SIZE;
}
+#endif
}
c_iter = c_iter->next;
} while (c_iter != NULL);
@@ -389,13 +393,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map unit size (%Zd)\n",
+ "not a multiple of the map unit size (%u)\n",
startbit, mapunit);
goto bad;
}
if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "beyond the end of the bitmap (%Zd)\n",
+ "beyond the end of the bitmap (%u)\n",
startbit, (e->highbit - mapunit));
goto bad;
}
@@ -432,11 +436,15 @@ int ebitmap_read(struct ebitmap *e, void *fp)
map = le64_to_cpu(map);
index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
+#if EBITMAP_UNIT_SIZE == 64
+ n->maps[index] = map;
+#else
while (map) {
n->maps[index] = map & (-1UL);
map = map >> EBITMAP_UNIT_SIZE;
index++;
}
+#endif
}
ok:
rc = 0;
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-10-02 15:12 ` KaiGai Kohei
@ 2007-10-02 15:28 ` Stephen Smalley
2007-10-03 13:41 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: Stephen Smalley @ 2007-10-02 15:28 UTC (permalink / raw)
To: KaiGai Kohei
Cc: James Morris, KaiGai Kohei, selinux, Paul Moore, Yuichi Nakamura,
Eric Paris
On Wed, 2007-10-03 at 00:12 +0900, KaiGai Kohei wrote:
> James Morris wrote:
> > On Sat, 29 Sep 2007, KaiGai Kohei wrote:
> >
> >> Stephen Smalley wrote:
> >>> On Fri, 2007-09-28 at 19:56 +0900, KaiGai Kohei wrote:
> >>>> James Morris wrote:
> >>>>>> ++ struct ebitmap_node *_n;
> >>>>>> ++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
> >>>>> Leading underscores are usually used to indicate that core code is not
> >>>>> supposed to use the symbol. Please change it to not have a leading
> >>>>> underscore. 'tmp' or 'n2' is probably ok.
> >>>> OK, I replaced all of '_n' by 'tmp'.
> >>>> Rest of the part in the following patch is same as the previous one.
> >>> Seems to be damaged, or at least doesn't apply for me. What is it
> >>> relative to?
> >> I generated the patch against to the latest of James's git tree
> >> But it seems to me that all tab chatacters are translated into
> >> four white spaces, when I copied and pasted the patch.
> >> I'm sorry, it was my misoperation.
> >>
> >> Can you receive it with tab kept in this time?
> >
> > Yes, but there are compiler warnings on 64-bit.
> >
> > Please test it on a 64-bit machine.
> >
> > $ make -j3 SUBDIRS=security
> > CC security/selinux/ss/ebitmap.o
> > CC security/selinux/ss/sidtab.o
> > CC security/selinux/ss/avtab.o
> > security/selinux/ss/ebitmap.c: In function ‘ebitmap_netlbl_import’:
> > security/selinux/ss/ebitmap.c:196: warning: right shift count >= width of type
> > security/selinux/ss/ebitmap.c: In function ‘ebitmap_read’:
> > security/selinux/ss/ebitmap.c:393: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’
> > security/selinux/ss/ebitmap.c:399: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’
> > security/selinux/ss/ebitmap.c:437: warning: right shift count >= width of type
>
> The attached patch kills these warnings.
>
> While killing them, I faced to a serious bug.
> At first, I expected the following while { ... } block is never looped
> multiple time in 64-bit architecture.
>
> --------
> +#if EBITMAP_UNIT_SIZE == 64
> + n->maps[index] = map;
> +#else
> while (map) {
> n->maps[index] = map & (-1UL);
> map = map >> EBITMAP_UNIT_SIZE;
> index++;
> }
> +#endif
> --------
>
> However, I might misunderstand about the works of shift operations.
> When we tries to shift a variable with the width of it, this operation
> does not give us any effect.
>
> See the following small code.
>
> [kaigai@masu ~]$ cat hoge.c
> #include <stdio.h>
>
> int main(int argc, char *argv[]) {
> unsigned long code = -1UL;
>
> printf("code = %016lx\n", code);
> printf("code >> 16 = %016lx\n", code >> 16);
> printf("code >> 63 = %016lx\n", code >> 63);
> printf("code >> 64 = %016lx\n", code >> 64);
> printf("code >> 65 = %016lx\n", code >> 65);
>
> return 0;
> }
> [kaigai@masu ~]$ env LANG=C gcc hoge.c
> hoge.c: In function 'main':
> hoge.c:9: warning: right shift count >= width of type
> hoge.c:10: warning: right shift count >= width of type
> [kaigai@masu ~]$ ./a.out
> code = ffffffffffffffff
> code >> 16 = 0000ffffffffffff
> code >> 63 = 0000000000000001
> code >> 64 = ffffffffffffffff
> code >> 65 = 7fffffffffffffff
> [kaigai@masu ~]$ uname -m
> x86_64
>
> I was suprised at. :-)
Me too. But see:
http://gcc.gnu.org/ml/gcc/2004-11/msg01133.html
http://marc.info/?t=118688311400003&r=1&w=2
> It is the reason why I put #if block to separate 64bit/32bit cases.
>
> Do you have any idea to write it more simply?
>
> ----------------------------------------
> [PATCH] kills warnings in Improve SELinux performance when AVC misses
>
> This patch kills ugly warnings when the "Improve SELinux performance
> when ACV misses" patch.
>
> Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
> ---
> security/selinux/ss/ebitmap.c | 12 ++++++++++--
> 1 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
> index ae44c0c..2e21ca1 100644
> --- a/security/selinux/ss/ebitmap.c
> +++ b/security/selinux/ss/ebitmap.c
> @@ -191,10 +191,14 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
> delta = c_pos - e_iter->startbit;
> e_idx = delta / EBITMAP_UNIT_SIZE;
> e_sft = delta % EBITMAP_UNIT_SIZE;
> +#if EBITMAP_UNIT_SIZE == 64
> + e_iter->maps[e_idx] |= map;
> +#else
> while (map) {
> e_iter->maps[e_idx++] |= map & (-1UL);
> map >>= EBITMAP_UNIT_SIZE;
> }
> +#endif
> }
> c_iter = c_iter->next;
> } while (c_iter != NULL);
> @@ -389,13 +393,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
>
> if (startbit & (mapunit - 1)) {
> printk(KERN_ERR "security: ebitmap start bit (%d) is "
> - "not a multiple of the map unit size (%Zd)\n",
> + "not a multiple of the map unit size (%u)\n",
> startbit, mapunit);
> goto bad;
> }
> if (startbit > e->highbit - mapunit) {
> printk(KERN_ERR "security: ebitmap start bit (%d) is "
> - "beyond the end of the bitmap (%Zd)\n",
> + "beyond the end of the bitmap (%u)\n",
> startbit, (e->highbit - mapunit));
> goto bad;
> }
> @@ -432,11 +436,15 @@ int ebitmap_read(struct ebitmap *e, void *fp)
> map = le64_to_cpu(map);
>
> index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
> +#if EBITMAP_UNIT_SIZE == 64
> + n->maps[index] = map;
> +#else
> while (map) {
> n->maps[index] = map & (-1UL);
> map = map >> EBITMAP_UNIT_SIZE;
> index++;
> }
> +#endif
> }
> ok:
> rc = 0;
>
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-10-02 15:28 ` Stephen Smalley
@ 2007-10-03 13:41 ` KaiGai Kohei
2007-10-03 14:42 ` KaiGai Kohei
0 siblings, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-10-03 13:41 UTC (permalink / raw)
To: Stephen Smalley
Cc: James Morris, KaiGai Kohei, selinux, Paul Moore, Yuichi Nakamura,
Eric Paris
>> --------
>> +#if EBITMAP_UNIT_SIZE == 64
>> + n->maps[index] = map;
>> +#else
>> while (map) {
>> n->maps[index] = map & (-1UL);
>> map = map >> EBITMAP_UNIT_SIZE;
>> index++;
>> }
>> +#endif
>> --------
- snip -
>> [kaigai@masu ~]$ ./a.out
>> code = ffffffffffffffff
>> code >> 16 = 0000ffffffffffff
>> code >> 63 = 0000000000000001
>> code >> 64 = ffffffffffffffff
>> code >> 65 = 7fffffffffffffff
>> [kaigai@masu ~]$ uname -m
>> x86_64
>>
>> I was suprised at. :-)
>
> Me too. But see:
> http://gcc.gnu.org/ml/gcc/2004-11/msg01133.html
> http://marc.info/?t=118688311400003&r=1&w=2
#if ... #endif block was removed in the previous patch.
I added a macro that shifts a variable by the width of unsigned long,
defined as follows:
#define EBITMAP_SHIFT_UNIT_SIZE(x) \
(((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)
[PATCH] kills warnings in Improve SELinux performance when AVC misses
This patch kills ugly warnings when the "Improve SELinux performance
when ACV misses" patch.
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
---
security/selinux/ss/ebitmap.c | 11 +++++------
security/selinux/ss/ebitmap.h | 2 ++
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ae44c0c..c1a6b22 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -193,7 +193,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
e_sft = delta % EBITMAP_UNIT_SIZE;
while (map) {
e_iter->maps[e_idx++] |= map & (-1UL);
- map >>= EBITMAP_UNIT_SIZE;
+ map = EBITMAP_SHIFT_UNIT_SIZE(map);
}
}
c_iter = c_iter->next;
@@ -389,13 +389,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map unit size (%Zd)\n",
+ "not a multiple of the map unit size (%u)\n",
startbit, mapunit);
goto bad;
}
if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "beyond the end of the bitmap (%Zd)\n",
+ "beyond the end of the bitmap (%u)\n",
startbit, (e->highbit - mapunit));
goto bad;
}
@@ -433,9 +433,8 @@ int ebitmap_read(struct ebitmap *e, void *fp)
index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
while (map) {
- n->maps[index] = map & (-1UL);
- map = map >> EBITMAP_UNIT_SIZE;
- index++;
+ n->maps[index++] = map & (-1UL);
+ map = EBITMAP_SHIFT_UNIT_SIZE(map);
}
}
ok:
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index e38a327..f283b43 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -21,6 +21,8 @@
#define EBITMAP_UNIT_SIZE BITS_PER_LONG
#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
#define EBITMAP_BIT 1ULL
+#define EBITMAP_SHIFT_UNIT_SIZE(x) \
+ (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)
struct ebitmap_node {
struct ebitmap_node *next;
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-10-03 13:41 ` KaiGai Kohei
@ 2007-10-03 14:42 ` KaiGai Kohei
2007-10-04 0:37 ` James Morris
0 siblings, 1 reply; 52+ messages in thread
From: KaiGai Kohei @ 2007-10-03 14:42 UTC (permalink / raw)
To: Stephen Smalley
Cc: James Morris, KaiGai Kohei, selinux, Paul Moore, Yuichi Nakamura,
Eric Paris
>>> I was suprised at. :-)
>>
>> Me too. But see:
>> http://gcc.gnu.org/ml/gcc/2004-11/msg01133.html
>> http://marc.info/?t=118688311400003&r=1&w=2
>
> #if ... #endif block was removed in the previous patch.
> I added a macro that shifts a variable by the width of unsigned long,
> defined as follows:
>
> #define EBITMAP_SHIFT_UNIT_SIZE(x) \
> (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)
>
> [PATCH] kills warnings in Improve SELinux performance when AVC misses
Sorry, tab character were polluted again.
It seems to me that Thunderbird replace tab character into four white
spaces when I use "Content-Type: text/plain; charset=UTF-8".
I resend this one as follows.
[PATCH] kills warnings in Improve SELinux performance when AVC misses
This patch kills ugly warnings when the "Improve SELinux performance
when ACV misses" patch.
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
---
security/selinux/ss/ebitmap.c | 11 +++++------
security/selinux/ss/ebitmap.h | 2 ++
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ae44c0c..c1a6b22 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -193,7 +193,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
e_sft = delta % EBITMAP_UNIT_SIZE;
while (map) {
e_iter->maps[e_idx++] |= map & (-1UL);
- map >>= EBITMAP_UNIT_SIZE;
+ map = EBITMAP_SHIFT_UNIT_SIZE(map);
}
}
c_iter = c_iter->next;
@@ -389,13 +389,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "not a multiple of the map unit size (%Zd)\n",
+ "not a multiple of the map unit size (%u)\n",
startbit, mapunit);
goto bad;
}
if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
- "beyond the end of the bitmap (%Zd)\n",
+ "beyond the end of the bitmap (%u)\n",
startbit, (e->highbit - mapunit));
goto bad;
}
@@ -433,9 +433,8 @@ int ebitmap_read(struct ebitmap *e, void *fp)
index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
while (map) {
- n->maps[index] = map & (-1UL);
- map = map >> EBITMAP_UNIT_SIZE;
- index++;
+ n->maps[index++] = map & (-1UL);
+ map = EBITMAP_SHIFT_UNIT_SIZE(map);
}
}
ok:
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index e38a327..f283b43 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -21,6 +21,8 @@
#define EBITMAP_UNIT_SIZE BITS_PER_LONG
#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
#define EBITMAP_BIT 1ULL
+#define EBITMAP_SHIFT_UNIT_SIZE(x) \
+ (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)
struct ebitmap_node {
struct ebitmap_node *next;
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH] Improve SELinux performance when AVC misses.
2007-10-03 14:42 ` KaiGai Kohei
@ 2007-10-04 0:37 ` James Morris
0 siblings, 0 replies; 52+ messages in thread
From: James Morris @ 2007-10-04 0:37 UTC (permalink / raw)
To: KaiGai Kohei
Cc: Stephen Smalley, KaiGai Kohei, selinux, Paul Moore,
Yuichi Nakamura, Eric Paris
All applied to
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6.git#for-akpm
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2007-08-24 2:55 ` Yuichi Nakamura
2007-08-27 13:39 ` Stephen Smalley
@ 2008-01-31 21:00 ` Stephen Smalley
2008-01-31 21:44 ` Stephen Smalley
2008-02-01 4:59 ` Yuichi Nakamura
1 sibling, 2 replies; 52+ messages in thread
From: Stephen Smalley @ 2008-01-31 21:00 UTC (permalink / raw)
To: Yuichi Nakamura
Cc: James Morris, selinux, busybox, Eric Paris, kaigai,
Joshua Brindle, Todd C. Miller, Chad Sellers
On Fri, 2007-08-24 at 11:55 +0900, Yuichi Nakamura wrote:
> On Thu, 23 Aug 2007 09:15:25 -0400
> Stephen Smalley wrote:
> > On Thu, 2007-08-23 at 09:57 +0900, Yuichi Nakamura wrote:
> > > Following is updated patch to 2.6.22.
> > >
> > > Signed-off-by: Yuichi Nakamura<ynakam@hitachisoft.jp>
> > > ---
> > > security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++-----------
> > > security/selinux/ss/avtab.h | 16 +++++--
> > > security/selinux/ss/conditional.c | 4 +
> > > security/selinux/ss/policydb.c | 7 ---
> > > 4 files changed, 73 insertions(+), 32 deletions(-)
> > > diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
> > > --- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
> > > +++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-23 09:30:03.000000000 +0900
> > > +int avtab_alloc(struct avtab *h, int nrules)
> >
> > nrules should be u32 too.
> Fixed.
>
> >
> > And you should likely test for the degenerate case (nrules == 0) and
> > bail on it.
> Checking nrules==0.
> And also checking !h->htable like below in avtab_search_node etc.
> - if (!h)
> + if (!h || !h->htable)
>
> Following is updated patch.
> From: Yuichi Nakamura <ynakam@hitachisoft.jp>
>
> 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>
> ---
> security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++-----------
> security/selinux/ss/avtab.h | 16 ++++--
> security/selinux/ss/conditional.c | 4 +
> security/selinux/ss/policydb.c | 7 --
> 4 files changed, 82 insertions(+), 36 deletions(-)
Hi,
I'd like to apply the equivalent changes to libsepol, if you have no
objection (note that libsepol is LGPL rather than GPL). A port of your
patch to libsepol is below. This is to reduce memory usage by
libsepol/libsemanage when reading in modules and policies. Is that ok
with you?
checkpolicy/test/dispol.c | 2
libsepol/include/sepol/policydb/avtab.h | 18 ++++---
libsepol/src/avtab.c | 80 ++++++++++++++++++++++++--------
libsepol/src/conditional.c | 4 +
libsepol/src/policydb.c | 7 --
libsepol/src/write.c | 11 ++--
6 files changed, 85 insertions(+), 37 deletions(-)
Index: libsepol/include/sepol/policydb/avtab.h
===================================================================
--- libsepol/include/sepol/policydb/avtab.h (revision 2773)
+++ libsepol/include/sepol/policydb/avtab.h (working copy)
@@ -1,6 +1,11 @@
/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+/*
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
+ */
+
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
@@ -75,10 +80,12 @@
typedef struct avtab {
avtab_ptr_t *htable;
uint32_t nel; /* number of elements */
+ uint32_t nslot; /* number of hash slots */
+ uint16_t mask; /* mask to compute hash func */
} avtab_t;
extern int avtab_init(avtab_t *);
-
+extern int avtab_alloc(avtab_t *, uint32_t);
extern int avtab_insert(avtab_t * h, avtab_key_t * k, avtab_datum_t * d);
extern avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * k);
@@ -110,12 +117,11 @@
extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified);
-#define AVTAB_HASH_BITS 15
-#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
-#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_HASH_BITS 13
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
-#define AVTAB_SIZE AVTAB_HASH_BUCKETS
-
#endif /* _AVTAB_H_ */
/* FLASK */
Index: libsepol/src/conditional.c
===================================================================
--- libsepol/src/conditional.c (revision 2773)
+++ libsepol/src/conditional.c (working copy)
@@ -829,6 +829,10 @@
len = le32_to_cpu(buf[0]);
+ rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel);
+ if (rc)
+ goto err;
+
for (i = 0; i < len; i++) {
node = malloc(sizeof(cond_node_t));
if (!node)
Index: libsepol/src/policydb.c
===================================================================
--- libsepol/src/policydb.c (revision 2773)
+++ libsepol/src/policydb.c (working copy)
@@ -492,17 +492,14 @@
rc = roles_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
rc = cond_policydb_init(p);
if (rc)
- goto out_free_avtab;
+ goto out_free_symtab;
out:
return rc;
- out_free_avtab:
- avtab_destroy(&p->te_avtab);
-
out_free_symtab:
for (i = 0; i < SYM_NUM; i++) {
hashtab_destroy(p->symtab[i].table);
Index: libsepol/src/write.c
===================================================================
--- libsepol/src/write.c (revision 2773)
+++ libsepol/src/write.c (working copy)
@@ -229,9 +229,9 @@
static inline void avtab_reset_merged(avtab_t * a)
{
- int i;
+ unsigned int i;
avtab_ptr_t cur;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < a->nslot; i++) {
for (cur = a->htable[i]; cur; cur = cur->next)
cur->merged = 0;
}
@@ -239,7 +239,8 @@
static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
{
- int i, rc;
+ unsigned int i;
+ int rc;
avtab_t expa;
avtab_ptr_t cur;
uint32_t nel;
@@ -269,7 +270,7 @@
return POLICYDB_ERROR;
}
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < a->nslot; i++) {
for (cur = a->htable[i]; cur; cur = cur->next) {
/* If old format, compute final nel.
If new format, write out the items. */
@@ -290,7 +291,7 @@
goto out;
}
avtab_reset_merged(a);
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < a->nslot; i++) {
for (cur = a->htable[i]; cur; cur = cur->next) {
if (avtab_write_item(p, cur, fp, 1, 1, NULL)) {
rc = -1;
Index: libsepol/src/avtab.c
===================================================================
--- libsepol/src/avtab.c (revision 2773)
+++ libsepol/src/avtab.c (working copy)
@@ -1,6 +1,11 @@
/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+/*
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
+ */
+
/* Updated: Frank Mayer <mayerf@tresys.com>
* and Karl MacMillan <kmacmillan@mentalrootkit.com>
*
@@ -44,11 +49,11 @@
#include "debug.h"
#include "private.h"
-#define AVTAB_HASH(keyp) \
-((keyp->target_class + \
- (keyp->target_type << 2) + \
- (keyp->source_type << 9)) & \
- AVTAB_HASH_MASK)
+static inline int avtab_hash(struct avtab_key *keyp, uint16_t mask)
+{
+ return ((keyp->target_class + (keyp->target_type << 2) +
+ (keyp->source_type << 9)) & mask);
+}
static avtab_ptr_t
avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
@@ -83,7 +88,7 @@
if (!h)
return SEPOL_ENOMEM;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur; prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
@@ -123,7 +128,7 @@
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
cur; prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
@@ -156,7 +161,7 @@
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -191,7 +196,7 @@
if (!h)
return NULL;
- hvalue = AVTAB_HASH(key);
+ hvalue = avtab_hash(key, h->mask);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -242,13 +247,13 @@
void avtab_destroy(avtab_t * h)
{
- int i;
+ unsigned int i;
avtab_ptr_t cur, temp;
if (!h || !h->htable)
return;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
while (cur != NULL) {
temp = cur;
@@ -259,19 +264,22 @@
}
free(h->htable);
h->htable = NULL;
+ h->nslot = 0;
+ h->mask = 0;
}
int avtab_map(avtab_t * h,
int (*apply) (avtab_key_t * k,
avtab_datum_t * d, void *args), void *args)
{
- int i, ret;
+ unsigned int i;
+ int ret;
avtab_ptr_t cur;
if (!h)
return 0;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
while (cur != NULL) {
ret = apply(&cur->key, &cur->datum, args);
@@ -285,25 +293,50 @@
int avtab_init(avtab_t * h)
{
- int i;
+ h->htable = NULL;
+ h->nel = 0;
+ return 0;
+}
- h->htable = malloc(sizeof(avtab_ptr_t) * AVTAB_SIZE);
+int avtab_alloc(avtab_t *h, uint32_t nrules)
+{
+ uint16_t mask = 0;
+ uint32_t shift = 0;
+ uint32_t work = nrules;
+ uint32_t nslot = 0;
+
+ if (nrules == 0)
+ goto out;
+
+ while (work) {
+ work = work >> 1;
+ shift++;
+ }
+ if (shift > 2)
+ shift = shift - 2;
+ nslot = 1 << shift;
+ if (nslot > MAX_AVTAB_SIZE)
+ nslot = MAX_AVTAB_SIZE;
+ mask = nslot - 1;
+
+ h->htable = calloc(nslot, sizeof(avtab_ptr_t));
if (!h->htable)
return -1;
- for (i = 0; i < AVTAB_SIZE; i++)
- h->htable[i] = (avtab_ptr_t) NULL;
+out:
h->nel = 0;
+ h->nslot = nslot;
+ h->mask = mask;
return 0;
}
void avtab_hash_eval(avtab_t * h, char *tag)
{
- int i, chain_len, slots_used, max_chain_len;
+ unsigned int i, chain_len, slots_used, max_chain_len;
avtab_ptr_t cur;
slots_used = 0;
max_chain_len = 0;
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < h->nslot; i++) {
cur = h->htable[i];
if (cur) {
slots_used++;
@@ -320,7 +353,7 @@
printf
("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
- tag, h->nel, slots_used, AVTAB_SIZE, max_chain_len);
+ tag, h->nel, slots_used, h->nslot, max_chain_len);
}
/* Ordering of datums in the original avtab format in the policy file. */
@@ -471,6 +504,13 @@
ERR(fp->handle, "table is empty");
goto bad;
}
+
+ rc = avtab_alloc(a, nel);
+ if (rc) {
+ ERR(fp->handle, "out of memory");
+ goto bad;
+ }
+
for (i = 0; i < nel; i++) {
rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL);
if (rc) {
Index: checkpolicy/test/dispol.c
===================================================================
--- checkpolicy/test/dispol.c (revision 2773)
+++ checkpolicy/test/dispol.c (working copy)
@@ -169,7 +169,7 @@
}
/* hmm...should have used avtab_map. */
- for (i = 0; i < AVTAB_SIZE; i++) {
+ for (i = 0; i < expa.nslot; i++) {
for (cur = expa.htable[i]; cur; cur = cur->next) {
render_av_rule(&cur->key, &cur->datum, what, p, fp);
}
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2008-01-31 21:00 ` Stephen Smalley
@ 2008-01-31 21:44 ` Stephen Smalley
2008-02-01 4:59 ` Yuichi Nakamura
1 sibling, 0 replies; 52+ messages in thread
From: Stephen Smalley @ 2008-01-31 21:44 UTC (permalink / raw)
To: Yuichi Nakamura
Cc: James Morris, selinux, busybox, Eric Paris, kaigai,
Joshua Brindle, Todd C. Miller, Chad Sellers
On Thu, 2008-01-31 at 16:00 -0500, Stephen Smalley wrote:
> On Fri, 2007-08-24 at 11:55 +0900, Yuichi Nakamura wrote:
> > On Thu, 23 Aug 2007 09:15:25 -0400
> > Stephen Smalley wrote:
> > > On Thu, 2007-08-23 at 09:57 +0900, Yuichi Nakamura wrote:
> > > > Following is updated patch to 2.6.22.
> > > >
> > > > Signed-off-by: Yuichi Nakamura<ynakam@hitachisoft.jp>
> > > > ---
> > > > security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++-----------
> > > > security/selinux/ss/avtab.h | 16 +++++--
> > > > security/selinux/ss/conditional.c | 4 +
> > > > security/selinux/ss/policydb.c | 7 ---
> > > > 4 files changed, 73 insertions(+), 32 deletions(-)
> > > > diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
> > > > --- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
> > > > +++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-23 09:30:03.000000000 +0900
> > > > +int avtab_alloc(struct avtab *h, int nrules)
> > >
> > > nrules should be u32 too.
> > Fixed.
> >
> > >
> > > And you should likely test for the degenerate case (nrules == 0) and
> > > bail on it.
> > Checking nrules==0.
> > And also checking !h->htable like below in avtab_search_node etc.
> > - if (!h)
> > + if (!h || !h->htable)
> >
> > Following is updated patch.
> > From: Yuichi Nakamura <ynakam@hitachisoft.jp>
> >
> > 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>
> > ---
> > security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++-----------
> > security/selinux/ss/avtab.h | 16 ++++--
> > security/selinux/ss/conditional.c | 4 +
> > security/selinux/ss/policydb.c | 7 --
> > 4 files changed, 82 insertions(+), 36 deletions(-)
>
> Hi,
>
> I'd like to apply the equivalent changes to libsepol, if you have no
> objection (note that libsepol is LGPL rather than GPL). A port of your
> patch to libsepol is below. This is to reduce memory usage by
> libsepol/libsemanage when reading in modules and policies. Is that ok
> with you?
>
> checkpolicy/test/dispol.c | 2
> libsepol/include/sepol/policydb/avtab.h | 18 ++++---
> libsepol/src/avtab.c | 80 ++++++++++++++++++++++++--------
> libsepol/src/conditional.c | 4 +
> libsepol/src/policydb.c | 7 --
> libsepol/src/write.c | 11 ++--
> 6 files changed, 85 insertions(+), 37 deletions(-)
Some further fixes below, relative to the prior patch.
diff -u libsepol/src/avtab.c libsepol/src/avtab.c
--- libsepol/src/avtab.c (working copy)
+++ libsepol/src/avtab.c (working copy)
@@ -85,7 +85,7 @@
uint16_t specified =
key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
- if (!h)
+ if (!h || !h->htable)
return SEPOL_ENOMEM;
hvalue = avtab_hash(key, h->mask);
@@ -126,7 +126,7 @@
uint16_t specified =
key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
- if (!h)
+ if (!h || !h->htable)
return NULL;
hvalue = avtab_hash(key, h->mask);
for (prev = NULL, cur = h->htable[hvalue];
@@ -158,7 +158,7 @@
uint16_t specified =
key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
- if (!h)
+ if (!h || !h->htable)
return NULL;
hvalue = avtab_hash(key, h->mask);
@@ -193,7 +193,7 @@
uint16_t specified =
key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
- if (!h)
+ if (!h || !h->htable)
return NULL;
hvalue = avtab_hash(key, h->mask);
--- libsepol/src/expand.c (revision 2773)
+++ libsepol/src/expand.c (working copy)
@@ -2137,6 +2138,16 @@
avrule_block_t *curblock;
int retval = -1;
+ if (avtab_alloc(&state->out->te_avtab, MAX_AVTAB_SIZE)) {
+ ERR(state->handle, "Out of Memory!");
+ return -1;
+ }
+
+ if (avtab_alloc(&state->out->te_cond_avtab, MAX_AVTAB_SIZE)) {
+ ERR(state->handle, "Out of Memory!");
+ return -1;
+ }
+
for (curblock = state->base->global; curblock != NULL;
curblock = curblock->next) {
avrule_decl_t *decl = curblock->enabled;
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [patch] Tuning avtab to reduce memory usage
2008-01-31 21:00 ` Stephen Smalley
2008-01-31 21:44 ` Stephen Smalley
@ 2008-02-01 4:59 ` Yuichi Nakamura
1 sibling, 0 replies; 52+ messages in thread
From: Yuichi Nakamura @ 2008-02-01 4:59 UTC (permalink / raw)
To: Stephen Smalley
Cc: ynakam, James Morris, selinux, busybox, Eric Paris, kaigai,
Joshua Brindle, Todd C. Miller, Chad Sellers
Hi.
On Thu, 31 Jan 2008 16:00:50 -0500
Stephen Smalley wrote:
>
> On Fri, 2007-08-24 at 11:55 +0900, Yuichi Nakamura wrote:
> > On Thu, 23 Aug 2007 09:15:25 -0400
> > Stephen Smalley wrote:
> > > On Thu, 2007-08-23 at 09:57 +0900, Yuichi Nakamura wrote:
> > > > Following is updated patch to 2.6.22.
> > > >
> > > > Signed-off-by: Yuichi Nakamura<ynakam@hitachisoft.jp>
> > > > ---
> > > > security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++-----------
> > > > security/selinux/ss/avtab.h | 16 +++++--
> > > > security/selinux/ss/conditional.c | 4 +
> > > > security/selinux/ss/policydb.c | 7 ---
> > > > 4 files changed, 73 insertions(+), 32 deletions(-)
> > > > diff -purN -X linux-2.6.22/Documentation/dontdiff linux-2.6.22.orig/security/selinux/ss/avtab.c linux-2.6.22/security/selinux/ss/avtab.c
> > > > --- linux-2.6.22.orig/security/selinux/ss/avtab.c 2007-07-09 08:32:17.000000000 +0900
> > > > +++ linux-2.6.22/security/selinux/ss/avtab.c 2007-08-23 09:30:03.000000000 +0900
> > > > +int avtab_alloc(struct avtab *h, int nrules)
> > >
> > > nrules should be u32 too.
> > Fixed.
> >
> > >
> > > And you should likely test for the degenerate case (nrules == 0) and
> > > bail on it.
> > Checking nrules==0.
> > And also checking !h->htable like below in avtab_search_node etc.
> > - if (!h)
> > + if (!h || !h->htable)
> >
> > Following is updated patch.
> > From: Yuichi Nakamura <ynakam@hitachisoft.jp>
> >
> > 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>
> > ---
> > security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++-----------
> > security/selinux/ss/avtab.h | 16 ++++--
> > security/selinux/ss/conditional.c | 4 +
> > security/selinux/ss/policydb.c | 7 --
> > 4 files changed, 82 insertions(+), 36 deletions(-)
>
> Hi,
>
> I'd like to apply the equivalent changes to libsepol, if you have no
> objection (note that libsepol is LGPL rather than GPL). A port of your
> patch to libsepol is below. This is to reduce memory usage by
> libsepol/libsemanage when reading in modules and policies. Is that ok
> with you?
It is OK for me.
Please use the code.
>
> checkpolicy/test/dispol.c | 2
> libsepol/include/sepol/policydb/avtab.h | 18 ++++---
> libsepol/src/avtab.c | 80 ++++++++++++++++++++++++--------
> libsepol/src/conditional.c | 4 +
> libsepol/src/policydb.c | 7 --
> libsepol/src/write.c | 11 ++--
> 6 files changed, 85 insertions(+), 37 deletions(-)
>
> Index: libsepol/include/sepol/policydb/avtab.h
> ===================================================================
> --- libsepol/include/sepol/policydb/avtab.h (revision 2773)
> +++ libsepol/include/sepol/policydb/avtab.h (working copy)
> @@ -1,6 +1,11 @@
>
> /* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
>
> +/*
> + * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
> + * Tuned number of hash slots for avtab to reduce memory usage
> + */
> +
> /* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
> *
> * Added conditional policy language extensions
> @@ -75,10 +80,12 @@
> typedef struct avtab {
> avtab_ptr_t *htable;
> uint32_t nel; /* number of elements */
> + uint32_t nslot; /* number of hash slots */
> + uint16_t mask; /* mask to compute hash func */
> } avtab_t;
>
> extern int avtab_init(avtab_t *);
> -
> +extern int avtab_alloc(avtab_t *, uint32_t);
> extern int avtab_insert(avtab_t * h, avtab_key_t * k, avtab_datum_t * d);
>
> extern avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * k);
> @@ -110,12 +117,11 @@
>
> extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified);
>
> -#define AVTAB_HASH_BITS 15
> -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
> -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
> +#define MAX_AVTAB_HASH_BITS 13
> +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
> +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
> +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
>
> -#define AVTAB_SIZE AVTAB_HASH_BUCKETS
> -
> #endif /* _AVTAB_H_ */
>
> /* FLASK */
> Index: libsepol/src/conditional.c
> ===================================================================
> --- libsepol/src/conditional.c (revision 2773)
> +++ libsepol/src/conditional.c (working copy)
> @@ -829,6 +829,10 @@
>
> len = le32_to_cpu(buf[0]);
>
> + rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel);
> + if (rc)
> + goto err;
> +
> for (i = 0; i < len; i++) {
> node = malloc(sizeof(cond_node_t));
> if (!node)
> Index: libsepol/src/policydb.c
> ===================================================================
> --- libsepol/src/policydb.c (revision 2773)
> +++ libsepol/src/policydb.c (working copy)
> @@ -492,17 +492,14 @@
>
> rc = roles_init(p);
> if (rc)
> - goto out_free_avtab;
> + goto out_free_symtab;
>
> rc = cond_policydb_init(p);
> if (rc)
> - goto out_free_avtab;
> + goto out_free_symtab;
> out:
> return rc;
>
> - out_free_avtab:
> - avtab_destroy(&p->te_avtab);
> -
> out_free_symtab:
> for (i = 0; i < SYM_NUM; i++) {
> hashtab_destroy(p->symtab[i].table);
> Index: libsepol/src/write.c
> ===================================================================
> --- libsepol/src/write.c (revision 2773)
> +++ libsepol/src/write.c (working copy)
> @@ -229,9 +229,9 @@
>
> static inline void avtab_reset_merged(avtab_t * a)
> {
> - int i;
> + unsigned int i;
> avtab_ptr_t cur;
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < a->nslot; i++) {
> for (cur = a->htable[i]; cur; cur = cur->next)
> cur->merged = 0;
> }
> @@ -239,7 +239,8 @@
>
> static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
> {
> - int i, rc;
> + unsigned int i;
> + int rc;
> avtab_t expa;
> avtab_ptr_t cur;
> uint32_t nel;
> @@ -269,7 +270,7 @@
> return POLICYDB_ERROR;
> }
>
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < a->nslot; i++) {
> for (cur = a->htable[i]; cur; cur = cur->next) {
> /* If old format, compute final nel.
> If new format, write out the items. */
> @@ -290,7 +291,7 @@
> goto out;
> }
> avtab_reset_merged(a);
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < a->nslot; i++) {
> for (cur = a->htable[i]; cur; cur = cur->next) {
> if (avtab_write_item(p, cur, fp, 1, 1, NULL)) {
> rc = -1;
> Index: libsepol/src/avtab.c
> ===================================================================
> --- libsepol/src/avtab.c (revision 2773)
> +++ libsepol/src/avtab.c (working copy)
> @@ -1,6 +1,11 @@
>
> /* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
>
> +/*
> + * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
> + * Tuned number of hash slots for avtab to reduce memory usage
> + */
> +
> /* Updated: Frank Mayer <mayerf@tresys.com>
> * and Karl MacMillan <kmacmillan@mentalrootkit.com>
> *
> @@ -44,11 +49,11 @@
> #include "debug.h"
> #include "private.h"
>
> -#define AVTAB_HASH(keyp) \
> -((keyp->target_class + \
> - (keyp->target_type << 2) + \
> - (keyp->source_type << 9)) & \
> - AVTAB_HASH_MASK)
> +static inline int avtab_hash(struct avtab_key *keyp, uint16_t mask)
> +{
> + return ((keyp->target_class + (keyp->target_type << 2) +
> + (keyp->source_type << 9)) & mask);
> +}
>
> static avtab_ptr_t
> avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
> @@ -83,7 +88,7 @@
> if (!h)
> return SEPOL_ENOMEM;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = avtab_hash(key, h->mask);
> for (prev = NULL, cur = h->htable[hvalue];
> cur; prev = cur, cur = cur->next) {
> if (key->source_type == cur->key.source_type &&
> @@ -123,7 +128,7 @@
>
> if (!h)
> return NULL;
> - hvalue = AVTAB_HASH(key);
> + hvalue = avtab_hash(key, h->mask);
> for (prev = NULL, cur = h->htable[hvalue];
> cur; prev = cur, cur = cur->next) {
> if (key->source_type == cur->key.source_type &&
> @@ -156,7 +161,7 @@
> if (!h)
> return NULL;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = avtab_hash(key, h->mask);
> for (cur = h->htable[hvalue]; cur; cur = cur->next) {
> if (key->source_type == cur->key.source_type &&
> key->target_type == cur->key.target_type &&
> @@ -191,7 +196,7 @@
> if (!h)
> return NULL;
>
> - hvalue = AVTAB_HASH(key);
> + hvalue = avtab_hash(key, h->mask);
> for (cur = h->htable[hvalue]; cur; cur = cur->next) {
> if (key->source_type == cur->key.source_type &&
> key->target_type == cur->key.target_type &&
> @@ -242,13 +247,13 @@
>
> void avtab_destroy(avtab_t * h)
> {
> - int i;
> + unsigned int i;
> avtab_ptr_t cur, temp;
>
> if (!h || !h->htable)
> return;
>
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < h->nslot; i++) {
> cur = h->htable[i];
> while (cur != NULL) {
> temp = cur;
> @@ -259,19 +264,22 @@
> }
> free(h->htable);
> h->htable = NULL;
> + h->nslot = 0;
> + h->mask = 0;
> }
>
> int avtab_map(avtab_t * h,
> int (*apply) (avtab_key_t * k,
> avtab_datum_t * d, void *args), void *args)
> {
> - int i, ret;
> + unsigned int i;
> + int ret;
> avtab_ptr_t cur;
>
> if (!h)
> return 0;
>
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < h->nslot; i++) {
> cur = h->htable[i];
> while (cur != NULL) {
> ret = apply(&cur->key, &cur->datum, args);
> @@ -285,25 +293,50 @@
>
> int avtab_init(avtab_t * h)
> {
> - int i;
> + h->htable = NULL;
> + h->nel = 0;
> + return 0;
> +}
>
> - h->htable = malloc(sizeof(avtab_ptr_t) * AVTAB_SIZE);
> +int avtab_alloc(avtab_t *h, uint32_t nrules)
> +{
> + uint16_t mask = 0;
> + uint32_t shift = 0;
> + uint32_t work = nrules;
> + uint32_t nslot = 0;
> +
> + if (nrules == 0)
> + goto out;
> +
> + while (work) {
> + work = work >> 1;
> + shift++;
> + }
> + if (shift > 2)
> + shift = shift - 2;
> + nslot = 1 << shift;
> + if (nslot > MAX_AVTAB_SIZE)
> + nslot = MAX_AVTAB_SIZE;
> + mask = nslot - 1;
> +
> + h->htable = calloc(nslot, sizeof(avtab_ptr_t));
> if (!h->htable)
> return -1;
> - for (i = 0; i < AVTAB_SIZE; i++)
> - h->htable[i] = (avtab_ptr_t) NULL;
> +out:
> h->nel = 0;
> + h->nslot = nslot;
> + h->mask = mask;
> return 0;
> }
>
> void avtab_hash_eval(avtab_t * h, char *tag)
> {
> - int i, chain_len, slots_used, max_chain_len;
> + unsigned int i, chain_len, slots_used, max_chain_len;
> avtab_ptr_t cur;
>
> slots_used = 0;
> max_chain_len = 0;
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < h->nslot; i++) {
> cur = h->htable[i];
> if (cur) {
> slots_used++;
> @@ -320,7 +353,7 @@
>
> printf
> ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
> - tag, h->nel, slots_used, AVTAB_SIZE, max_chain_len);
> + tag, h->nel, slots_used, h->nslot, max_chain_len);
> }
>
> /* Ordering of datums in the original avtab format in the policy file. */
> @@ -471,6 +504,13 @@
> ERR(fp->handle, "table is empty");
> goto bad;
> }
> +
> + rc = avtab_alloc(a, nel);
> + if (rc) {
> + ERR(fp->handle, "out of memory");
> + goto bad;
> + }
> +
> for (i = 0; i < nel; i++) {
> rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL);
> if (rc) {
> Index: checkpolicy/test/dispol.c
> ===================================================================
> --- checkpolicy/test/dispol.c (revision 2773)
> +++ checkpolicy/test/dispol.c (working copy)
> @@ -169,7 +169,7 @@
> }
>
> /* hmm...should have used avtab_map. */
> - for (i = 0; i < AVTAB_SIZE; i++) {
> + for (i = 0; i < expa.nslot; i++) {
> for (cur = expa.htable[i]; cur; cur = cur->next) {
> render_av_rule(&cur->key, &cur->datum, what, p, fp);
> }
>
>
> --
> Stephen Smalley
> National Security Agency
>
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
--
Yuichi Nakamura
Hitachi Software Engineering Co., Ltd.
Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/
SELinux Policy Editor: http://seedit.sourceforge.net/
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 52+ messages in thread
end of thread, other threads:[~2008-02-01 4:59 UTC | newest]
Thread overview: 52+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-21 4:29 [patch] Tuning avtab to reduce memory usage Yuichi Nakamura
2007-08-21 13:47 ` Stephen Smalley
2007-08-21 14:19 ` Yuichi Nakamura
2007-08-21 15:11 ` Paul Moore
2007-08-21 16:37 ` Stephen Smalley
2007-08-21 16:55 ` Paul Moore
2007-08-22 9:25 ` KaiGai Kohei
2007-09-12 3:08 ` KaiGai Kohei
2007-09-12 19:54 ` Paul Moore
2007-09-13 1:37 ` [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage) KaiGai Kohei
2007-09-13 11:34 ` Stephen Smalley
2007-09-14 1:02 ` Wrappers to load bitmaps (Re: [PATCH] Improve ebitmap scanning) KaiGai Kohei
2007-09-14 1:02 ` KaiGai Kohei
2007-09-13 20:47 ` [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage) Paul Moore
2007-09-18 17:21 ` [patch] Tuning avtab to reduce memory usage Stephen Smalley
2007-09-18 22:11 ` Paul Moore
2007-09-20 8:14 ` KaiGai Kohei
2007-09-21 19:21 ` Stephen Smalley
2007-09-25 5:06 ` KaiGai Kohei
2007-09-25 12:04 ` Paul Moore
2007-09-25 13:53 ` Stephen Smalley
2007-09-26 5:49 ` [PATCH] Improve SELinux performance when AVC misses KaiGai Kohei
2007-09-27 2:22 ` KaiGai Kohei
2007-09-27 2:43 ` KaiGai Kohei
2007-09-27 20:47 ` James Morris
2007-09-28 10:56 ` KaiGai Kohei
2007-09-28 14:47 ` Stephen Smalley
2007-09-28 17:20 ` KaiGai Kohei
2007-09-28 18:40 ` Stephen Smalley
2007-09-28 21:09 ` James Morris
2007-10-02 15:12 ` KaiGai Kohei
2007-10-02 15:28 ` Stephen Smalley
2007-10-03 13:41 ` KaiGai Kohei
2007-10-03 14:42 ` KaiGai Kohei
2007-10-04 0:37 ` James Morris
2007-08-21 14:00 ` [patch] Tuning avtab to reduce memory usage James Morris
2007-08-22 2:55 ` Yuichi Nakamura
2007-08-22 3:42 ` KaiGai Kohei
2007-08-22 13:44 ` James Morris
2007-08-23 0:57 ` Yuichi Nakamura
2007-08-23 13:15 ` Stephen Smalley
2007-08-24 2:55 ` Yuichi Nakamura
2007-08-27 13:39 ` Stephen Smalley
2007-08-27 16:55 ` James Morris
2008-01-31 21:00 ` Stephen Smalley
2008-01-31 21:44 ` Stephen Smalley
2008-02-01 4:59 ` Yuichi Nakamura
2007-08-23 14:46 ` James Morris
2007-08-24 2:33 ` Yuichi Nakamura
2007-08-22 16:05 ` James Morris
2007-08-21 19:43 ` J. Tang
2007-08-22 3:11 ` Yuichi Nakamura
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.