/*
       * The "user cache".
       *
       * (C) Copyright 1991-2000 Linus Torvalds
       *
       * We have a per-user structure to keep track of how many
       * processes, files etc the user has claimed, in order to be
       * able to have per-user limits for system resources. 
       */
      
      #include <linux/init.h>
      #include <linux/sched.h>
      #include <linux/slab.h>
      
      /*
       * UID task count cache, to get fast user lookup in "alloc_uid"
       * when changing user ID's (ie setuid() and friends).
       */
      #define UIDHASH_BITS		8
      #define UIDHASH_SZ		(1 << UIDHASH_BITS)
      #define UIDHASH_MASK		(UIDHASH_SZ - 1)
      #define __uidhashfn(uid)	(((uid >> UIDHASH_BITS) ^ uid) & UIDHASH_MASK)
      #define uidhashentry(uid)	(uidhash_table + __uidhashfn(uid))
      
      static kmem_cache_t *uid_cachep;
      static struct user_struct *uidhash_table[UIDHASH_SZ];
      static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
      
      struct user_struct root_user = {
      	__count:	ATOMIC_INIT(1),
      	processes:	ATOMIC_INIT(1),
      	files:		ATOMIC_INIT(0)
      };
      
      /*
       * These routines must be called with the uidhash spinlock held!
       */
  38  static inline void uid_hash_insert(struct user_struct *up, struct user_struct **hashent)
      {
      	struct user_struct *next = *hashent;
      
      	up->next = next;
  43  	if (next)
      		next->pprev = &up->next;
      	up->pprev = hashent;
      	*hashent = up;
      }
      
  49  static inline void uid_hash_remove(struct user_struct *up)
      {
      	struct user_struct *next = up->next;
      	struct user_struct **pprev = up->pprev;
      
  54  	if (next)
      		next->pprev = pprev;
      	*pprev = next;
      }
      
  59  static inline struct user_struct *uid_hash_find(uid_t uid, struct user_struct **hashent)
      {
      	struct user_struct *next;
      
      	next = *hashent;
  64  	for (;;) {
      		struct user_struct *up = next;
  66  		if (next) {
      			next = up->next;
  68  			if (up->uid != uid)
  69  				continue;
      			atomic_inc(&up->__count);
      		}
  72  		return up;
      	}
      }
      
  76  void free_uid(struct user_struct *up)
      {
  78  	if (up && atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
      		uid_hash_remove(up);
      		kmem_cache_free(uid_cachep, up);
  81  		spin_unlock(&uidhash_lock);
      	}
      }
      
  85  struct user_struct * alloc_uid(uid_t uid)
      {
      	struct user_struct **hashent = uidhashentry(uid);
      	struct user_struct *up;
      
      	spin_lock(&uidhash_lock);
      	up = uid_hash_find(uid, hashent);
  92  	spin_unlock(&uidhash_lock);
      
  94  	if (!up) {
      		struct user_struct *new;
      
      		new = kmem_cache_alloc(uid_cachep, SLAB_KERNEL);
  98  		if (!new)
  99  			return NULL;
      		new->uid = uid;
      		atomic_set(&new->__count, 1);
      		atomic_set(&new->processes, 0);
      		atomic_set(&new->files, 0);
      
      		/*
      		 * Before adding this, check whether we raced
      		 * on adding the same user already..
      		 */
      		spin_lock(&uidhash_lock);
      		up = uid_hash_find(uid, hashent);
 111  		if (up) {
      			kmem_cache_free(uid_cachep, new);
 113  		} else {
      			uid_hash_insert(new, hashent);
      			up = new;
      		}
 117  		spin_unlock(&uidhash_lock);
      
      	}
 120  	return up;
      }
      
      
 124  static int __init uid_cache_init(void)
      {
      	uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
      				       0,
      				       SLAB_HWCACHE_ALIGN, NULL, NULL);
 129  	if(!uid_cachep)
      		panic("Cannot create uid taskcount SLAB cache\n");
      
      	/* Insert the root user immediately - init already runs with this */
      	uid_hash_insert(&root_user, uidhashentry(0));
 134  	return 0;
      }
      
      module_init(uid_cache_init);