From d8e2bd85a3188b65ae8a3a82cc6dade218f69aa0 Mon Sep 17 00:00:00 2001 From: S.Çağlar Onur Date: Tue, 7 Dec 2010 11:09:20 -0500 Subject: [PATCH] linux-2.6-590-dcookies-mm.patch --- fs/dcookies.c | 97 +++++++++++++++++++++++++++++++++++++-------- include/linux/dcookies.h | 21 ++++++++++ 2 files changed, 100 insertions(+), 18 deletions(-) diff --git a/fs/dcookies.c b/fs/dcookies.c index a21cabd..1e95c94 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -25,6 +25,7 @@ #include #include #include +#include #include /* The dcookies are allocated from a kmem_cache and @@ -38,15 +39,21 @@ struct dcookie_struct { 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) @@ -68,7 +75,7 @@ static struct dcookie_struct * find_dcookie(unsigned long dcookie) 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); @@ -78,21 +85,33 @@ static struct dcookie_struct * find_dcookie(unsigned long dcookie) } } + 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); } static struct dcookie_struct *alloc_dcookie(struct path *path) { - struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, - GFP_KERNEL); + struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, GFP_ATOMIC); + struct dentry *d; if (!dcs) return NULL; @@ -117,7 +136,7 @@ int get_dcookie(struct path *path, unsigned long *cookie) int err = 0; struct dcookie_struct * dcs; - mutex_lock(&dcookie_mutex); + spin_lock(&dcookie_hash_write_lock); if (!is_live()) { err = -EINVAL; @@ -137,7 +156,7 @@ int get_dcookie(struct path *path, unsigned long *cookie) *cookie = dcookie_value(dcs); out: - mutex_unlock(&dcookie_mutex); + spin_unlock(&dcookie_hash_write_lock); return err; } @@ -209,7 +228,7 @@ SYSCALL_ALIAS(sys_lookup_dcookie, SyS_lookup_dcookie); static int dcookie_init(void) { struct list_head * d; - unsigned int i, hash_bits; + unsigned int i, j, hash_bits; int err = -ENOMEM; dcookie_cache = kmem_cache_create("dcookie_cache", @@ -219,9 +238,11 @@ static int dcookie_init(void) if (!dcookie_cache) goto out; - dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!dcookie_hashtable) + for (i=0; i<3; i++) { + dcookie_hashtable[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!dcookie_hashtable[i]) goto out_kmem; + } err = 0; @@ -244,13 +265,15 @@ static int dcookie_init(void) hash_size = 1UL << hash_bits; /* And initialize the newly allocated array */ - d = dcookie_hashtable; - i = hash_size; + for (i=0; i<3; i++) { + d = dcookie_hashtable[i]; + j = hash_size; do { INIT_LIST_HEAD(d); d++; - i--; - } while (i); + j--; + } while (j); + } out: return err; @@ -272,17 +295,31 @@ static void free_dcookie(struct dcookie_struct * dcs) 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; +} -static void dcookie_exit(void) -{ +/* 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 + 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); @@ -290,7 +327,29 @@ static void dcookie_exit(void) } } - kfree(dcookie_hashtable); + return 0; +} + +static void dcookie_exit(void) +{ + struct list_head * list; + struct list_head * pos; + struct list_head * pos2; + struct dcookie_struct * dcs; + size_t j; + unsigned int i; + + for (i = 0; i < 3; ++i) { + for (j = 0; j < hash_size; ++j) { + list = dcookie_hashtable[i] + j; + list_for_each_safe(pos, pos2, list) { + dcs = list_entry(pos, struct dcookie_struct, hash_list); + list_del(&dcs->hash_list); + free_dcookie(dcs); + } + } + kfree(dcookie_hashtable[i]); + } kmem_cache_destroy(dcookie_cache); } @@ -340,3 +399,5 @@ void dcookie_unregister(struct dcookie_user * user) 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); diff --git a/include/linux/dcookies.h b/include/linux/dcookies.h index 24c806f..3c1d2b2 100644 --- a/include/linux/dcookies.h +++ b/include/linux/dcookies.h @@ -46,6 +46,27 @@ void dcookie_unregister(struct dcookie_user * user); */ int get_dcookie(struct path *path, 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_collect(void); + #else static inline struct dcookie_user * dcookie_register(void) -- 1.5.4.3