diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 74488e4..65ceeaa 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -66,7 +66,6 @@ struct proc_dir_entry {
 	write_proc_t *write_proc;
 	atomic_t count;		/* use count */
 	int deleted;		/* delete flag */
-	void *set;
 };
 
 struct kcore_list {
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index fc131d6..fc8e367 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -24,7 +24,6 @@
 #include <linux/compiler.h>
 
 struct file;
-struct completion;
 
 #define CTL_MAXNAME 10		/* how many path components do we allow in a
 				   call to sysctl?   In other words, what is
@@ -926,8 +925,6 @@ struct ctl_table_header
 {
 	ctl_table *ctl_table;
 	struct list_head ctl_entry;
-	int used;
-	struct completion *unregistering;
 };
 
 struct ctl_table_header * register_sysctl_table(ctl_table * table, 
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 9990e10..3d94e14 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -994,34 +994,57 @@ extern void init_irq_proc (void);
 
 static DEFINE_SPINLOCK(sysctl_lock);
 
+#include "ksplice-patch.h"
+#include "ksplice-shadow.h"
+
+struct header_shadow {
+	struct completion *unregistering;
+	int used;
+};
+
+struct proc_dir_shadow {
+	void *set;
+};
+
+DEFINE_SHADOW_FIELD(struct proc_dir_entry, struct proc_dir_shadow, GFP_ATOMIC,
+		    proc_dir, (void));
+#define init_new_header_shadow(shadow) \
+	do { shadow->used = 0; shadow->unregistering = NULL; } while(0);
+DEFINE_SHADOW_FIELD(struct ctl_table_header, struct header_shadow, GFP_ATOMIC,
+		    header, init_new_header_shadow);
+
 /* called under sysctl_lock */
 static int use_table(struct ctl_table_header *p)
 {
-	if (unlikely(p->unregistering))
+	struct header_shadow *shadow = make_header_shadow(p, GFP_ATOMIC);
+	if (unlikely(shadow == NULL || shadow->unregistering))
 		return 0;
-	p->used++;
+	shadow->used++;
 	return 1;
 }
 
 /* called under sysctl_lock */
 static void unuse_table(struct ctl_table_header *p)
 {
-	if (!--p->used)
-		if (unlikely(p->unregistering))
-			complete(p->unregistering);
+	struct header_shadow *shadow = get_header_shadow(p);
+	BUG_ON(shadow == NULL);
+	if (!--shadow->used)
+		if (unlikely(shadow->unregistering))
+			complete(shadow->unregistering);
 }
 
 /* called under sysctl_lock, will reacquire if has to wait */
 static void start_unregistering(struct ctl_table_header *p)
 {
+	struct header_shadow *shadow = make_header_shadow(p, GFP_ATOMIC);
 	/*
 	 * if p->used is 0, nobody will ever touch that entry again;
 	 * we'll eliminate all paths to it before dropping sysctl_lock
 	 */
-	if (unlikely(p->used)) {
+	if (unlikely(shadow == NULL || shadow->used)) {
 		struct completion wait;
 		init_completion(&wait);
-		p->unregistering = &wait;
+		shadow->unregistering = &wait;
 		spin_unlock(&sysctl_lock);
 		wait_for_completion(&wait);
 		spin_lock(&sysctl_lock);
@@ -1288,8 +1311,10 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table,
 		return NULL;
 	tmp->ctl_table = table;
 	INIT_LIST_HEAD(&tmp->ctl_entry);
-	tmp->used = 0;
-	tmp->unregistering = NULL;
+	if (init_header_shadow(tmp, GFP_ATOMIC) == NULL) {
+		kfree(tmp);
+		return NULL;
+	}
 	spin_lock(&sysctl_lock);
 	if (insert_at_head)
 		list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
@@ -1318,6 +1343,7 @@ void unregister_sysctl_table(struct ctl_table_header * header)
 	unregister_proc_table(header->ctl_table, proc_sys_root);
 #endif
 	spin_unlock(&sysctl_lock);
+	cleanup_header_shadow(header);
 	kfree(header);
 }
 
@@ -1361,10 +1387,16 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root,
 		}
 
 		if (!de) {
+			struct proc_dir_shadow *shadow;
 			de = create_proc_entry(table->procname, mode, root);
 			if (!de)
 				continue;
-			de->set = set;
+			shadow = init_proc_dir_shadow(de, GFP_KERNEL);
+			if (shadow == NULL) {
+				remove_proc_entry(table->procname, de);
+				continue;
+			}
+			shadow->set = set;
 			de->data = (void *) table;
 			if (table->proc_handler)
 				de->proc_fops = &proc_sys_file_operations;
@@ -1375,6 +1407,20 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root,
 	}
 }
 
+/* Scan the sysctl entries in table and add them all into /proc */
+static int scan_proc_table(ctl_table * table, struct proc_dir_entry *target)
+{
+	for (; table->ctl_name; table++) {
+		if (table->de == target)
+			return 1;
+		if (table->child && (table->de->mode & S_IFDIR)) {
+			if (scan_proc_table(table->child, target) == 1)
+				return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * Unregister a /proc sysctl table and any subdirectories.
  */
@@ -1408,6 +1454,7 @@ static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root
 			continue;
 
 		table->de = NULL;
+		cleanup_proc_dir_shadow(de);
 		remove_proc_entry(table->procname, root);
 	}
 }
@@ -1420,9 +1467,31 @@ static ssize_t do_rw_proc(int write, struct file * file, char __user * buf,
 	struct ctl_table *table;
 	size_t res;
 	ssize_t error = -ENOTDIR;
+	struct proc_dir_shadow *shadow;
 	
 	spin_lock(&sysctl_lock);
-	if (de && de->data && use_table(de->set)) {
+	shadow = get_proc_dir_shadow(de);
+	if (shadow == NULL && de && de->data) {
+		struct list_head *tmp = &root_table_header.ctl_entry;
+		shadow = init_proc_dir_shadow(de, GFP_ATOMIC);
+		if (shadow == NULL) {
+			spin_unlock(&sysctl_lock);
+			return -ENOMEM;
+		}
+		do {
+			struct ctl_table_header *head =
+			    list_entry(tmp, struct ctl_table_header, ctl_entry);
+			if (scan_proc_table(head->ctl_table, de)) {
+				shadow->set = head;
+				break;
+			}
+		} while ((tmp = tmp->next) != &root_table_header.ctl_entry);
+		if (shadow->set == NULL) {
+			spin_unlock(&sysctl_lock);
+			return -ENOENT;
+		}
+	}
+	if (de && de->data && use_table(shadow->set)) {
 		/*
 		 * at that point we know that sysctl was not unregistered
 		 * and won't be until we finish
@@ -1444,7 +1513,7 @@ static ssize_t do_rw_proc(int write, struct file * file, char __user * buf,
 			error = res;
 	out:
 		spin_lock(&sysctl_lock);
-		unuse_table(de->set);
+		unuse_table(shadow->set);
 	}
 	spin_unlock(&sysctl_lock);
 	return error;
