1
2
3
4
5
6
7
8
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
18
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
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
103
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
134 uid_hash_insert(&root_user, uidhashentry(0));
135 return 0;
136}
137
138module_init(uid_cache_init);
139