add linux-2.6-590-dcookies-mm.patch
[linux-2.6.git] / linux-2.6-590-dcookies-mm.patch
1 diff --git a/fs/dcookies.c b/fs/dcookies.c
2 index a21cabd..1e95c94 100644
3 --- a/fs/dcookies.c
4 +++ b/fs/dcookies.c
5 @@ -25,6 +25,7 @@
6  #include <linux/dcookies.h>
7  #include <linux/mutex.h>
8  #include <linux/path.h>
9 +#include <linux/spinlock.h>
10  #include <asm/uaccess.h>
11  
12  /* The dcookies are allocated from a kmem_cache and
13 @@ -38,15 +39,21 @@ struct dcookie_struct {
14  
15  static LIST_HEAD(dcookie_users);
16  static DEFINE_MUTEX(dcookie_mutex);
17 +spinlock_t dcookie_hash_write_lock = SPIN_LOCK_UNLOCKED;
18  static struct kmem_cache *dcookie_cache __read_mostly;
19 -static struct list_head *dcookie_hashtable __read_mostly;
20 +static struct list_head *dcookie_hashtable[3] __read_mostly;
21  static size_t hash_size __read_mostly;
22 +unsigned int current_hash = 1, old_hash = 0;
23  
24  static inline int is_live(void)
25  {
26         return !(list_empty(&dcookie_users));
27  }
28  
29 +static inline int is_shared(void)
30 +{
31 +       return !(list_empty(&dcookie_users)) && !(list_empty(dcookie_users.next));
32 +}
33  
34  /* The dentry is locked, its address will do for the cookie */
35  static inline unsigned long dcookie_value(struct dcookie_struct * dcs)
36 @@ -68,7 +75,7 @@ static struct dcookie_struct * find_dcookie(unsigned long dcookie)
37         struct list_head * pos;
38         struct list_head * list;
39  
40 -       list = dcookie_hashtable + dcookie_hash(dcookie);
41 +       list = dcookie_hashtable[current_hash] + dcookie_hash(dcookie);
42  
43         list_for_each(pos, list) {
44                 dcs = list_entry(pos, struct dcookie_struct, hash_list);
45 @@ -78,21 +85,33 @@ static struct dcookie_struct * find_dcookie(unsigned long dcookie)
46                 }
47         }
48  
49 +       if (!found) {
50 +               list = dcookie_hashtable[old_hash] + dcookie_hash(dcookie);
51 +
52 +               list_for_each(pos, list) {
53 +                       dcs = list_entry(pos, struct dcookie_struct, hash_list);
54 +                       if (dcookie_value(dcs) == dcookie) {
55 +                               found = dcs;
56 +                               break;
57 +                       }
58 +               }
59 +       }
60 +
61         return found;
62  }
63  
64  
65  static void hash_dcookie(struct dcookie_struct * dcs)
66  {
67 -       struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs));
68 +       struct list_head * list = dcookie_hashtable[current_hash] + dcookie_hash(dcookie_value(dcs));
69         list_add(&dcs->hash_list, list);
70  }
71  
72  
73  static struct dcookie_struct *alloc_dcookie(struct path *path)
74  {
75 -       struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache,
76 -                                                       GFP_KERNEL);
77 +       struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, GFP_ATOMIC);
78 +       
79         struct dentry *d;
80         if (!dcs)
81                 return NULL;
82 @@ -117,7 +136,7 @@ int get_dcookie(struct path *path, unsigned long *cookie)
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 @@ -137,7 +156,7 @@ int get_dcookie(struct path *path, unsigned long *cookie)
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 @@ -209,7 +228,7 @@ SYSCALL_ALIAS(sys_lookup_dcookie, SyS_lookup_dcookie);
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 @@ -219,9 +238,11 @@ static int dcookie_init(void)
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 @@ -244,13 +265,15 @@ static int dcookie_init(void)
124         hash_size = 1UL << hash_bits;
125  
126         /* And initialize the newly allocated array */
127 -       d = dcookie_hashtable;
128 -       i = hash_size;
129 +       for (i=0; i<3; i++) {
130 +               d = dcookie_hashtable[i];
131 +               j = hash_size;
132         do {
133                 INIT_LIST_HEAD(d);
134                 d++;
135 -               i--;
136 -       } while (i);
137 +               j--;
138 +               } while (j);
139 +       }
140  
141  out:
142         return err;
143 @@ -272,17 +295,31 @@ static void free_dcookie(struct dcookie_struct * dcs)
144         kmem_cache_free(dcookie_cache, dcs);
145  }
146  
147 +int dcookie_swap(void) {
148 +       if (is_shared())
149 +               return -EAGAIN;
150 +       
151 +       old_hash=current_hash;
152 +       current_hash = (current_hash + 1) % 3;
153 +       return 0;
154 +}
155  
156 -static void dcookie_exit(void)
157 -{
158 +/* Switch to the second hash */
159 +int dcookie_garbage_collect(void) {
160         struct list_head * list;
161         struct list_head * pos;
162         struct list_head * pos2;
163         struct dcookie_struct * dcs;
164         size_t i;
165 +       
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 @@ -290,7 +327,29 @@ static void dcookie_exit(void)
179                 }
180         }
181  
182 -       kfree(dcookie_hashtable);
183 +       return 0;
184 +}
185 +
186 +static void dcookie_exit(void)
187 +{
188 +       struct list_head * list;
189 +       struct list_head * pos;
190 +       struct list_head * pos2;
191 +       struct dcookie_struct * dcs;
192 +       size_t j;
193 +       unsigned int i;
194 +
195 +       for (i = 0; i < 3; ++i) {
196 +               for (j = 0; j < hash_size; ++j) {
197 +                       list = dcookie_hashtable[i] + j;
198 +                       list_for_each_safe(pos, pos2, list) {
199 +                               dcs = list_entry(pos, struct dcookie_struct, hash_list);
200 +                               list_del(&dcs->hash_list);
201 +                               free_dcookie(dcs);
202 +                       }
203 +               }
204 +               kfree(dcookie_hashtable[i]);
205 +       }
206         kmem_cache_destroy(dcookie_cache);
207  }
208  
209 @@ -340,3 +399,5 @@ void dcookie_unregister(struct dcookie_user * user)
210  EXPORT_SYMBOL_GPL(dcookie_register);
211  EXPORT_SYMBOL_GPL(dcookie_unregister);
212  EXPORT_SYMBOL_GPL(get_dcookie);
213 +EXPORT_SYMBOL_GPL(dcookie_garbage_collect);
214 +EXPORT_SYMBOL_GPL(dcookie_swap);
215 diff --git a/include/linux/dcookies.h b/include/linux/dcookies.h
216 index 24c806f..3c1d2b2 100644
217 --- a/include/linux/dcookies.h
218 +++ b/include/linux/dcookies.h
219 @@ -46,6 +46,27 @@ void dcookie_unregister(struct dcookie_user * user);
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)