Skip to content

Commit 24def7b

Browse files
WOnder93pcmoore
authored andcommitted
selinux: prepare for inlining of hashtab functions
Refactor searching and inserting into hashtabs to pave the way for converting hashtab_search() and hashtab_insert() to inline functions in the next patch. This will avoid indirect calls and allow the compiler to better optimize individual callers, leading to a significant performance improvement. In order to avoid the indirect calls, the key hashing and comparison callbacks need to be extracted from the hashtab struct and passed directly to hashtab_search()/_insert() by the callers so that the callback address is always known at compile time. The kernel's rhashtable library (<linux/rhashtable*.h>) does the same thing. This of course makes the hashtab functions slightly easier to misuse by passing a wrong callback set, but unfortunately there is no better way to implement a hash table that is both generic and efficient in C. This patch tries to somewhat mitigate this by only calling the hashtab functions in the same file where the corresponding callbacks are defined (wrapping them into more specialized functions as needed). Note that this patch doesn't bring any benefit without also moving the definitions of hashtab_search() and -_insert() to the header file, which is done in a follow-up patch for easier review of the hashtab.c changes in this patch. Signed-off-by: Ondrej Mosnacek <[email protected]> Acked-by: Stephen Smalley <[email protected]> Signed-off-by: Paul Moore <[email protected]>
1 parent 237389e commit 24def7b

File tree

7 files changed

+110
-63
lines changed

7 files changed

+110
-63
lines changed

security/selinux/ss/hashtab.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,19 @@ static u32 hashtab_compute_size(u32 nel)
2929
return nel == 0 ? 0 : roundup_pow_of_two(nel);
3030
}
3131

32-
int hashtab_init(struct hashtab *h,
33-
u32 (*hash_value)(struct hashtab *h, const void *key),
34-
int (*keycmp)(struct hashtab *h, const void *key1,
35-
const void *key2),
36-
u32 nel_hint)
32+
int hashtab_init(struct hashtab *h, u32 nel_hint)
3733
{
3834
h->size = hashtab_compute_size(nel_hint);
3935
h->nel = 0;
40-
h->hash_value = hash_value;
41-
h->keycmp = keycmp;
4236
if (!h->size)
4337
return 0;
4438

4539
h->htable = kcalloc(h->size, sizeof(*h->htable), GFP_KERNEL);
4640
return h->htable ? 0 : -ENOMEM;
4741
}
4842

49-
int hashtab_insert(struct hashtab *h, void *key, void *datum)
43+
int hashtab_insert(struct hashtab *h, void *key, void *datum,
44+
struct hashtab_key_params key_params)
5045
{
5146
u32 hvalue;
5247
struct hashtab_node *prev, *cur, *newnode;
@@ -56,17 +51,20 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
5651
if (!h->size || h->nel == HASHTAB_MAX_NODES)
5752
return -EINVAL;
5853

59-
hvalue = h->hash_value(h, key);
54+
hvalue = key_params.hash(key) & (h->size - 1);
6055
prev = NULL;
6156
cur = h->htable[hvalue];
62-
while (cur && h->keycmp(h, key, cur->key) > 0) {
57+
while (cur) {
58+
int cmp = key_params.cmp(key, cur->key);
59+
60+
if (cmp == 0)
61+
return -EEXIST;
62+
if (cmp < 0)
63+
break;
6364
prev = cur;
6465
cur = cur->next;
6566
}
6667

67-
if (cur && (h->keycmp(h, key, cur->key) == 0))
68-
return -EEXIST;
69-
7068
newnode = kmem_cache_zalloc(hashtab_node_cachep, GFP_KERNEL);
7169
if (!newnode)
7270
return -ENOMEM;
@@ -84,23 +82,27 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
8482
return 0;
8583
}
8684

87-
void *hashtab_search(struct hashtab *h, const void *key)
85+
void *hashtab_search(struct hashtab *h, const void *key,
86+
struct hashtab_key_params key_params)
8887
{
8988
u32 hvalue;
9089
struct hashtab_node *cur;
9190

9291
if (!h->size)
9392
return NULL;
9493

95-
hvalue = h->hash_value(h, key);
94+
hvalue = key_params.hash(key) & (h->size - 1);
9695
cur = h->htable[hvalue];
97-
while (cur && h->keycmp(h, key, cur->key) > 0)
98-
cur = cur->next;
96+
while (cur) {
97+
int cmp = key_params.cmp(key, cur->key);
9998

100-
if (!cur || (h->keycmp(h, key, cur->key) != 0))
101-
return NULL;
102-
103-
return cur->datum;
99+
if (cmp == 0)
100+
return cur->datum;
101+
if (cmp < 0)
102+
break;
103+
cur = cur->next;
104+
}
105+
return NULL;
104106
}
105107

106108
void hashtab_destroy(struct hashtab *h)

security/selinux/ss/hashtab.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313

1414
#define HASHTAB_MAX_NODES 0xffffffff
1515

16+
struct hashtab_key_params {
17+
u32 (*hash)(const void *key); /* hash function */
18+
int (*cmp)(const void *key1, const void *key2);
19+
/* key comparison function */
20+
};
21+
1622
struct hashtab_node {
1723
void *key;
1824
void *datum;
@@ -23,10 +29,6 @@ struct hashtab {
2329
struct hashtab_node **htable; /* hash table */
2430
u32 size; /* number of slots in hash table */
2531
u32 nel; /* number of elements in hash table */
26-
u32 (*hash_value)(struct hashtab *h, const void *key);
27-
/* hash function */
28-
int (*keycmp)(struct hashtab *h, const void *key1, const void *key2);
29-
/* key comparison function */
3032
};
3133

3234
struct hashtab_info {
@@ -39,11 +41,7 @@ struct hashtab_info {
3941
*
4042
* Returns -ENOMEM if insufficient space is available or 0 otherwise.
4143
*/
42-
int hashtab_init(struct hashtab *h,
43-
u32 (*hash_value)(struct hashtab *h, const void *key),
44-
int (*keycmp)(struct hashtab *h, const void *key1,
45-
const void *key2),
46-
u32 nel_hint);
44+
int hashtab_init(struct hashtab *h, u32 nel_hint);
4745

4846
/*
4947
* Inserts the specified (key, datum) pair into the specified hash table.
@@ -53,15 +51,17 @@ int hashtab_init(struct hashtab *h,
5351
* -EINVAL for general errors or
5452
0 otherwise.
5553
*/
56-
int hashtab_insert(struct hashtab *h, void *k, void *d);
54+
int hashtab_insert(struct hashtab *h, void *k, void *d,
55+
struct hashtab_key_params key_params);
5756

5857
/*
5958
* Searches for the entry with the specified key in the hash table.
6059
*
6160
* Returns NULL if no entry has the specified key or
6261
* the datum of the entry otherwise.
6362
*/
64-
void *hashtab_search(struct hashtab *h, const void *k);
63+
void *hashtab_search(struct hashtab *h, const void *k,
64+
struct hashtab_key_params key_params);
6565

6666
/*
6767
* Destroys the specified hash table.

security/selinux/ss/mls.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ int mls_compute_sid(struct policydb *p,
507507
rtr.source_type = scontext->type;
508508
rtr.target_type = tcontext->type;
509509
rtr.target_class = tclass;
510-
r = hashtab_search(&p->range_tr, &rtr);
510+
r = policydb_rangetr_search(p, &rtr);
511511
if (r)
512512
return mls_range_set(newcontext, r);
513513

security/selinux/ss/policydb.c

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ static int roles_init(struct policydb *p)
411411
return rc;
412412
}
413413

414-
static u32 filenametr_hash(struct hashtab *h, const void *k)
414+
static u32 filenametr_hash(const void *k)
415415
{
416416
const struct filename_trans_key *ft = k;
417417
unsigned long hash;
@@ -423,10 +423,10 @@ static u32 filenametr_hash(struct hashtab *h, const void *k)
423423
byte_num = 0;
424424
while ((focus = ft->name[byte_num++]))
425425
hash = partial_name_hash(focus, hash);
426-
return hash & (h->size - 1);
426+
return hash;
427427
}
428428

429-
static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
429+
static int filenametr_cmp(const void *k1, const void *k2)
430430
{
431431
const struct filename_trans_key *ft1 = k1;
432432
const struct filename_trans_key *ft2 = k2;
@@ -444,15 +444,26 @@ static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
444444

445445
}
446446

447-
static u32 rangetr_hash(struct hashtab *h, const void *k)
447+
static const struct hashtab_key_params filenametr_key_params = {
448+
.hash = filenametr_hash,
449+
.cmp = filenametr_cmp,
450+
};
451+
452+
struct filename_trans_datum *policydb_filenametr_search(
453+
struct policydb *p, struct filename_trans_key *key)
454+
{
455+
return hashtab_search(&p->filename_trans, key, filenametr_key_params);
456+
}
457+
458+
static u32 rangetr_hash(const void *k)
448459
{
449460
const struct range_trans *key = k;
450461

451-
return (key->source_type + (key->target_type << 3) +
452-
(key->target_class << 5)) & (h->size - 1);
462+
return key->source_type + (key->target_type << 3) +
463+
(key->target_class << 5);
453464
}
454465

455-
static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
466+
static int rangetr_cmp(const void *k1, const void *k2)
456467
{
457468
const struct range_trans *key1 = k1, *key2 = k2;
458469
int v;
@@ -470,15 +481,25 @@ static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
470481
return v;
471482
}
472483

473-
static u32 role_trans_hash(struct hashtab *h, const void *k)
484+
static const struct hashtab_key_params rangetr_key_params = {
485+
.hash = rangetr_hash,
486+
.cmp = rangetr_cmp,
487+
};
488+
489+
struct mls_range *policydb_rangetr_search(struct policydb *p,
490+
struct range_trans *key)
491+
{
492+
return hashtab_search(&p->range_tr, key, rangetr_key_params);
493+
}
494+
495+
static u32 role_trans_hash(const void *k)
474496
{
475497
const struct role_trans_key *key = k;
476498

477-
return (key->role + (key->type << 3) + (key->tclass << 5)) &
478-
(h->size - 1);
499+
return key->role + (key->type << 3) + (key->tclass << 5);
479500
}
480501

481-
static int role_trans_cmp(struct hashtab *h, const void *k1, const void *k2)
502+
static int role_trans_cmp(const void *k1, const void *k2)
482503
{
483504
const struct role_trans_key *key1 = k1, *key2 = k2;
484505
int v;
@@ -494,6 +515,17 @@ static int role_trans_cmp(struct hashtab *h, const void *k1, const void *k2)
494515
return key1->tclass - key2->tclass;
495516
}
496517

518+
static const struct hashtab_key_params roletr_key_params = {
519+
.hash = role_trans_hash,
520+
.cmp = role_trans_cmp,
521+
};
522+
523+
struct role_trans_datum *policydb_roletr_search(struct policydb *p,
524+
struct role_trans_key *key)
525+
{
526+
return hashtab_search(&p->role_tr, key, roletr_key_params);
527+
}
528+
497529
/*
498530
* Initialize a policy database structure.
499531
*/
@@ -1796,7 +1828,7 @@ static int range_read(struct policydb *p, void *fp)
17961828

17971829
nel = le32_to_cpu(buf[0]);
17981830

1799-
rc = hashtab_init(&p->range_tr, rangetr_hash, rangetr_cmp, nel);
1831+
rc = hashtab_init(&p->range_tr, nel);
18001832
if (rc)
18011833
return rc;
18021834

@@ -1841,7 +1873,7 @@ static int range_read(struct policydb *p, void *fp)
18411873
goto out;
18421874
}
18431875

1844-
rc = hashtab_insert(&p->range_tr, rt, r);
1876+
rc = hashtab_insert(&p->range_tr, rt, r, rangetr_key_params);
18451877
if (rc)
18461878
goto out;
18471879

@@ -1888,7 +1920,7 @@ static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
18881920
otype = le32_to_cpu(buf[3]);
18891921

18901922
last = NULL;
1891-
datum = hashtab_search(&p->filename_trans, &key);
1923+
datum = policydb_filenametr_search(p, &key);
18921924
while (datum) {
18931925
if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
18941926
/* conflicting/duplicate rules are ignored */
@@ -1918,7 +1950,8 @@ static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
19181950
if (!ft)
19191951
goto out;
19201952

1921-
rc = hashtab_insert(&p->filename_trans, ft, datum);
1953+
rc = hashtab_insert(&p->filename_trans, ft, datum,
1954+
filenametr_key_params);
19221955
if (rc)
19231956
goto out;
19241957
name = NULL;
@@ -2006,7 +2039,8 @@ static int filename_trans_read_helper(struct policydb *p, void *fp)
20062039
ft->tclass = tclass;
20072040
ft->name = name;
20082041

2009-
rc = hashtab_insert(&p->filename_trans, ft, first);
2042+
rc = hashtab_insert(&p->filename_trans, ft, first,
2043+
filenametr_key_params);
20102044
if (rc == -EEXIST)
20112045
pr_err("SELinux: Duplicate filename transition key\n");
20122046
if (rc)
@@ -2044,8 +2078,7 @@ static int filename_trans_read(struct policydb *p, void *fp)
20442078
if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
20452079
p->compat_filename_trans_count = nel;
20462080

2047-
rc = hashtab_init(&p->filename_trans, filenametr_hash,
2048-
filenametr_cmp, (1 << 11));
2081+
rc = hashtab_init(&p->filename_trans, (1 << 11));
20492082
if (rc)
20502083
return rc;
20512084

@@ -2055,8 +2088,7 @@ static int filename_trans_read(struct policydb *p, void *fp)
20552088
return rc;
20562089
}
20572090
} else {
2058-
rc = hashtab_init(&p->filename_trans, filenametr_hash,
2059-
filenametr_cmp, nel);
2091+
rc = hashtab_init(&p->filename_trans, nel);
20602092
if (rc)
20612093
return rc;
20622094

@@ -2539,7 +2571,7 @@ int policydb_read(struct policydb *p, void *fp)
25392571
goto bad;
25402572
nel = le32_to_cpu(buf[0]);
25412573

2542-
rc = hashtab_init(&p->role_tr, role_trans_hash, role_trans_cmp, nel);
2574+
rc = hashtab_init(&p->role_tr, nel);
25432575
if (rc)
25442576
goto bad;
25452577
for (i = 0; i < nel; i++) {
@@ -2576,7 +2608,7 @@ int policydb_read(struct policydb *p, void *fp)
25762608
!policydb_role_isvalid(p, rtd->new_role))
25772609
goto bad;
25782610

2579-
rc = hashtab_insert(&p->role_tr, rtk, rtd);
2611+
rc = hashtab_insert(&p->role_tr, rtk, rtd, roletr_key_params);
25802612
if (rc)
25812613
goto bad;
25822614

security/selinux/ss/policydb.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,15 @@ extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
324324
extern int policydb_read(struct policydb *p, void *fp);
325325
extern int policydb_write(struct policydb *p, void *fp);
326326

327+
extern struct filename_trans_datum *policydb_filenametr_search(
328+
struct policydb *p, struct filename_trans_key *key);
329+
330+
extern struct mls_range *policydb_rangetr_search(
331+
struct policydb *p, struct range_trans *key);
332+
333+
extern struct role_trans_datum *policydb_roletr_search(
334+
struct policydb *p, struct role_trans_key *key);
335+
327336
#define POLICYDB_CONFIG_MLS 1
328337

329338
/* the config flags related to unknown classes/perms are bits 2 and 3 */

security/selinux/ss/services.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,7 +1671,7 @@ static void filename_compute_type(struct policydb *policydb,
16711671
ft.tclass = tclass;
16721672
ft.name = objname;
16731673

1674-
datum = hashtab_search(&policydb->filename_trans, &ft);
1674+
datum = policydb_filenametr_search(policydb, &ft);
16751675
while (datum) {
16761676
if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
16771677
newcontext->type = datum->otype;
@@ -1834,7 +1834,7 @@ static int security_compute_sid(struct selinux_state *state,
18341834
.tclass = tclass,
18351835
};
18361836

1837-
rtd = hashtab_search(&policydb->role_tr, &rtk);
1837+
rtd = policydb_roletr_search(policydb, &rtk);
18381838
if (rtd)
18391839
newcontext.role = rtd->new_role;
18401840
}

0 commit comments

Comments
 (0)