18c2ecf20Sopenharmony_ci#include <linux/export.h> 28c2ecf20Sopenharmony_ci#include <linux/kernel.h> 38c2ecf20Sopenharmony_ci#include <linux/mm.h> 48c2ecf20Sopenharmony_ci#include <linux/slab.h> 58c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* Allocate an array of spinlocks to be accessed by a hash. Two arguments 88c2ecf20Sopenharmony_ci * indicate the number of elements to allocate in the array. max_size 98c2ecf20Sopenharmony_ci * gives the maximum number of elements to allocate. cpu_mult gives 108c2ecf20Sopenharmony_ci * the number of locks per CPU to allocate. The size is rounded up 118c2ecf20Sopenharmony_ci * to a power of 2 to be suitable as a hash table. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciint __alloc_bucket_spinlocks(spinlock_t **locks, unsigned int *locks_mask, 158c2ecf20Sopenharmony_ci size_t max_size, unsigned int cpu_mult, gfp_t gfp, 168c2ecf20Sopenharmony_ci const char *name, struct lock_class_key *key) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci spinlock_t *tlocks = NULL; 198c2ecf20Sopenharmony_ci unsigned int i, size; 208c2ecf20Sopenharmony_ci#if defined(CONFIG_PROVE_LOCKING) 218c2ecf20Sopenharmony_ci unsigned int nr_pcpus = 2; 228c2ecf20Sopenharmony_ci#else 238c2ecf20Sopenharmony_ci unsigned int nr_pcpus = num_possible_cpus(); 248c2ecf20Sopenharmony_ci#endif 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (cpu_mult) { 278c2ecf20Sopenharmony_ci nr_pcpus = min_t(unsigned int, nr_pcpus, 64UL); 288c2ecf20Sopenharmony_ci size = min_t(unsigned int, nr_pcpus * cpu_mult, max_size); 298c2ecf20Sopenharmony_ci } else { 308c2ecf20Sopenharmony_ci size = max_size; 318c2ecf20Sopenharmony_ci } 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (sizeof(spinlock_t) != 0) { 348c2ecf20Sopenharmony_ci tlocks = kvmalloc_array(size, sizeof(spinlock_t), gfp); 358c2ecf20Sopenharmony_ci if (!tlocks) 368c2ecf20Sopenharmony_ci return -ENOMEM; 378c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 388c2ecf20Sopenharmony_ci spin_lock_init(&tlocks[i]); 398c2ecf20Sopenharmony_ci lockdep_init_map(&tlocks[i].dep_map, name, key, 0); 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci *locks = tlocks; 448c2ecf20Sopenharmony_ci *locks_mask = size - 1; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__alloc_bucket_spinlocks); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_civoid free_bucket_spinlocks(spinlock_t *locks) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci kvfree(locks); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(free_bucket_spinlocks); 55