Setting tag linux-2.6-27-38
[linux-2.6.git] / linux-2.6-590-dcookies-mm.patch
1 diff -Nurb linux-2.6.27-580/fs/dcookies.c linux-2.6.27-590/fs/dcookies.c
2 --- linux-2.6.27-580/fs/dcookies.c      2009-07-23 10:51:40.000000000 -0400
3 +++ linux-2.6.27-590/fs/dcookies.c      2009-11-30 17:26:58.000000000 -0500
4 @@ -24,6 +24,7 @@
5  #include <linux/errno.h>
6  #include <linux/dcookies.h>
7  #include <linux/mutex.h>
8 +#include <linux/spinlock.h>
9  #include <linux/path.h>
10  #include <asm/uaccess.h>
11  
12 @@ -38,15 +39,21 @@
13  
14  static LIST_HEAD(dcookie_users);
15  static DEFINE_MUTEX(dcookie_mutex);
16 +spinlock_t dcookie_hash_write_lock = SPIN_LOCK_UNLOCKED;
17  static struct kmem_cache *dcookie_cache __read_mostly;
18 -static struct list_head *dcookie_hashtable __read_mostly;
19 +static struct list_head *dcookie_hashtable[3] __read_mostly;
20  static size_t hash_size __read_mostly;
21 +unsigned int current_hash = 1, old_hash = 0;
22  
23  static inline int is_live(void)
24  {
25         return !(list_empty(&dcookie_users));
26  }
27  
28 +static inline int is_shared(void)
29 +{
30 +       return !(list_empty(&dcookie_users)) && !(list_empty(dcookie_users.next));
31 +}
32  
33  /* The dentry is locked, its address will do for the cookie */
34  static inline unsigned long dcookie_value(struct dcookie_struct * dcs)
35 @@ -68,7 +75,18 @@
36         struct list_head * pos;
37         struct list_head * list;
38  
39 -       list = dcookie_hashtable + dcookie_hash(dcookie);
40 +       list = dcookie_hashtable[current_hash] + dcookie_hash(dcookie);
41 +
42 +       list_for_each(pos, list) {
43 +               dcs = list_entry(pos, struct dcookie_struct, hash_list);
44 +               if (dcookie_value(dcs) == dcookie) {
45 +                       found = dcs;
46 +                       break;
47 +               }
48 +       }
49 +
50 +    if (!found) {
51 +        list = dcookie_hashtable[old_hash] + dcookie_hash(dcookie);
52  
53         list_for_each(pos, list) {
54                 dcs = list_entry(pos, struct dcookie_struct, hash_list);
55 @@ -77,6 +95,8 @@
56                         break;
57                 }
58         }
59 +    }
60 +
61  
62         return found;
63  }
64 @@ -84,15 +104,14 @@
65  
66  static void hash_dcookie(struct dcookie_struct * dcs)
67  {
68 -       struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs));
69 +       struct list_head * list = dcookie_hashtable[current_hash] + dcookie_hash(dcookie_value(dcs));
70         list_add(&dcs->hash_list, list);
71  }
72  
73  
74  static struct dcookie_struct *alloc_dcookie(struct path *path)
75  {
76 -       struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache,
77 -                                                       GFP_KERNEL);
78 +       struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_ATOMIC);
79         if (!dcs)
80                 return NULL;
81  
82 @@ -112,7 +131,7 @@
83         int err = 0;
84         struct dcookie_struct * dcs;
85  
86 -       mutex_lock(&dcookie_mutex);
87 +       spin_lock(&dcookie_hash_write_lock);
88  
89         if (!is_live()) {
90                 err = -EINVAL;
91 @@ -132,7 +151,7 @@
92         *cookie = dcookie_value(dcs);
93  
94  out:
95 -       mutex_unlock(&dcookie_mutex);
96 +       spin_unlock(&dcookie_hash_write_lock);
97         return err;
98  }
99  
100 @@ -204,7 +223,7 @@
101  static int dcookie_init(void)
102  {
103         struct list_head * d;
104 -       unsigned int i, hash_bits;
105 +       unsigned int i, j, hash_bits;
106         int err = -ENOMEM;
107  
108         dcookie_cache = kmem_cache_create("dcookie_cache",
109 @@ -214,9 +233,11 @@
110         if (!dcookie_cache)
111                 goto out;
112  
113 -       dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL);
114 -       if (!dcookie_hashtable)
115 +    for (i=0; i<3; i++) { 
116 +        dcookie_hashtable[i] = kmalloc(PAGE_SIZE, GFP_KERNEL);
117 +        if (!dcookie_hashtable[i])
118                 goto out_kmem;
119 +    }
120  
121         err = 0;
122  
123 @@ -239,13 +260,16 @@
124         hash_size = 1UL << hash_bits;
125  
126         /* And initialize the newly allocated array */
127 -       d = dcookie_hashtable;
128 -       i = hash_size;
129 +
130 +    for (i=0; i<3; i++) {
131 +        d = dcookie_hashtable[i];
132 +        j = hash_size;
133         do {
134                 INIT_LIST_HEAD(d);
135                 d++;
136 -               i--;
137 -       } while (i);
138 +            j--;
139 +        } while (j);
140 +    }
141  
142  out:
143         return err;
144 @@ -262,25 +286,61 @@
145         kmem_cache_free(dcookie_cache, dcs);
146  }
147  
148 +int dcookie_swap(void) {
149 +    if (is_shared())
150 +        return -EAGAIN;
151  
152 -static void dcookie_exit(void)
153 -{
154 +    old_hash=current_hash;
155 +    current_hash = (current_hash + 1) % 3;
156 +    return 0;
157 +}
158 +
159 +/* Switch to the second hash */
160 +int dcookie_garbage_collect(void) {
161         struct list_head * list;
162         struct list_head * pos;
163         struct list_head * pos2;
164         struct dcookie_struct * dcs;
165         size_t i;
166 +    int next_hash=(current_hash + 1) % 3;
167 +
168 +    if (is_shared())
169 +        return -EAGAIN;
170  
171 +    /* XXX consider the consequence of dcookie allocation concurring with this cleanup */
172         for (i = 0; i < hash_size; ++i) {
173 -               list = dcookie_hashtable + i;
174 +               list = dcookie_hashtable[next_hash] + i;
175 +               list_for_each_safe(pos, pos2, list) {
176 +                       dcs = list_entry(pos, struct dcookie_struct, hash_list);
177 +                       list_del(&dcs->hash_list);
178 +                       free_dcookie(dcs);
179 +               }
180 +       }
181 +
182 +    return 0;
183 +}
184 +
185 +static void dcookie_exit(void)
186 +{
187 +       struct list_head * list;
188 +       struct list_head * pos;
189 +       struct list_head * pos2;
190 +       struct dcookie_struct * dcs;
191 +       size_t j;
192 +    unsigned int i;
193 +
194 +    for (i = 0; i < 3; ++i) {
195 +        for (j = 0; j < hash_size; ++j) {
196 +            list = dcookie_hashtable[i] + j;
197                 list_for_each_safe(pos, pos2, list) {
198                         dcs = list_entry(pos, struct dcookie_struct, hash_list);
199                         list_del(&dcs->hash_list);
200                         free_dcookie(dcs);
201                 }
202         }
203 +           kfree(dcookie_hashtable[i]);
204 +    }
205  
206 -       kfree(dcookie_hashtable);
207         kmem_cache_destroy(dcookie_cache);
208  }
209  
210 @@ -330,3 +390,5 @@
211  EXPORT_SYMBOL_GPL(dcookie_register);
212  EXPORT_SYMBOL_GPL(dcookie_unregister);
213  EXPORT_SYMBOL_GPL(get_dcookie);
214 +EXPORT_SYMBOL_GPL(dcookie_garbage_collect);
215 +EXPORT_SYMBOL_GPL(dcookie_swap);
216 diff -Nurb linux-2.6.27-580/include/linux/dcookies.h linux-2.6.27-590/include/linux/dcookies.h
217 --- linux-2.6.27-580/include/linux/dcookies.h   2008-10-09 18:13:53.000000000 -0400
218 +++ linux-2.6.27-590/include/linux/dcookies.h   2009-11-30 16:42:59.000000000 -0500
219 @@ -46,6 +46,27 @@
220   */
221  int get_dcookie(struct path *path, unsigned long *cookie);
222  
223 +/**
224 + * dcookie_swap - switch to the next dcookie epoch
225 + *
226 + * Deactivate the current dcookie hash table and activate
227 + * the next one
228 + *
229 + * Returns 0 on success
230 + */
231 +
232 +int dcookie_swap(void);
233 +
234 +/**
235 + * dcookie_garbage_collect - clear the hash table next in line
236 + *
237 + * Clear the hash table to be activated in the next epoch.
238 + *
239 + * Returns 0 on success
240 + */
241 +
242 +int dcookie_garbage_collect(void);
243 +
244  #else
245  
246  static inline struct dcookie_user * dcookie_register(void)