diff --git a/include/linux/prune.h b/include/linux/prune.h
index 7c21d5c..e177fc2 100644
--- a/include/linux/prune.h
+++ b/include/linux/prune.h
@@ -58,6 +58,8 @@ struct prune_ops {
 				  struct prune_table *table, bool pruned);
 };
 
+int prune_init(void);
+void prune_fini(void);
 struct prune *prune_create(unsigned int mask_len, const struct prune_ops *ops,
 			   void *priv);
 void prune_destroy(struct prune *prune);
diff --git a/lib/prune.c b/lib/prune.c
index 77b3785..f9728d4 100644
--- a/lib/prune.c
+++ b/lib/prune.c
@@ -10,10 +10,20 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <linux/list.h>
+#include <linux/rculist.h>
 #include <linux/rhashtable.h>
 #include <linux/prune.h>
 #include <linux/jhash.h>
 #include <linux/bitmap.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+
+/*dentry for debugsfs purpose */
+static struct dentry *dentry;
+/* the list of all allocated prune objects */
+static struct list_head prune_object_list;
 
 /*
  * This structure holds the item configuration and its prune vector
@@ -43,6 +53,7 @@ struct prune_intersec_table_list_elem {
 struct prune_intersec_table {
 	struct rhashtable entry_ht;
 	unsigned long *mask;
+	struct list_head items_list; /* A walker for items_ht */
 	struct prune_table *neigh_table;
 	struct list_head list; /* Node of intersec_table_list (in prune_table)*/
 };
@@ -62,6 +73,7 @@ struct prune_intersec_table_entry {
 	struct prune_intersec_table *intersec_table;
 	struct list_head intersec_table_elem_list;
 	struct list_head neigh_table_elem_list;
+	struct list_head list; /* Node in items_list (in struct prune_intersec_table) */
 };
 
 /* This structure contains table entries of prune_table_entry and the
@@ -91,6 +103,190 @@ struct prune {
 	unsigned int mask_len;		/* Bits */
 };
 
+static void prune_vector_items_dump(struct seq_file *seq,
+				    struct prune_table_entry *entry)
+{
+	struct prune_vector_item *vector_item;
+
+	seq_puts(seq, "\t\titem prune vector:\n");
+	list_for_each_entry_rcu(vector_item, &entry->table_prune_vector, list) {
+		seq_printf(seq, "\t\t\ttable: %p\t is pruned: %s\n",
+			   vector_item->table->priv,
+			   vector_item->pruned ? "Yes" : "No");
+	}
+}
+
+static void prune_table_items_dump(struct seq_file *seq,
+				   struct prune_table *table)
+{
+	struct prune_table_entry *entry;
+
+	list_for_each_entry_rcu(entry, &table->entry_list, list) {
+		seq_puts(seq, "\t\titem info\n");
+		seq_puts(seq, "\t\t---------\n");
+		seq_printf(seq, "\t\titem key: %lu\n", *entry->item.key);
+		seq_printf(seq, "\t\titem prio: %u\n", entry->item.priority);
+		seq_printf(seq, "\t\titem priv: %p\n", entry->item.priv);
+
+		prune_vector_items_dump(seq, entry);
+	}
+}
+
+void prune_intersec_item_list_dump(struct seq_file *seq,
+				   struct prune_intersec_table *intersec_table)
+{
+	struct prune_intersec_table_entry *intersec_entry;
+	struct prune_intersec_table_list_elem *intersec_item;
+	struct prune_intersec_table_list_elem *neigh_item;
+
+	list_for_each_entry_rcu(intersec_entry, &intersec_table->items_list,
+				list) {
+		seq_puts(seq, "\t\t\tintersec entry info\n");
+		seq_puts(seq, "\t\t\t-------------------\n");
+		seq_printf(seq, "\t\t\t\t mask: %lu\n",
+			   *intersec_entry->ht_key);
+		seq_puts(seq, "\t\t\t\t intersec element info:\n");
+		list_for_each_entry_rcu(intersec_item,
+					&intersec_entry->intersec_table_elem_list,
+					list) {
+			seq_printf(seq, "\t\t\t\t\tentry prio: %lu\n",
+				   *intersec_item->entry->item.key);
+			seq_printf(seq, "\t\t\t\t\tentry prio: %u\n\n",
+				   intersec_item->entry->item.priority);
+		}
+		seq_puts(seq, "\t\t\t\t neigh element info:\n");
+		list_for_each_entry_rcu(neigh_item,
+					&intersec_entry->neigh_table_elem_list,
+					list) {
+			seq_printf(seq, "\t\t\t\t\tentry key: %lu\n",
+				   *neigh_item->entry->item.key);
+			seq_printf(seq, "\t\t\t\t\tentry prio: %u\n\n",
+				   neigh_item->entry->item.priority);
+		}
+	}
+}
+
+void prune_intersec_tables_dump(struct seq_file *seq, struct prune_table *table)
+{
+	struct prune_intersec_table *intersec_table;
+
+	list_for_each_entry_rcu(intersec_table, &table->intersec_table_list,
+				list) {
+		seq_puts(seq, "\t\tintersec table info\n");
+		seq_puts(seq, "\t\t-------------------\n");
+		seq_printf(seq, "\t\ttable mask: %lu\n", *intersec_table->mask);
+		seq_printf(seq, "\t\tniegh table priv: %p\n",
+			   intersec_table->neigh_table->priv);
+		prune_intersec_item_list_dump(seq, intersec_table);
+	}
+}
+
+static void prune_table_dump(struct seq_file *seq, struct prune *prune)
+{
+	struct prune_table *table;
+	unsigned int table_cnt = 0;
+
+	list_for_each_entry_rcu(table, &prune->table_list, list) {
+		seq_puts(seq, "\ttable info\n");
+		seq_puts(seq, "\t----------\n");
+		seq_printf(seq, "\ttable id: %p\n", table);
+		seq_printf(seq, "\ttable priv: %p\n", table->priv);
+		seq_printf(seq, "\ttable mask: %lu\n", *table->mask);
+		/* dump table items */
+		prune_table_items_dump(seq, table);
+		seq_puts(seq, "\n");
+		prune_intersec_tables_dump(seq, table);
+		seq_puts(seq, "\n\n");
+		table_cnt++;
+	}
+	seq_printf(seq, "Number of tables in prune object: %d\n", table_cnt);
+}
+
+static void prune_obj_dump(struct seq_file *seq, struct prune *prune)
+{
+	/* print prune object info */
+	seq_puts(seq, "prune\n");
+	seq_puts(seq, "-----\n");
+	seq_printf(seq, "prune priv: %p\n", prune->priv);
+	/* iterate over the prune tables */
+	prune_table_dump(seq, prune);
+	seq_puts(seq, "\n\n");
+}
+
+/* Iterate over the prune object_list and return the first valid object */
+static void *prune_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	struct prune *prune;
+	loff_t n = *pos;
+
+	rcu_read_lock();
+	if (!list_empty(&prune_object_list)) {
+		if (n-- == 0) {
+			prune = list_first_entry(&prune_object_list,
+						 typeof(*prune),
+						 list);
+			return prune;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Return the next object in the prune object_list.
+ */
+static void *prune_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct prune *prev_prune_obj = v;
+	struct prune *next_prune_obj = NULL;
+
+	++(*pos);
+
+	next_prune_obj = list_next_entry(prev_prune_obj, list);
+	if (&next_prune_obj->list == &prune_object_list)
+		return NULL;
+	else
+		return next_prune_obj;
+}
+
+/*
+ * frees needed resources initialized at start.
+ */
+static void prune_seq_stop(struct seq_file *seq, void *v)
+{
+	rcu_read_unlock(); /*unlock the rcu_lock taken at start */
+}
+
+/*
+ * Print the information for a prune object to the seq file.
+ */
+static int prune_seq_show(struct seq_file *seq, void *v)
+{
+	struct prune *prune = v;
+
+	prune_obj_dump(seq, prune);
+	return 0;
+}
+
+static const struct seq_operations prune_seq_ops = {
+	.start = prune_seq_start,
+	.next  = prune_seq_next,
+	.stop  = prune_seq_stop,
+	.show  = prune_seq_show,
+};
+
+static int prune_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &prune_seq_ops);
+}
+
+static const struct file_operations prune_fops = {
+	.owner	   = THIS_MODULE,
+	.open	    = prune_open,
+	.read	    = seq_read,
+	.llseek	  = seq_lseek,
+	.release = seq_release,
+};
+
 static unsigned int
 prune_intersec_table_entry_key_len(const struct prune_intersec_table_entry
 				   *intersec_entry)
@@ -135,7 +331,8 @@ static void prune_table_prune_vector_fini(struct prune_table_entry *entry)
 
 	list_for_each_safe(pos, tmp, &entry->table_prune_vector) {
 		vector_item = list_entry(pos, typeof(*vector_item), list);
-		list_del(&vector_item->list);
+		list_del_rcu(&vector_item->list);
+		synchronize_rcu();
 		kfree(vector_item);
 	}
 }
@@ -146,7 +343,7 @@ static int prune_table_prune_vector_init(struct prune *prune,
 	struct prune_vector_item *vector_item;
 	struct prune_table *table;
 
-	INIT_LIST_HEAD(&entry->table_prune_vector);
+	INIT_LIST_HEAD_RCU(&entry->table_prune_vector);
 
 	list_for_each_entry(table, &prune->table_list, list) {
 		vector_item = kzalloc(sizeof(*vector_item), GFP_KERNEL);
@@ -156,7 +353,7 @@ static int prune_table_prune_vector_init(struct prune *prune,
 		}
 		vector_item->pruned = true;
 		vector_item->table = table;
-		list_add_tail(&vector_item->list,
+		list_add_tail_rcu(&vector_item->list,
 				  &entry->table_prune_vector);
 	}
 	return 0;
@@ -192,7 +389,8 @@ prune_item_entry_create(struct prune *prune, unsigned long *key,
 static void prune_entry_destroy(struct prune_table_entry *entry)
 {
 	prune_table_prune_vector_fini(entry);
-	list_del(&entry->list);
+	list_del_rcu(&entry->list);
+	synchronize_rcu();
 	kfree(entry);
 }
 
@@ -533,7 +731,9 @@ prune_table_entry_create(struct prune *prune, struct prune_table *table,
 		prune_entry_destroy(entry);
 		return ERR_PTR(err);
 	}
-	list_add_tail(&entry->list, &table->entry_list);
+
+	list_add_tail_rcu(&entry->list, &table->entry_list);
+
 	entry->item.table = table;
 
 	return entry;
@@ -571,8 +771,8 @@ static struct prune_intersec_table_entry
 	bitmap_and(intersec_entry->ht_key, intersec_table_mask, item_key,
 		   mask_len);
 
-	INIT_LIST_HEAD(&intersec_entry->intersec_table_elem_list);
-	INIT_LIST_HEAD(&intersec_entry->neigh_table_elem_list);
+	INIT_LIST_HEAD_RCU(&intersec_entry->intersec_table_elem_list);
+	INIT_LIST_HEAD_RCU(&intersec_entry->neigh_table_elem_list);
 
 	return intersec_entry;
 err_key_alloc:
@@ -586,6 +786,7 @@ static int prune_intersec_item_add(struct prune_intersec_table *intersec_table,
 				   bool neigh)
 {
 	struct prune_intersec_table_list_elem *intersec_item = NULL;
+	unsigned long *mask;
 	unsigned int mask_len = entry->item.table->prune->mask_len;
 	struct prune_intersec_table_list_elem *neigh_item = NULL;
 	struct prune_intersec_table_entry *intersec_entry;
@@ -598,6 +799,7 @@ static int prune_intersec_item_add(struct prune_intersec_table *intersec_table,
 	if (!ht_key)
 		return -ENOMEM;
 
+	mask = intersec_table->mask;
 	bitmap_and(ht_key, intersec_table->mask, entry->item.key, mask_len);
 
 	rht_params = prune_intersec_table_entry_rht_params(intersec_table);
@@ -608,7 +810,7 @@ static int prune_intersec_item_add(struct prune_intersec_table *intersec_table,
 
 	if (!intersec_entry) {
 		/* create new intersec entry since there ins't already one */
-		intersec_entry = prune_intersec_entry_create(intersec_table->mask,
+		intersec_entry = prune_intersec_entry_create(mask,
 							     entry->item.key,
 							     intersec_table,
 							     mask_len);
@@ -625,16 +827,17 @@ static int prune_intersec_item_add(struct prune_intersec_table *intersec_table,
 			goto err_list_item_alloc;
 
 		intersec_item->entry = entry;
-		list_add_tail(&intersec_item->list,
-			      &intersec_entry->intersec_table_elem_list);
+		list_add_tail_rcu(&intersec_item->list,
+				  &intersec_entry->intersec_table_elem_list);
 	} else {
 		neigh_item = kzalloc(sizeof(*neigh_item), GFP_KERNEL);
 		if (!neigh_item)
 			goto err_nigh_list_item_alloc;
 
 		neigh_item->entry = entry;
-		list_add_tail(&neigh_item->list,
-			      &intersec_entry->neigh_table_elem_list);
+
+		list_add_tail_rcu(&neigh_item->list,
+				  &intersec_entry->neigh_table_elem_list);
 	}
 	if (!found) {
 		err = rhashtable_insert_fast(&intersec_table->entry_ht,
@@ -642,15 +845,19 @@ static int prune_intersec_item_add(struct prune_intersec_table *intersec_table,
 					     rht_params);
 		if (err)
 			goto err_rhashtable_insert;
+		list_add_tail_rcu(&intersec_entry->list,
+				  &intersec_table->items_list);
 	}
 	return 0;
 
 err_rhashtable_insert:
 	if (!neigh) {
-		list_del(&intersec_item->list);
+		list_del_rcu(&intersec_item->list);
+		synchronize_rcu();
 		kfree(intersec_item);
 	} else {
-		list_del(&neigh_item->list);
+		list_del_rcu(&neigh_item->list);
+		synchronize_rcu();
 		kfree(neigh_item);
 	}
 err_nigh_list_item_alloc:
@@ -694,7 +901,8 @@ prune_intersec_item_remove(struct prune_intersec_table *intersec_table,
 			intersec_item = list_entry(pos, typeof(*intersec_item),
 						   list);
 			if (intersec_item->entry == remove_entry) {
-				list_del(&intersec_item->list);
+				list_del_rcu(&intersec_item->list);
+				synchronize_rcu();
 				kfree(intersec_item);
 				break;
 			}
@@ -704,7 +912,8 @@ prune_intersec_item_remove(struct prune_intersec_table *intersec_table,
 				   &intersec_entry->neigh_table_elem_list) {
 			neigh_item = list_entry(pos, typeof(*neigh_item), list);
 			if (remove_entry == neigh_item->entry) {
-				list_del(&neigh_item->list);
+				list_del_rcu(&neigh_item->list);
+				synchronize_rcu();
 				kfree(neigh_item);
 				break;
 			}
@@ -715,6 +924,8 @@ prune_intersec_item_remove(struct prune_intersec_table *intersec_table,
 		rhashtable_remove_fast(&intersec_table->entry_ht,
 				       &intersec_entry->ht_node,
 				       rht_params);
+		list_del_rcu(&intersec_entry->list);
+		synchronize_rcu();
 		prune_intersec_entry_destroy(intersec_entry);
 	}
 	kfree(ht_key);
@@ -735,6 +946,8 @@ prune_intrsc_table_create(unsigned int mask_len)
 	if (!intersec_table->mask)
 		goto err_intersec_table_mask_alloc;
 
+	INIT_LIST_HEAD_RCU(&intersec_table->items_list);
+
 	return intersec_table;
 
 err_intersec_table_mask_alloc:
@@ -752,9 +965,10 @@ prune_intrsc_table_create(unsigned int mask_len)
  * @intersec_table: The intersection table which needs to be updated
  * @add_to_neighbor_items: True if items need to be add to neigh_table_elem_list
  */
-static void prune_intersec_table_items_update(struct prune_table *curr_table,
-					      struct prune_intersec_table *intersec_table,
-					      bool add_to_neighbor_items)
+static void
+prune_intersec_table_items_update(struct prune_table *curr_table,
+				  struct prune_intersec_table *intersec_table,
+				  bool add_to_neighbor_items)
 {
 	struct prune_table_entry *entry;
 
@@ -799,11 +1013,13 @@ static int prune_intersec_table_add(struct prune *prune,
 	/* Add new intersection table to the old table */
 	intersec_table1->neigh_table = new_table;
 	prune_intersec_table_items_update(curr_table, intersec_table1, false);
-	list_add(&intersec_table1->list, &curr_table->intersec_table_list);
+	list_add_tail_rcu(&intersec_table1->list,
+			  &curr_table->intersec_table_list);
 	/* Add new intersection table to new table */
 	intersec_table2->neigh_table = curr_table;
 	prune_intersec_table_items_update(curr_table, intersec_table2, true);
-	list_add(&intersec_table2->list, &new_table->intersec_table_list);
+	list_add_tail_rcu(&intersec_table2->list,
+			  &new_table->intersec_table_list);
 
 	return 0;
 
@@ -845,14 +1061,18 @@ static void prune_intersec_rht_free(void *ptr, void *arg)
 
 	list_for_each_safe(pos, tmp, &rht_node->intersec_table_elem_list) {
 		intersec_item = list_entry(pos, typeof(*intersec_item), list);
-		list_del(&intersec_item->list);
+		list_del_rcu(&intersec_item->list);
+		synchronize_rcu();
 		kfree(intersec_item);
 	}
 	list_for_each_safe(pos, tmp, &rht_node->neigh_table_elem_list) {
 		neigh_item = list_entry(pos, typeof(*neigh_item), list);
-		list_del(&neigh_item->list);
+		list_del_rcu(&neigh_item->list);
+		synchronize_rcu();
 		kfree(neigh_item);
 	}
+	list_del_rcu(&rht_node->list);
+	synchronize_rcu();
 	kfree(rht_node->ht_key);
 	kfree(rht_node);
 }
@@ -879,7 +1099,8 @@ static int prune_instersec_table_remove(unsigned int mask_len,
 						 list);
 		if (bitmap_equal(curr_mask, curr_intersec_table->mask,
 				 mask_len)) {
-			list_del(&curr_intersec_table->list);
+			list_del_rcu(&curr_intersec_table->list);
+			synchronize_rcu();
 			entry_ht = &curr_intersec_table->entry_ht;
 			rhashtable_free_and_destroy(entry_ht,
 						    prune_intersec_rht_free,
@@ -996,7 +1217,8 @@ static void prune_table_item_vector_remove(struct prune_table *table,
 			vector_item = list_entry(pos, typeof(*vector_item),
 						 list);
 			if (vector_item->table == del_table) {
-				list_del(&vector_item->list);
+				list_del_rcu(&vector_item->list);
+				synchronize_rcu();
 				kfree(vector_item);
 				break;
 			}
@@ -1018,7 +1240,7 @@ static int prune_table_item_vector_add(struct prune_table *table,
 		}
 		vector_item->pruned = true;
 		vector_item->table = new_table;
-		list_add_tail(&vector_item->list,
+		list_add_tail_rcu(&vector_item->list,
 				  &entry->table_prune_vector);
 	}
 	return 0;
@@ -1098,10 +1320,11 @@ struct prune *prune_create(unsigned int mask_len, const struct prune_ops *ops,
 
 	prune->priv = priv;
 	prune->mask_len = mask_len;
-	INIT_LIST_HEAD(&prune->table_list);
+	INIT_LIST_HEAD_RCU(&prune->table_list);
 	prune->ops = ops;
 	prune_intersec_tables_ht_params_init(prune, mask_len);
 
+	list_add_tail_rcu(&prune->list, &prune_object_list);
 	return prune;
 }
 EXPORT_SYMBOL(prune_create);
@@ -1114,6 +1337,8 @@ void prune_destroy(struct prune *prune)
 {
 	WARN_ON(!list_empty(&prune->table_list));
 
+	list_del_rcu(&prune->list);
+	synchronize_rcu();
 	kfree(prune);
 }
 EXPORT_SYMBOL(prune_destroy);
@@ -1130,8 +1355,6 @@ EXPORT_SYMBOL(prune_destroy);
  * otherwise it returns negative number to indicate an error.
  *
  * Note: It's the user responsibility to care for synchronization.
- * This function may sleep so you must not call it from interrupt
- * context or with spin locks held.
  */
 
 struct prune_table *prune_table_create(struct prune *prune, unsigned long *mask,
@@ -1155,8 +1378,9 @@ struct prune_table *prune_table_create(struct prune *prune, unsigned long *mask,
 	bitmap_copy(table->mask, mask, prune->mask_len);
 	table->priv = priv;
 	table->prune = prune;
-	INIT_LIST_HEAD(&table->entry_list);
-	INIT_LIST_HEAD(&table->intersec_table_list);
+	INIT_LIST_HEAD_RCU(&table->entry_list);
+	INIT_LIST_HEAD_RCU(&table->intersec_table_list);
+
 
 	/* Enlarge the prune vector of all item with the new table */
 	err = prune_item_prune_table_add(prune, table);
@@ -1167,7 +1391,7 @@ struct prune_table *prune_table_create(struct prune *prune, unsigned long *mask,
 	if (err)
 		goto err_table_build;
 
-	list_add_tail(&table->list, &prune->table_list);
+	list_add_tail_rcu(&table->list, &prune->table_list);
 
 	return table;
 
@@ -1189,8 +1413,6 @@ EXPORT_SYMBOL(prune_table_create);
  * Returns 0 in case of success, negative number to indicate an error.
  *
  * Note: It's the user responsibility to care for synchronization.
- * This function may sleep so you must not call it from interrupt
- * context or with spin locks held.
  */
 int prune_table_destroy(struct prune_table *table)
 {
@@ -1208,7 +1430,8 @@ int prune_table_destroy(struct prune_table *table)
 
 	prune_item_prune_table_remove(prune, table);
 
-	list_del(&table->list);
+	list_del_rcu(&table->list);
+	synchronize_rcu();
 	kfree(table->mask);
 	kfree(table);
 
@@ -1332,6 +1555,42 @@ struct list_head *prune_item_prune_vector(struct prune_item *item)
 }
 EXPORT_SYMBOL(prune_item_prune_vector);
 
+static struct dentry *prune_debugfs_create(void)
+{
+	dentry = debugfs_create_file("prune_debug", 0644, NULL, NULL,
+				     &prune_fops);
+	if (!dentry)
+		pr_warn("Failed to create the debugfs prune file\n");
+
+	return dentry;
+}
+
+static void prune_debugfs_destroy(struct dentry *dentry)
+{
+	debugfs_remove(dentry);
+}
+
+int prune_init(void)
+{
+	INIT_LIST_HEAD_RCU(&prune_object_list);
+#ifdef CONFIG_DEBUG_FS
+	dentry = prune_debugfs_create();
+	if (!dentry)
+		return -EINVAL;
+
+#endif
+	return 0;
+}
+EXPORT_SYMBOL(prune_init);
+
+void prune_fini(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	prune_debugfs_destroy(dentry);
+#endif
+}
+EXPORT_SYMBOL(prune_fini);
+
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Tal Bar <talb@mellanox.com>");
 MODULE_DESCRIPTION("Prune lookup table manager");
diff --git a/lib/test_prune.c b/lib/test_prune.c
index 7e2d81e..bbad14b 100644
--- a/lib/test_prune.c
+++ b/lib/test_prune.c
@@ -1200,11 +1200,13 @@ static int test_prune(void)
 
 static int __init test_prune_init(void)
 {
-		return test_prune();
+	prune_init();
+	return test_prune();
 }
 
 static void __exit test_prune_exit(void)
 {
+	 prune_fini();
 }
 
 module_init(test_prune_init);
