/* * Pop up to IDA_PCPU_BATCH_MOVE IDs off the global freelist, and push them onto * our percpu freelist: */ static inline void alloc_global_tags(struct percpu_ida *pool, struct percpu_ida_cpu *tags) { move_tags(tags->freelist, &tags->nr_free, pool->freelist, &pool->nr_free, min(pool->nr_free, pool->percpu_batch_size)); }
/* * Pop up to IDA_PCPU_BATCH_MOVE IDs off the global freelist, and push them onto * our percpu freelist: */ static inline void alloc_global_tags(struct percpu_ida *pool, struct percpu_ida_cpu *tags) { move_tags(tags->freelist, &tags->nr_free, pool->freelist, &pool->nr_free, min(pool->nr_free, IDA_PCPU_BATCH_MOVE)); }
/** * percpu_ida_free - free a tag * @pool: pool @tag was allocated from * @tag: a tag previously allocated with percpu_ida_alloc() * * Safe to be called from interrupt context. */ void percpu_ida_free(struct percpu_ida *pool, unsigned tag) { struct percpu_ida_cpu *tags; unsigned long flags; unsigned nr_free; BUG_ON(tag >= pool->nr_tags); local_irq_save(flags); tags = this_cpu_ptr(pool->tag_cpu); spin_lock(&tags->lock); tags->freelist[tags->nr_free++] = tag; nr_free = tags->nr_free; spin_unlock(&tags->lock); if (nr_free == 1) { cpumask_set_cpu(smp_processor_id(), &pool->cpus_have_tags); wake_up(&pool->wait); } if (nr_free == pool->percpu_max_size) { spin_lock(&pool->lock); /* * Global lock held and irqs disabled, don't need percpu * lock */ if (tags->nr_free == pool->percpu_max_size) { move_tags(pool->freelist, &pool->nr_free, tags->freelist, &tags->nr_free, pool->percpu_batch_size); wake_up(&pool->wait); } spin_unlock(&pool->lock); } local_irq_restore(flags); }
/** * percpu_ida_free - free a tag * @pool: pool @tag was allocated from * @tag: a tag previously allocated with percpu_ida_alloc() * * Safe to be called from interrupt context. */ void percpu_ida_free(struct percpu_ida *pool, unsigned tag) { struct percpu_ida_cpu *tags; unsigned long flags; unsigned nr_free; BUG_ON(tag >= pool->nr_tags); tags = raw_cpu_ptr(pool->tag_cpu); spin_lock_irqsave(&tags->lock, flags); tags->freelist[tags->nr_free++] = tag; nr_free = tags->nr_free; if (nr_free == 1) { cpumask_set_cpu(smp_processor_id(), &pool->cpus_have_tags); wake_up(&pool->wait); } spin_unlock_irqrestore(&tags->lock, flags); if (nr_free == pool->percpu_max_size) { spin_lock_irqsave(&pool->lock, flags); spin_lock(&tags->lock); if (tags->nr_free == pool->percpu_max_size) { move_tags(pool->freelist, &pool->nr_free, tags->freelist, &tags->nr_free, pool->percpu_batch_size); wake_up(&pool->wait); } spin_unlock(&tags->lock); spin_unlock_irqrestore(&pool->lock, flags); } }