linux-bk/kernel/user.c
<<
>>
Prefs
   1/*
   2 * The "user cache".
   3 *
   4 * (C) Copyright 1991-2000 Linus Torvalds
   5 *
   6 * We have a per-user structure to keep track of how many
   7 * processes, files etc the user has claimed, in order to be
   8 * able to have per-user limits for system resources. 
   9 */
  10
  11#include <linux/init.h>
  12#include <linux/sched.h>
  13#include <linux/slab.h>
  14#include <linux/bitops.h>
  15
  16/*
  17 * UID task count cache, to get fast user lookup in "alloc_uid"
  18 * when changing user ID's (ie setuid() and friends).
  19 */
  20#define UIDHASH_BITS            8
  21#define UIDHASH_SZ              (1 << UIDHASH_BITS)
  22#define UIDHASH_MASK            (UIDHASH_SZ - 1)
  23#define __uidhashfn(uid)        (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
  24#define uidhashentry(uid)       (uidhash_table + __uidhashfn((uid)))
  25
  26static kmem_cache_t *uid_cachep;
  27static struct list_head uidhash_table[UIDHASH_SZ];
  28static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
  29
  30struct user_struct root_user = {
  31        .__count        = ATOMIC_INIT(1),
  32        .processes      = ATOMIC_INIT(1),
  33        .files          = ATOMIC_INIT(0)
  34};
  35
  36/*
  37 * These routines must be called with the uidhash spinlock held!
  38 */
  39static inline void uid_hash_insert(struct user_struct *up, struct list_head *hashent)
  40{
  41        list_add(&up->uidhash_list, hashent);
  42}
  43
  44static inline void uid_hash_remove(struct user_struct *up)
  45{
  46        list_del(&up->uidhash_list);
  47}
  48
  49static inline struct user_struct *uid_hash_find(uid_t uid, struct list_head *hashent)
  50{
  51        struct list_head *up;
  52
  53        list_for_each(up, hashent) {
  54                struct user_struct *user;
  55
  56                user = list_entry(up, struct user_struct, uidhash_list);
  57
  58                if(user->uid == uid) {
  59                        atomic_inc(&user->__count);
  60                        return user;
  61                }
  62        }
  63
  64        return NULL;
  65}
  66
  67struct user_struct *find_user(uid_t uid)
  68{
  69        return uid_hash_find(uid, uidhashentry(uid));
  70}
  71
  72void free_uid(struct user_struct *up)
  73{
  74        if (up && atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
  75                uid_hash_remove(up);
  76                kmem_cache_free(uid_cachep, up);
  77                spin_unlock(&uidhash_lock);
  78        }
  79}
  80
  81struct user_struct * alloc_uid(uid_t uid)
  82{
  83        struct list_head *hashent = uidhashentry(uid);
  84        struct user_struct *up;
  85
  86        spin_lock(&uidhash_lock);
  87        up = uid_hash_find(uid, hashent);
  88        spin_unlock(&uidhash_lock);
  89
  90        if (!up) {
  91                struct user_struct *new;
  92
  93                new = kmem_cache_alloc(uid_cachep, SLAB_KERNEL);
  94                if (!new)
  95                        return NULL;
  96                new->uid = uid;
  97                atomic_set(&new->__count, 1);
  98                atomic_set(&new->processes, 0);
  99                atomic_set(&new->files, 0);
 100
 101                /*
 102                 * Before adding this, check whether we raced
 103                 * on adding the same user already..
 104                 */
 105                spin_lock(&uidhash_lock);
 106                up = uid_hash_find(uid, hashent);
 107                if (up) {
 108                        kmem_cache_free(uid_cachep, new);
 109                } else {
 110                        uid_hash_insert(new, hashent);
 111                        up = new;
 112                }
 113                spin_unlock(&uidhash_lock);
 114
 115        }
 116        return up;
 117}
 118
 119
 120static int __init uid_cache_init(void)
 121{
 122        int n;
 123
 124        uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
 125                                       0,
 126                                       SLAB_HWCACHE_ALIGN, NULL, NULL);
 127        if(!uid_cachep)
 128                panic("Cannot create uid taskcount SLAB cache\n");
 129
 130        for(n = 0; n < UIDHASH_SZ; ++n)
 131                INIT_LIST_HEAD(uidhash_table + n);
 132
 133        /* Insert the root user immediately - init already runs with this */
 134        uid_hash_insert(&root_user, uidhashentry(0));
 135        return 0;
 136}
 137
 138module_init(uid_cache_init);
 139
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.