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
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>
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;
23 static inline int is_live(void)
25 return !(list_empty(&dcookie_users));
28 +static inline int is_shared(void)
30 + return !(list_empty(&dcookie_users)) && !(list_empty(dcookie_users.next));
33 /* The dentry is locked, its address will do for the cookie */
34 static inline unsigned long dcookie_value(struct dcookie_struct * dcs)
36 struct list_head * pos;
37 struct list_head * list;
39 - list = dcookie_hashtable + dcookie_hash(dcookie);
40 + list = dcookie_hashtable[current_hash] + dcookie_hash(dcookie);
42 + list_for_each(pos, list) {
43 + dcs = list_entry(pos, struct dcookie_struct, hash_list);
44 + if (dcookie_value(dcs) == dcookie) {
51 + list = dcookie_hashtable[old_hash] + dcookie_hash(dcookie);
53 list_for_each(pos, list) {
54 dcs = list_entry(pos, struct dcookie_struct, hash_list);
66 static void hash_dcookie(struct dcookie_struct * dcs)
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);
74 static struct dcookie_struct *alloc_dcookie(struct path *path)
76 - struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache,
78 + struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_ATOMIC);
84 struct dcookie_struct * dcs;
86 - mutex_lock(&dcookie_mutex);
87 + spin_lock(&dcookie_hash_write_lock);
92 *cookie = dcookie_value(dcs);
95 - mutex_unlock(&dcookie_mutex);
96 + spin_unlock(&dcookie_hash_write_lock);
101 static int dcookie_init(void)
103 struct list_head * d;
104 - unsigned int i, hash_bits;
105 + unsigned int i, j, hash_bits;
108 dcookie_cache = kmem_cache_create("dcookie_cache",
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])
123 @@ -239,13 +260,16 @@
124 hash_size = 1UL << hash_bits;
126 /* And initialize the newly allocated array */
127 - d = dcookie_hashtable;
130 + for (i=0; i<3; i++) {
131 + d = dcookie_hashtable[i];
144 @@ -262,25 +286,61 @@
145 kmem_cache_free(dcookie_cache, dcs);
148 +int dcookie_swap(void) {
152 -static void dcookie_exit(void)
154 + old_hash=current_hash;
155 + current_hash = (current_hash + 1) % 3;
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;
166 + int next_hash=(current_hash + 1) % 3;
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);
185 +static void dcookie_exit(void)
187 + struct list_head * list;
188 + struct list_head * pos;
189 + struct list_head * pos2;
190 + struct dcookie_struct * dcs;
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);
203 + kfree(dcookie_hashtable[i]);
206 - kfree(dcookie_hashtable);
207 kmem_cache_destroy(dcookie_cache);
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
221 int get_dcookie(struct path *path, unsigned long *cookie);
224 + * dcookie_swap - switch to the next dcookie epoch
226 + * Deactivate the current dcookie hash table and activate
229 + * Returns 0 on success
232 +int dcookie_swap(void);
235 + * dcookie_garbage_collect - clear the hash table next in line
237 + * Clear the hash table to be activated in the next epoch.
239 + * Returns 0 on success
242 +int dcookie_garbage_collect(void);
246 static inline struct dcookie_user * dcookie_register(void)