From: Sapan Bhatia Date: Mon, 30 Nov 2009 22:19:50 +0000 (+0000) Subject: Dcookie garbage collection, needed by Chopstix. X-Git-Tag: linux-2.6-27-4~43 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;ds=sidebyside;h=3c2a5901d44ab5e00ac0cf888ea90a3f29db8b88;p=linux-2.6.git Dcookie garbage collection, needed by Chopstix. --- diff --git a/linux-2.6-590-dcookies-mm.patch b/linux-2.6-590-dcookies-mm.patch new file mode 100644 index 000000000..67a0d398f --- /dev/null +++ b/linux-2.6-590-dcookies-mm.patch @@ -0,0 +1,318 @@ +diff -Nurb linux-2.6.27-580/fs/dcookies.c linux-2.6.27-590/fs/dcookies.c +--- linux-2.6.27-580/fs/dcookies.c 2009-07-23 10:51:40.000000000 -0400 ++++ linux-2.6.27-590/fs/dcookies.c 2009-11-30 17:26:58.000000000 -0500 +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -38,15 +39,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) +@@ -68,7 +75,18 @@ + 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); ++ if (dcookie_value(dcs) == dcookie) { ++ found = dcs; ++ break; ++ } ++ } ++ ++ if (!found) { ++ list = dcookie_hashtable[old_hash] + dcookie_hash(dcookie); + + list_for_each(pos, list) { + dcs = list_entry(pos, struct dcookie_struct, hash_list); +@@ -77,6 +95,8 @@ + break; + } + } ++ } ++ + + return found; + } +@@ -84,15 +104,14 @@ + + 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); + if (!dcs) + return NULL; + +@@ -112,7 +131,7 @@ + int err = 0; + struct dcookie_struct * dcs; + +- mutex_lock(&dcookie_mutex); ++ spin_lock(&dcookie_hash_write_lock); + + if (!is_live()) { + err = -EINVAL; +@@ -132,7 +151,7 @@ + *cookie = dcookie_value(dcs); + + out: +- mutex_unlock(&dcookie_mutex); ++ spin_unlock(&dcookie_hash_write_lock); + return err; + } + +@@ -204,7 +223,7 @@ + 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", +@@ -214,9 +233,11 @@ + 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; + +@@ -239,13 +260,16 @@ + 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[0]; ++ j = hash_size; + do { + INIT_LIST_HEAD(d); + d++; +- i--; +- } while (i); ++ j--; ++ } while (j); ++ } + + out: + return err; +@@ -262,25 +286,61 @@ + kmem_cache_free(dcookie_cache, dcs); + } + ++int dcookie_swap(void) { ++ if (is_shared()) ++ return -EAGAIN; + +-static void dcookie_exit(void) +-{ ++ 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 + 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) ++{ ++ 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; ++j) { ++ 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]); ++ } + +- kfree(dcookie_hashtable); + kmem_cache_destroy(dcookie_cache); + } + +@@ -330,3 +390,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); +diff -Nurb linux-2.6.27-580/include/linux/dcookies.h linux-2.6.27-590/include/linux/dcookies.h +--- linux-2.6.27-580/include/linux/dcookies.h 2008-10-09 18:13:53.000000000 -0400 ++++ linux-2.6.27-590/include/linux/dcookies.h 2009-11-30 16:42:59.000000000 -0500 +@@ -46,6 +46,27 @@ + */ + 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_colect(void); ++ + #else + + static inline struct dcookie_user * dcookie_register(void) +diff -Nurb linux-2.6.27-580/include/linux/dcookies.h.orig linux-2.6.27-590/include/linux/dcookies.h.orig +--- linux-2.6.27-580/include/linux/dcookies.h.orig 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.27-590/include/linux/dcookies.h.orig 2008-10-09 18:13:53.000000000 -0400 +@@ -0,0 +1,68 @@ ++/* ++ * dcookies.h ++ * ++ * Persistent cookie-path mappings ++ * ++ * Copyright 2002 John Levon ++ */ ++ ++#ifndef DCOOKIES_H ++#define DCOOKIES_H ++ ++ ++#ifdef CONFIG_PROFILING ++ ++#include ++#include ++#include ++ ++struct dcookie_user; ++ ++/** ++ * dcookie_register - register a user of dcookies ++ * ++ * Register as a dcookie user. Returns %NULL on failure. ++ */ ++struct dcookie_user * dcookie_register(void); ++ ++/** ++ * dcookie_unregister - unregister a user of dcookies ++ * ++ * Unregister as a dcookie user. This may invalidate ++ * any dcookie values returned from get_dcookie(). ++ */ ++void dcookie_unregister(struct dcookie_user * user); ++ ++/** ++ * get_dcookie - acquire a dcookie ++ * ++ * Convert the given dentry/vfsmount pair into ++ * a cookie value. ++ * ++ * Returns -EINVAL if no living task has registered as a ++ * dcookie user. ++ * ++ * Returns 0 on success, with *cookie filled in ++ */ ++int get_dcookie(struct path *path, unsigned long *cookie); ++ ++#else ++ ++static inline struct dcookie_user * dcookie_register(void) ++{ ++ return NULL; ++} ++ ++static inline void dcookie_unregister(struct dcookie_user * user) ++{ ++ return; ++} ++ ++static inline int get_dcookie(struct path *path, unsigned long *cookie) ++{ ++ return -ENOSYS; ++} ++ ++#endif /* CONFIG_PROFILING */ ++ ++#endif /* DCOOKIES_H */