limiter
static void dump_limiter(const char *name, struct limiter *limiter)
vdo_log_info("%s: %u of %u busy (max %u), %s", name, limiter->busy,
limiter->limit, limiter->max_busy,
((bio_list_empty(&limiter->waiters) &&
bio_list_empty(&limiter->new_waiters)) ?
dump_limiter("data_vios", &pool->limiter);
for (i = 0; i < pool->limiter.limit; i++) {
return READ_ONCE(pool->limiter.busy);
return READ_ONCE(pool->limiter.limit);
return READ_ONCE(pool->limiter.max_busy);
struct limiter;
typedef void (*assigner_fn)(struct limiter *limiter);
struct limiter limiter;
struct limiter discard_limiter;
if (pool->limiter.busy > 0)
return (bio_list_empty(&pool->limiter.new_waiters) &&
static void assign_data_vio(struct limiter *limiter, struct data_vio *data_vio)
struct bio *bio = bio_list_pop(limiter->permitted_waiters);
launch_bio(limiter->pool->completion.vdo, data_vio, bio);
limiter->wake_count++;
bio = bio_list_peek(limiter->permitted_waiters);
limiter->arrival = ((bio == NULL) ? U64_MAX : get_arrival_time(bio));
static void assign_discard_permit(struct limiter *limiter)
struct bio *bio = bio_list_pop(&limiter->waiters);
if (limiter->arrival == U64_MAX)
limiter->arrival = get_arrival_time(bio);
bio_list_add(limiter->permitted_waiters, bio);
static void get_waiters(struct limiter *limiter)
bio_list_merge_init(&limiter->waiters, &limiter->new_waiters);
static void assign_data_vio_to_waiter(struct limiter *limiter)
assign_data_vio(limiter, get_available_data_vio(limiter->pool));
static void update_limiter(struct limiter *limiter)
struct bio_list *waiters = &limiter->waiters;
data_vio_count_t available = limiter->limit - limiter->busy;
VDO_ASSERT_LOG_ONLY((limiter->release_count <= limiter->busy),
limiter->release_count, limiter->busy);
get_waiters(limiter);
for (; (limiter->release_count > 0) && !bio_list_empty(waiters); limiter->release_count--)
limiter->assigner(limiter);
if (limiter->release_count > 0) {
WRITE_ONCE(limiter->busy, limiter->busy - limiter->release_count);
limiter->release_count = 0;
limiter->assigner(limiter);
WRITE_ONCE(limiter->busy, limiter->limit - available);
if (limiter->max_busy < limiter->busy)
WRITE_ONCE(limiter->max_busy, limiter->busy);
if (pool->limiter.arrival < pool->discard_limiter.arrival) {
assign_data_vio(&pool->limiter, data_vio);
pool->limiter.release_count++;
get_waiters(&pool->limiter);
if (pool->limiter.arrival == U64_MAX) {
struct bio *bio = bio_list_peek(&pool->limiter.waiters);
pool->limiter.arrival = get_arrival_time(bio);
update_limiter(&pool->limiter);
to_wake = pool->limiter.wake_count;
pool->limiter.wake_count = 0;
wake_up_nr(&pool->limiter.blocked_threads, to_wake);
static void initialize_limiter(struct limiter *limiter, struct data_vio_pool *pool,
limiter->pool = pool;
limiter->assigner = assigner;
limiter->limit = limit;
limiter->arrival = U64_MAX;
init_waitqueue_head(&limiter->blocked_threads);
initialize_limiter(&pool->limiter, pool, assign_data_vio_to_waiter, pool_size);
pool->limiter.permitted_waiters = &pool->limiter.waiters;
VDO_ASSERT_LOG_ONLY((pool->limiter.busy == 0),
pool->limiter.busy);
VDO_ASSERT_LOG_ONLY((bio_list_empty(&pool->limiter.waiters) &&
bio_list_empty(&pool->limiter.new_waiters)),
static bool acquire_permit(struct limiter *limiter)
if (limiter->busy >= limiter->limit)
WRITE_ONCE(limiter->busy, limiter->busy + 1);
if (limiter->max_busy < limiter->busy)
WRITE_ONCE(limiter->max_busy, limiter->busy);
static void wait_permit(struct limiter *limiter, struct bio *bio)
__releases(&limiter->pool->lock)
bio_list_add(&limiter->new_waiters, bio);
prepare_to_wait_exclusive(&limiter->blocked_threads, &wait,
spin_unlock(&limiter->pool->lock);
finish_wait(&limiter->blocked_threads, &wait);
if (!acquire_permit(&pool->limiter)) {
wait_permit(&pool->limiter, bio);
__le32 limiter;
struct semaphore *limiter = &rxrpc_call_limiter;
limiter = &rxrpc_kernel_call_limiter;
down(limiter);
return limiter;
return down_interruptible(limiter) < 0 ? NULL : limiter;
struct semaphore *limiter = &rxrpc_call_limiter;
limiter = &rxrpc_kernel_call_limiter;
up(limiter);
struct semaphore *limiter;
limiter = rxrpc_get_call_slot(p, gfp);
if (!limiter) {
up(limiter);