From: Sapan Bhatia Date: Wed, 8 Apr 2009 15:47:52 +0000 (+0000) Subject: Continual garbage collection for Dcookies. X-Git-Tag: linux-2.6-22-34~5 X-Git-Url: http://git.onelab.eu/?p=linux-2.6.git;a=commitdiff_plain;h=ccea97027ba8c0509afab15acad35db8421f0c83 Continual garbage collection for Dcookies. --- diff --git a/linux-2.6-592-GC-dcookies-nosleep.patch b/linux-2.6-592-GC-dcookies-nosleep.patch new file mode 100644 index 000000000..6130260d3 --- /dev/null +++ b/linux-2.6-592-GC-dcookies-nosleep.patch @@ -0,0 +1,254 @@ +--- linux-chopstix/include/linux/dcookies.h.orig 2009-03-05 08:45:29.000000000 -0500 ++++ linux-chopstix/include/linux/dcookies.h 2009-03-12 13:43:53.000000000 -0400 +@@ -45,6 +45,27 @@ + int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt, + unsigned long * cookie); + ++ ++/** ++ * dcookie_swap - switch to the next dcookie epoch ++ * ++ * Deactivate the current dcookie hash table and activate ++ * the next one ++ * ++ * Returns 0 on success ++ */ ++ ++int dcookie_swap(void); ++ ++/** ++ * dcookie_garbage_collect - clear the hash table next in line ++ * ++ * Clear the hash table to be activated in the next epoch. ++ * ++ * Returns 0 on success ++ */ ++ ++int dcookie_garbage_colect(void); + #else + + static inline struct dcookie_user * dcookie_register(void) +--- linux-chopstix/fs/dcookies.c.orig 2009-03-05 08:46:09.000000000 -0500 ++++ linux-chopstix/fs/dcookies.c 2009-04-06 11:37:35.000000000 -0400 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + + /* The dcookies are allocated from a kmem_cache and +@@ -37,15 +38,21 @@ + + static LIST_HEAD(dcookie_users); + static DEFINE_MUTEX(dcookie_mutex); ++spinlock_t dcookie_hash_write_lock = SPIN_LOCK_UNLOCKED; + static struct kmem_cache *dcookie_cache __read_mostly; +-static struct list_head *dcookie_hashtable __read_mostly; ++static struct list_head *dcookie_hashtable[3] __read_mostly; + static size_t hash_size __read_mostly; ++unsigned int current_hash = 1, old_hash = 0; + + static inline int is_live(void) + { + return !(list_empty(&dcookie_users)); + } + ++static inline int is_shared(void) ++{ ++ return !(list_empty(&dcookie_users)) && !(list_empty(dcookie_users.next)); ++} + + /* The dentry is locked, its address will do for the cookie */ + static inline unsigned long dcookie_value(struct dcookie_struct * dcs) +@@ -67,7 +74,7 @@ + struct list_head * pos; + struct list_head * list; + +- list = dcookie_hashtable + dcookie_hash(dcookie); ++ list = dcookie_hashtable[current_hash] + dcookie_hash(dcookie); + + list_for_each(pos, list) { + dcs = list_entry(pos, struct dcookie_struct, hash_list); +@@ -77,13 +84,26 @@ + } + } + ++ if (!found) { ++ list = dcookie_hashtable[old_hash] + dcookie_hash(dcookie); ++ ++ list_for_each(pos, list) { ++ dcs = list_entry(pos, struct dcookie_struct, hash_list); ++ if (dcookie_value(dcs) == dcookie) { ++ found = dcs; ++ break; ++ } ++ } ++ ++ } ++ + return found; + } + + + static void hash_dcookie(struct dcookie_struct * dcs) + { +- struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs)); ++ struct list_head * list = dcookie_hashtable[current_hash] + dcookie_hash(dcookie_value(dcs)); + list_add(&dcs->hash_list, list); + } + +@@ -91,7 +111,7 @@ + static struct dcookie_struct * alloc_dcookie(struct dentry * dentry, + struct vfsmount * vfsmnt) + { +- struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_KERNEL); ++ struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_ATOMIC); + if (!dcs) + return NULL; + +@@ -114,7 +134,7 @@ + int err = 0; + struct dcookie_struct * dcs; + +- mutex_lock(&dcookie_mutex); ++ spin_lock(&dcookie_hash_write_lock); + + if (!is_live()) { + err = -EINVAL; +@@ -134,7 +154,7 @@ + *cookie = dcookie_value(dcs); + + out: +- mutex_unlock(&dcookie_mutex); ++ spin_unlock(&dcookie_hash_write_lock); + return err; + } + +@@ -210,9 +230,18 @@ + if (!dcookie_cache) + goto out; + +- dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL); +- if (!dcookie_hashtable) ++ dcookie_hashtable[0] = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ if (!dcookie_hashtable[0]) + goto out_kmem; ++ ++ dcookie_hashtable[1] = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ if (!dcookie_hashtable[1]) ++ goto out_kmem; ++ ++ dcookie_hashtable[2] = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ if (!dcookie_hashtable[2]) ++ goto out_kmem; ++ + + err = 0; + +@@ -235,7 +264,24 @@ + hash_size = 1UL << hash_bits; + + /* And initialize the newly allocated array */ +- d = dcookie_hashtable; ++ ++ d = dcookie_hashtable[0]; ++ i = hash_size; ++ do { ++ INIT_LIST_HEAD(d); ++ d++; ++ i--; ++ } while (i); ++ ++ d = dcookie_hashtable[1]; ++ i = hash_size; ++ do { ++ INIT_LIST_HEAD(d); ++ d++; ++ i--; ++ } while (i); ++ ++ d = dcookie_hashtable[2]; + i = hash_size; + do { + INIT_LIST_HEAD(d); +@@ -259,6 +305,39 @@ + kmem_cache_free(dcookie_cache, dcs); + } + ++int dcookie_swap(void) { ++ if (is_shared()) ++ return -EAGAIN; ++ ++ old_hash=current_hash; ++ current_hash = (current_hash + 1) % 3; ++ return 0; ++} ++ ++/* Switch to the second hash */ ++int dcookie_garbage_collect(void) { ++ struct list_head * list; ++ struct list_head * pos; ++ struct list_head * pos2; ++ struct dcookie_struct * dcs; ++ size_t i; ++ int next_hash=(current_hash + 1) % 3; ++ ++ if (is_shared()) ++ return -EAGAIN; ++ ++ /* XXX consider the consequence of dcookie allocation concurring with this cleanup */ ++ for (i = 0; i < hash_size; ++i) { ++ list = dcookie_hashtable[next_hash] + i; ++ list_for_each_safe(pos, pos2, list) { ++ dcs = list_entry(pos, struct dcookie_struct, hash_list); ++ list_del(&dcs->hash_list); ++ free_dcookie(dcs); ++ } ++ } ++ ++ return 0; ++} + + static void dcookie_exit(void) + { +@@ -269,7 +348,21 @@ + size_t i; + + for (i = 0; i < hash_size; ++i) { +- list = dcookie_hashtable + i; ++ list = dcookie_hashtable[0] + i; ++ list_for_each_safe(pos, pos2, list) { ++ dcs = list_entry(pos, struct dcookie_struct, hash_list); ++ list_del(&dcs->hash_list); ++ free_dcookie(dcs); ++ } ++ ++ list = dcookie_hashtable[1] + i; ++ list_for_each_safe(pos, pos2, list) { ++ dcs = list_entry(pos, struct dcookie_struct, hash_list); ++ list_del(&dcs->hash_list); ++ free_dcookie(dcs); ++ } ++ ++ list = dcookie_hashtable[2] + i; + list_for_each_safe(pos, pos2, list) { + dcs = list_entry(pos, struct dcookie_struct, hash_list); + list_del(&dcs->hash_list); +@@ -277,7 +370,9 @@ + } + } + +- kfree(dcookie_hashtable); ++ kfree(dcookie_hashtable[0]); ++ kfree(dcookie_hashtable[1]); ++ kfree(dcookie_hashtable[2]); + kmem_cache_destroy(dcookie_cache); + } + +@@ -327,3 +422,5 @@ + EXPORT_SYMBOL_GPL(dcookie_register); + EXPORT_SYMBOL_GPL(dcookie_unregister); + EXPORT_SYMBOL_GPL(get_dcookie); ++EXPORT_SYMBOL_GPL(dcookie_garbage_collect); ++EXPORT_SYMBOL_GPL(dcookie_swap);