/* Data structure and operations for quarantine queues. */
/* * Each queue is a single-linked list, which also stores the total size of * objects inside of it.
*/ struct qlist_head { struct qlist_node *head; struct qlist_node *tail;
size_t bytes; bool offline;
};
/* * The object quarantine consists of per-cpu queues and a global queue, * guarded by quarantine_lock.
*/ static DEFINE_PER_CPU(struct qlist_head, cpu_quarantine);
/* Round-robin FIFO array of batches. */ staticstruct qlist_head global_quarantine[QUARANTINE_BATCHES]; staticint quarantine_head; staticint quarantine_tail; /* Total size of all objects in global_quarantine across all batches. */ staticunsignedlong quarantine_size; static DEFINE_RAW_SPINLOCK(quarantine_lock);
DEFINE_STATIC_SRCU(remove_cache_srcu);
/* Maximum size of the global queue. */ staticunsignedlong quarantine_max_size;
/* * Target size of a batch in global_quarantine. * Usually equal to QUARANTINE_PERCPU_SIZE unless we have too much RAM.
*/ staticunsignedlong quarantine_batch_size;
/* * The fraction of physical memory the quarantine is allowed to occupy. * Quarantine doesn't support memory shrinker with SLAB allocator, so we keep * the ratio low to avoid OOM.
*/ #define QUARANTINE_FRACTION 32
/* * Note: Keep per-object metadata to allow KASAN print stack traces for * use-after-free-before-realloc bugs.
*/
/* * If init_on_free is enabled and KASAN's free metadata is stored in * the object, zero the metadata. Otherwise, the object's memory will * not be properly zeroed, as KASAN saves the metadata after the slab * allocator zeroes the object.
*/ if (slab_want_init_on_free(cache) &&
cache->kasan_info.free_meta_offset == 0)
memzero_explicit(free_meta, sizeof(*free_meta));
/* * If there's no metadata for this object, don't put it into * quarantine.
*/ if (!meta) returnfalse;
/* * Note: irq must be disabled until after we move the batch to the * global quarantine. Otherwise kasan_quarantine_remove_cache() can * miss some objects belonging to the cache if they are in our local * temp list. kasan_quarantine_remove_cache() executes on_each_cpu() * at the beginning which ensures that it either sees the objects in * per-cpu lists or in the global quarantine.
*/
local_irq_save(flags);
q = this_cpu_ptr(&cpu_quarantine); if (q->offline) {
local_irq_restore(flags); returnfalse;
}
qlist_put(q, &meta->quarantine_link, cache->size); if (unlikely(q->bytes > QUARANTINE_PERCPU_SIZE)) {
qlist_move_all(q, &temp);
raw_spin_lock(&quarantine_lock);
WRITE_ONCE(quarantine_size, quarantine_size + temp.bytes);
qlist_move_all(&temp, &global_quarantine[quarantine_tail]); if (global_quarantine[quarantine_tail].bytes >=
READ_ONCE(quarantine_batch_size)) { int new_tail;
if (likely(READ_ONCE(quarantine_size) <=
READ_ONCE(quarantine_max_size))) return;
/* * srcu critical section ensures that kasan_quarantine_remove_cache() * will not miss objects belonging to the cache while they are in our * local to_free list. srcu is chosen because (1) it gives us private * grace period domain that does not interfere with anything else, * and (2) it allows synchronize_srcu() to return without waiting * if there are no pending read critical sections (which is the * expected case).
*/
srcu_idx = srcu_read_lock(&remove_cache_srcu);
raw_spin_lock_irqsave(&quarantine_lock, flags);
/* * Update quarantine size in case of hotplug. Allocate a fraction of * the installed memory to quarantine minus per-cpu queue limits.
*/
total_size = (totalram_pages() << PAGE_SHIFT) /
QUARANTINE_FRACTION;
percpu_quarantines = QUARANTINE_PERCPU_SIZE * num_online_cpus();
new_quarantine_size = (total_size < percpu_quarantines) ?
0 : total_size - percpu_quarantines;
WRITE_ONCE(quarantine_max_size, new_quarantine_size); /* Aim at consuming at most 1/2 of slots in quarantine. */
WRITE_ONCE(quarantine_batch_size, max((size_t)QUARANTINE_PERCPU_SIZE,
2 * total_size / QUARANTINE_BATCHES));
if (likely(quarantine_size > quarantine_max_size)) {
qlist_move_all(&global_quarantine[quarantine_head], &to_free);
WRITE_ONCE(quarantine_size, quarantine_size - to_free.bytes);
quarantine_head++; if (quarantine_head == QUARANTINE_BATCHES)
quarantine_head = 0;
}
q = this_cpu_ptr(&cpu_quarantine); /* * Ensure the ordering between the writing to q->offline and * per_cpu_remove_cache. Prevent cpu_quarantine from being corrupted * by interrupt.
*/ if (READ_ONCE(q->offline)) return;
__per_cpu_remove_cache(q, arg);
}
/* Free all quarantined objects belonging to cache. */ void kasan_quarantine_remove_cache(struct kmem_cache *cache)
{ unsignedlong flags, i; struct qlist_head to_free = QLIST_INIT; int cpu; struct cpu_shrink_qlist *sq;
/* * Must be careful to not miss any objects that are being moved from * per-cpu list to the global quarantine in kasan_quarantine_put(), * nor objects being freed in kasan_quarantine_reduce(). on_each_cpu() * achieves the first goal, while synchronize_srcu() achieves the * second.
*/
on_each_cpu(per_cpu_remove_cache, cache, 1);
raw_spin_lock_irqsave(&quarantine_lock, flags); for (i = 0; i < QUARANTINE_BATCHES; i++) { if (qlist_empty(&global_quarantine[i])) continue;
qlist_move_cache(&global_quarantine[i], &to_free, cache); /* Scanning whole quarantine can take a while. */
raw_spin_unlock_irqrestore(&quarantine_lock, flags);
cond_resched();
raw_spin_lock_irqsave(&quarantine_lock, flags);
}
raw_spin_unlock_irqrestore(&quarantine_lock, flags);
q = this_cpu_ptr(&cpu_quarantine); /* Ensure the ordering between the writing to q->offline and * qlist_free_all. Otherwise, cpu_quarantine may be corrupted * by interrupt.
*/
WRITE_ONCE(q->offline, true);
barrier();
qlist_free_all(q, NULL); return 0;
}
staticint __init kasan_cpu_quarantine_init(void)
{ int ret = 0;
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mm/kasan:online",
kasan_cpu_online, kasan_cpu_offline); if (ret < 0)
pr_err("cpu quarantine register failed [%d]\n", ret); return ret;
}
late_initcall(kasan_cpu_quarantine_init);
Messung V0.5
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.