Lines Matching +full:cache +full:- +full:level
1 // SPDX-License-Identifier: GPL-2.0
31 #define sid_to_index(sid) (sid - (SECINITSID_NUM + 1))
37 memset(s->roots, 0, sizeof(s->roots)); in sidtab_init()
40 s->isids[i].set = 0; in sidtab_init()
42 s->count = 0; in sidtab_init()
43 s->convert = NULL; in sidtab_init()
44 hash_init(s->context_to_sid); in sidtab_init()
46 spin_lock_init(&s->lock); in sidtab_init()
49 s->cache_free_slots = CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE; in sidtab_init()
50 INIT_LIST_HEAD(&s->cache_lru_list); in sidtab_init()
51 spin_lock_init(&s->cache_lock); in sidtab_init()
63 hash_for_each_possible_rcu(s->context_to_sid, entry, list, hash) { in context_to_sid()
64 if (entry->hash != hash) in context_to_sid()
66 if (context_cmp(&entry->context, context)) { in context_to_sid()
67 sid = entry->sid; in context_to_sid()
82 return -EINVAL; in sidtab_set_initial()
84 isid = &s->isids[sid - 1]; in sidtab_set_initial()
86 rc = context_cpy(&isid->entry.context, context); in sidtab_set_initial()
91 isid->entry.cache = NULL; in sidtab_set_initial()
93 isid->set = 1; in sidtab_set_initial()
104 isid->entry.sid = sid; in sidtab_set_initial()
105 isid->entry.hash = hash; in sidtab_set_initial()
106 hash_add(s->context_to_sid, &isid->entry.list, hash); in sidtab_set_initial()
123 hash_for_each_rcu(sidtab->context_to_sid, i, entry, list) { in sidtab_hash_stats()
149 u32 level = 0; in sidtab_level_from_count() local
153 ++level; in sidtab_level_from_count()
155 return level; in sidtab_level_from_count()
158 static int sidtab_alloc_roots(struct sidtab *s, u32 level) in sidtab_alloc_roots() argument
162 if (!s->roots[0].ptr_leaf) { in sidtab_alloc_roots()
163 s->roots[0].ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, in sidtab_alloc_roots()
165 if (!s->roots[0].ptr_leaf) in sidtab_alloc_roots()
166 return -ENOMEM; in sidtab_alloc_roots()
168 for (l = 1; l <= level; ++l) in sidtab_alloc_roots()
169 if (!s->roots[l].ptr_inner) { in sidtab_alloc_roots()
170 s->roots[l].ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, in sidtab_alloc_roots()
172 if (!s->roots[l].ptr_inner) in sidtab_alloc_roots()
173 return -ENOMEM; in sidtab_alloc_roots()
174 s->roots[l].ptr_inner->entries[0] = s->roots[l - 1]; in sidtab_alloc_roots()
183 u32 level, capacity_shift, leaf_index = index / SIDTAB_LEAF_ENTRIES; in sidtab_do_lookup() local
185 /* find the level of the subtree we need */ in sidtab_do_lookup()
186 level = sidtab_level_from_count(index + 1); in sidtab_do_lookup()
187 capacity_shift = level * SIDTAB_INNER_SHIFT; in sidtab_do_lookup()
190 if (alloc && sidtab_alloc_roots(s, level) != 0) in sidtab_do_lookup()
194 entry = &s->roots[level]; in sidtab_do_lookup()
195 while (level != 0) { in sidtab_do_lookup()
196 capacity_shift -= SIDTAB_INNER_SHIFT; in sidtab_do_lookup()
197 --level; in sidtab_do_lookup()
199 entry = &entry->ptr_inner->entries[leaf_index >> capacity_shift]; in sidtab_do_lookup()
200 leaf_index &= ((u32)1 << capacity_shift) - 1; in sidtab_do_lookup()
202 if (!entry->ptr_inner) { in sidtab_do_lookup()
204 entry->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, in sidtab_do_lookup()
206 if (!entry->ptr_inner) in sidtab_do_lookup()
210 if (!entry->ptr_leaf) { in sidtab_do_lookup()
212 entry->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, in sidtab_do_lookup()
214 if (!entry->ptr_leaf) in sidtab_do_lookup()
217 return &entry->ptr_leaf->entries[index % SIDTAB_LEAF_ENTRIES]; in sidtab_do_lookup()
223 u32 count = smp_load_acquire(&s->count); in sidtab_lookup()
233 return s->isids[sid - 1].set ? &s->isids[sid - 1].entry : NULL; in sidtab_lookup_initial()
246 if (entry && (!entry->context.len || force)) in sidtab_search_core()
276 /* lock-free search failed: lock, re-search, and insert if not found */ in sidtab_context_to_sid()
277 spin_lock_irqsave(&s->lock, flags); in sidtab_context_to_sid()
284 count = s->count; in sidtab_context_to_sid()
285 convert = s->convert; in sidtab_context_to_sid()
288 rc = -EOVERFLOW; in sidtab_context_to_sid()
293 rc = -ENOMEM; in sidtab_context_to_sid()
298 dst->sid = index_to_sid(count); in sidtab_context_to_sid()
299 dst->hash = hash; in sidtab_context_to_sid()
301 rc = context_cpy(&dst->context, context); in sidtab_context_to_sid()
310 rc = -ENOMEM; in sidtab_context_to_sid()
311 dst_convert = sidtab_do_lookup(convert->target, count, 1); in sidtab_context_to_sid()
313 context_destroy(&dst->context); in sidtab_context_to_sid()
317 rc = convert->func(context, &dst_convert->context, in sidtab_context_to_sid()
318 convert->args); in sidtab_context_to_sid()
320 context_destroy(&dst->context); in sidtab_context_to_sid()
323 dst_convert->sid = index_to_sid(count); in sidtab_context_to_sid()
324 dst_convert->hash = context_compute_hash(&dst_convert->context); in sidtab_context_to_sid()
325 convert->target->count = count + 1; in sidtab_context_to_sid()
327 hash_add_rcu(convert->target->context_to_sid, in sidtab_context_to_sid()
328 &dst_convert->list, dst_convert->hash); in sidtab_context_to_sid()
331 if (context->len) in sidtab_context_to_sid()
333 context->str); in sidtab_context_to_sid()
338 smp_store_release(&s->count, count + 1); in sidtab_context_to_sid()
339 hash_add_rcu(s->context_to_sid, &dst->list, dst->hash); in sidtab_context_to_sid()
343 spin_unlock_irqrestore(&s->lock, flags); in sidtab_context_to_sid()
354 entry->sid = index_to_sid(i); in sidtab_convert_hashtable()
355 entry->hash = context_compute_hash(&entry->context); in sidtab_convert_hashtable()
357 hash_add_rcu(s->context_to_sid, &entry->list, entry->hash); in sidtab_convert_hashtable()
363 u32 *pos, u32 count, u32 level, in sidtab_convert_tree() argument
369 if (level != 0) { in sidtab_convert_tree()
370 if (!edst->ptr_inner) { in sidtab_convert_tree()
371 edst->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, in sidtab_convert_tree()
373 if (!edst->ptr_inner) in sidtab_convert_tree()
374 return -ENOMEM; in sidtab_convert_tree()
378 rc = sidtab_convert_tree(&edst->ptr_inner->entries[i], in sidtab_convert_tree()
379 &esrc->ptr_inner->entries[i], in sidtab_convert_tree()
380 pos, count, level - 1, in sidtab_convert_tree()
387 if (!edst->ptr_leaf) { in sidtab_convert_tree()
388 edst->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, in sidtab_convert_tree()
390 if (!edst->ptr_leaf) in sidtab_convert_tree()
391 return -ENOMEM; in sidtab_convert_tree()
395 rc = convert->func(&esrc->ptr_leaf->entries[i].context, in sidtab_convert_tree()
396 &edst->ptr_leaf->entries[i].context, in sidtab_convert_tree()
397 convert->args); in sidtab_convert_tree()
411 u32 count, level, pos; in sidtab_convert() local
414 spin_lock_irqsave(&s->lock, flags); in sidtab_convert()
417 if (s->convert) { in sidtab_convert()
418 spin_unlock_irqrestore(&s->lock, flags); in sidtab_convert()
419 return -EBUSY; in sidtab_convert()
422 count = s->count; in sidtab_convert()
423 level = sidtab_level_from_count(count); in sidtab_convert()
428 rc = sidtab_do_lookup(params->target, count - 1, 1) ? 0 : -ENOMEM; in sidtab_convert()
430 spin_unlock_irqrestore(&s->lock, flags); in sidtab_convert()
435 params->target->count = count; in sidtab_convert()
438 s->convert = params; in sidtab_convert()
441 spin_unlock_irqrestore(&s->lock, flags); in sidtab_convert()
447 rc = sidtab_convert_tree(¶ms->target->roots[level], in sidtab_convert()
448 &s->roots[level], &pos, count, level, params); in sidtab_convert()
450 /* we need to keep the old table - disable live convert */ in sidtab_convert()
451 spin_lock_irqsave(&s->lock, flags); in sidtab_convert()
452 s->convert = NULL; in sidtab_convert()
453 spin_unlock_irqrestore(&s->lock, flags); in sidtab_convert()
458 * so we must re-acquire the lock here. in sidtab_convert()
460 spin_lock_irqsave(&s->lock, flags); in sidtab_convert()
461 sidtab_convert_hashtable(params->target, count); in sidtab_convert()
462 spin_unlock_irqrestore(&s->lock, flags); in sidtab_convert()
471 /* cancelling policy load - disable live convert of sidtab */ in sidtab_cancel_convert()
472 spin_lock_irqsave(&s->lock, flags); in sidtab_cancel_convert()
473 s->convert = NULL; in sidtab_cancel_convert()
474 spin_unlock_irqrestore(&s->lock, flags); in sidtab_cancel_convert()
479 context_destroy(&entry->context); in sidtab_destroy_entry()
481 kfree(rcu_dereference_raw(entry->cache)); in sidtab_destroy_entry()
485 static void sidtab_destroy_tree(union sidtab_entry_inner entry, u32 level) in sidtab_destroy_tree() argument
489 if (level != 0) { in sidtab_destroy_tree()
496 sidtab_destroy_tree(node->entries[i], level - 1); in sidtab_destroy_tree()
505 sidtab_destroy_entry(&node->entries[i]); in sidtab_destroy_tree()
512 u32 i, level; in sidtab_destroy() local
515 if (s->isids[i].set) in sidtab_destroy()
516 sidtab_destroy_entry(&s->isids[i].entry); in sidtab_destroy()
518 level = SIDTAB_MAX_LEVEL; in sidtab_destroy()
519 while (level && !s->roots[level].ptr_inner) in sidtab_destroy()
520 --level; in sidtab_destroy()
522 sidtab_destroy_tree(s->roots[level], level); in sidtab_destroy()
535 struct sidtab_str_cache *cache, *victim = NULL; in sidtab_sid2str_put() local
538 /* do not cache invalid contexts */ in sidtab_sid2str_put()
539 if (entry->context.len) in sidtab_sid2str_put()
542 spin_lock_irqsave(&s->cache_lock, flags); in sidtab_sid2str_put()
544 cache = rcu_dereference_protected(entry->cache, in sidtab_sid2str_put()
545 lockdep_is_held(&s->cache_lock)); in sidtab_sid2str_put()
546 if (cache) { in sidtab_sid2str_put()
547 /* entry in cache - just bump to the head of LRU list */ in sidtab_sid2str_put()
548 list_move(&cache->lru_member, &s->cache_lru_list); in sidtab_sid2str_put()
552 cache = kmalloc(sizeof(struct sidtab_str_cache) + str_len, GFP_ATOMIC); in sidtab_sid2str_put()
553 if (!cache) in sidtab_sid2str_put()
556 if (s->cache_free_slots == 0) { in sidtab_sid2str_put()
557 /* pop a cache entry from the tail and free it */ in sidtab_sid2str_put()
558 victim = container_of(s->cache_lru_list.prev, in sidtab_sid2str_put()
560 list_del(&victim->lru_member); in sidtab_sid2str_put()
561 rcu_assign_pointer(victim->parent->cache, NULL); in sidtab_sid2str_put()
563 s->cache_free_slots--; in sidtab_sid2str_put()
565 cache->parent = entry; in sidtab_sid2str_put()
566 cache->len = str_len; in sidtab_sid2str_put()
567 memcpy(cache->str, str, str_len); in sidtab_sid2str_put()
568 list_add(&cache->lru_member, &s->cache_lru_list); in sidtab_sid2str_put()
570 rcu_assign_pointer(entry->cache, cache); in sidtab_sid2str_put()
573 spin_unlock_irqrestore(&s->cache_lock, flags); in sidtab_sid2str_put()
580 struct sidtab_str_cache *cache; in sidtab_sid2str_get() local
583 if (entry->context.len) in sidtab_sid2str_get()
584 return -ENOENT; /* do not cache invalid contexts */ in sidtab_sid2str_get()
588 cache = rcu_dereference(entry->cache); in sidtab_sid2str_get()
589 if (!cache) { in sidtab_sid2str_get()
590 rc = -ENOENT; in sidtab_sid2str_get()
592 *out_len = cache->len; in sidtab_sid2str_get()
594 *out = kmemdup(cache->str, cache->len, GFP_ATOMIC); in sidtab_sid2str_get()
596 rc = -ENOMEM; in sidtab_sid2str_get()