void static_key_slow_inc(struct static_key *key) { int v, v1; STATIC_KEY_CHECK_USE(); /* * Careful if we get concurrent static_key_slow_inc() calls; * later calls must wait for the first one to _finish_ the * jump_label_update() process. At the same time, however, * the jump_label_update() call below wants to see * static_key_enabled(&key) for jumps to be updated properly. * * So give a special meaning to negative key->enabled: it sends * static_key_slow_inc() down the slow path, and it is non-zero * so it counts as "enabled" in jump_label_update(). Note that * atomic_inc_unless_negative() checks >= 0, so roll our own. */ for (v = atomic_read(&key->enabled); v > 0; v = v1) { v1 = atomic_cmpxchg(&key->enabled, v, v + 1); if (likely(v1 == v)) return; } jump_label_lock(); if (atomic_read(&key->enabled) == 0) { atomic_set(&key->enabled, -1); jump_label_update(key); atomic_set(&key->enabled, 1); } else { atomic_inc(&key->enabled); } jump_label_unlock(); }
void jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl) { STATIC_KEY_CHECK_USE(); key->timeout = rl; INIT_DELAYED_WORK(&key->work, jump_label_update_timeout); }
void static_key_disable_cpuslocked(struct static_key *key) { STATIC_KEY_CHECK_USE(key); if (atomic_read(&key->enabled) != 1) { WARN_ON_ONCE(atomic_read(&key->enabled) != 0); return; } jump_label_lock(); if (atomic_cmpxchg(&key->enabled, 1, 0)) jump_label_update(key); jump_label_unlock(); }
void static_key_slow_inc(struct static_key *key) { STATIC_KEY_CHECK_USE(); if (atomic_inc_not_zero(&key->enabled)) return; jump_label_lock(); if (atomic_read(&key->enabled) == 0) { if (!jump_label_get_branch_default(key)) jump_label_update(key, JUMP_LABEL_ENABLE); else jump_label_update(key, JUMP_LABEL_DISABLE); } atomic_inc(&key->enabled); jump_label_unlock(); }
void static_key_enable_cpuslocked(struct static_key *key) { STATIC_KEY_CHECK_USE(key); if (atomic_read(&key->enabled) > 0) { WARN_ON_ONCE(atomic_read(&key->enabled) != 1); return; } jump_label_lock(); if (atomic_read(&key->enabled) == 0) { atomic_set(&key->enabled, -1); jump_label_update(key); /* * See static_key_slow_inc(). */ atomic_set_release(&key->enabled, 1); } jump_label_unlock(); }
void static_key_slow_dec_deferred(struct static_key_deferred *key) { STATIC_KEY_CHECK_USE(); __static_key_slow_dec(&key->key, key->timeout, &key->work); }
void static_key_slow_dec(struct static_key *key) { STATIC_KEY_CHECK_USE(); __static_key_slow_dec(key, 0, NULL); }
void static_key_deferred_flush(struct static_key_deferred *key) { STATIC_KEY_CHECK_USE(key); flush_delayed_work(&key->work); }