diff options
author | KaiGai Kohei <kaigai@ak.jp.nec.com> | 2007-09-28 13:20:55 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2007-10-16 18:59:34 -0400 |
commit | 9fe79ad1e43d236bbbb8edb3cf634356de714c79 (patch) | |
tree | 91149cefa28baf692eb55f88f8c544a33e9126df /security/selinux/ss/ebitmap.h | |
parent | 3f12070e27b4a213d62607d2bff139793089a77d (diff) |
SELinux: improve 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>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/ss/ebitmap.h')
-rw-r--r-- | security/selinux/ss/ebitmap.h | 87 |
1 files changed, 66 insertions, 21 deletions
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 1270e34b61c1..e38a327dd703 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
@@ -16,14 +16,16 @@ | |||
16 | 16 | ||
17 | #include <net/netlabel.h> | 17 | #include <net/netlabel.h> |
18 | 18 | ||
19 | #define MAPTYPE u64 /* portion of bitmap in each node */ | 19 | #define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \ |
20 | #define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */ | 20 | / sizeof(unsigned long)) |
21 | #define MAPBIT 1ULL /* a bit in the node bitmap */ | 21 | #define EBITMAP_UNIT_SIZE BITS_PER_LONG |
22 | #define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) | ||
23 | #define EBITMAP_BIT 1ULL | ||
22 | 24 | ||
23 | struct ebitmap_node { | 25 | struct ebitmap_node { |
24 | u32 startbit; /* starting position in the total bitmap */ | ||
25 | MAPTYPE map; /* this node's portion of the bitmap */ | ||
26 | struct ebitmap_node *next; | 26 | struct ebitmap_node *next; |
27 | unsigned long maps[EBITMAP_UNIT_NUMS]; | ||
28 | u32 startbit; | ||
27 | }; | 29 | }; |
28 | 30 | ||
29 | struct ebitmap { | 31 | struct ebitmap { |
@@ -34,11 +36,17 @@ struct ebitmap { | |||
34 | #define ebitmap_length(e) ((e)->highbit) | 36 | #define ebitmap_length(e) ((e)->highbit) |
35 | #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0) | 37 | #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0) |
36 | 38 | ||
37 | static inline unsigned int ebitmap_start(struct ebitmap *e, | 39 | static inline unsigned int ebitmap_start_positive(struct ebitmap *e, |
38 | struct ebitmap_node **n) | 40 | struct ebitmap_node **n) |
39 | { | 41 | { |
40 | *n = e->node; | 42 | unsigned int ofs; |
41 | return ebitmap_startbit(e); | 43 | |
44 | for (*n = e->node; *n; *n = (*n)->next) { | ||
45 | ofs = find_first_bit((*n)->maps, EBITMAP_SIZE); | ||
46 | if (ofs < EBITMAP_SIZE) | ||
47 | return (*n)->startbit + ofs; | ||
48 | } | ||
49 | return ebitmap_length(e); | ||
42 | } | 50 | } |
43 | 51 | ||
44 | static inline void ebitmap_init(struct ebitmap *e) | 52 | static inline void ebitmap_init(struct ebitmap *e) |
@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e) | |||
46 | memset(e, 0, sizeof(*e)); | 54 | memset(e, 0, sizeof(*e)); |
47 | } | 55 | } |
48 | 56 | ||
49 | static inline unsigned int ebitmap_next(struct ebitmap_node **n, | 57 | static inline unsigned int ebitmap_next_positive(struct ebitmap *e, |
50 | unsigned int bit) | 58 | struct ebitmap_node **n, |
59 | unsigned int bit) | ||
51 | { | 60 | { |
52 | if ((bit == ((*n)->startbit + MAPSIZE - 1)) && | 61 | unsigned int ofs; |
53 | (*n)->next) { | 62 | |
54 | *n = (*n)->next; | 63 | ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1); |
55 | return (*n)->startbit; | 64 | if (ofs < EBITMAP_SIZE) |
56 | } | 65 | return ofs + (*n)->startbit; |
57 | 66 | ||
58 | return (bit+1); | 67 | for (*n = (*n)->next; *n; *n = (*n)->next) { |
68 | ofs = find_first_bit((*n)->maps, EBITMAP_SIZE); | ||
69 | if (ofs < EBITMAP_SIZE) | ||
70 | return ofs + (*n)->startbit; | ||
71 | } | ||
72 | return ebitmap_length(e); | ||
59 | } | 73 | } |
60 | 74 | ||
61 | static inline int ebitmap_node_get_bit(struct ebitmap_node * n, | 75 | #define EBITMAP_NODE_INDEX(node, bit) \ |
76 | (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE) | ||
77 | #define EBITMAP_NODE_OFFSET(node, bit) \ | ||
78 | (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE) | ||
79 | |||
80 | static inline int ebitmap_node_get_bit(struct ebitmap_node *n, | ||
62 | unsigned int bit) | 81 | unsigned int bit) |
63 | { | 82 | { |
64 | if (n->map & (MAPBIT << (bit - n->startbit))) | 83 | unsigned int index = EBITMAP_NODE_INDEX(n, bit); |
84 | unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit); | ||
85 | |||
86 | BUG_ON(index >= EBITMAP_UNIT_NUMS); | ||
87 | if ((n->maps[index] & (EBITMAP_BIT << ofs))) | ||
65 | return 1; | 88 | return 1; |
66 | return 0; | 89 | return 0; |
67 | } | 90 | } |
68 | 91 | ||
69 | #define ebitmap_for_each_bit(e, n, bit) \ | 92 | static inline void ebitmap_node_set_bit(struct ebitmap_node *n, |
70 | for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \ | 93 | unsigned int bit) |
94 | { | ||
95 | unsigned int index = EBITMAP_NODE_INDEX(n, bit); | ||
96 | unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit); | ||
97 | |||
98 | BUG_ON(index >= EBITMAP_UNIT_NUMS); | ||
99 | n->maps[index] |= (EBITMAP_BIT << ofs); | ||
100 | } | ||
101 | |||
102 | static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, | ||
103 | unsigned int bit) | ||
104 | { | ||
105 | unsigned int index = EBITMAP_NODE_INDEX(n, bit); | ||
106 | unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit); | ||
107 | |||
108 | BUG_ON(index >= EBITMAP_UNIT_NUMS); | ||
109 | n->maps[index] &= ~(EBITMAP_BIT << ofs); | ||
110 | } | ||
111 | |||
112 | #define ebitmap_for_each_positive_bit(e, n, bit) \ | ||
113 | for (bit = ebitmap_start_positive(e, &n); \ | ||
114 | bit < ebitmap_length(e); \ | ||
115 | bit = ebitmap_next_positive(e, &n, bit)) \ | ||
71 | 116 | ||
72 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); | 117 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); |
73 | int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); | 118 | int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); |