Dcookie garbage collection, needed by Chopstix.
authorSapan Bhatia <sapanb@cs.princeton.edu>
Mon, 30 Nov 2009 22:19:50 +0000 (22:19 +0000)
committerSapan Bhatia <sapanb@cs.princeton.edu>
Mon, 30 Nov 2009 22:19:50 +0000 (22:19 +0000)
linux-2.6-590-dcookies-mm.patch [new file with mode: 0644]

diff --git a/linux-2.6-590-dcookies-mm.patch b/linux-2.6-590-dcookies-mm.patch
new file mode 100644 (file)
index 0000000..67a0d39
--- /dev/null
@@ -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 <linux/errno.h>
+ #include <linux/dcookies.h>
+ #include <linux/mutex.h>
++#include <linux/spinlock.h>
+ #include <linux/path.h>
+ #include <asm/uaccess.h>
+@@ -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 <levon@movementarian.org>
++ */
++
++#ifndef DCOOKIES_H
++#define DCOOKIES_H
++ 
++
++#ifdef CONFIG_PROFILING
++ 
++#include <linux/dcache.h>
++#include <linux/path.h>
++#include <linux/types.h>
++ 
++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 */