From: Sapan Bhatia <sapanb@cs.princeton.edu>
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/?a=commitdiff_plain;h=ccea97027ba8c0509afab15acad35db8421f0c83;p=linux-2.6.git

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 <linux/errno.h>
+ #include <linux/dcookies.h>
+ #include <linux/mutex.h>
++#include <linux/spinlock.h>
+ #include <asm/uaccess.h>
+ 
+ /* 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);