[SSI] openssi/kernel/cluster/ssi/ipc unixnm.c,1.16,1.17

Roger Tsang <[email protected]> Sun, 08 Aug 2010 02:27:12 +0000
Newsgroups gmane.linux.cluster.ssic.cvs
Message-ID <[email protected]>
Update of /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/ipc
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv3340/cluster/ssi/ipc

Modified Files:
      Tag: OPENSSI-FC
	unixnm.c 
Log Message:
IPC (UNIX domain sockets):
- Implement lockless unixnm_svr_table list traversal. Reduce connect(), sendmsg() contention with bind(), connect(), sendmsg().
- ssi_unix_deregister() do O(1) lookup. Remove release() contention with bind() and various paths with unix_table_lock.
- unixnm_put() do O(1) lookup. Reduce release() contention with bind(), connect(), sendmsg().
- Allocate unixnm_svr_entry and unixnm_cache_entry structures from the Linux slab cache.

 cluster/ssi/ipc/unixnm.c         |  350 ++++++++++++++++++-------------
 include/cluster/ssi/unix.h       |   27 --
 include/net/af_unix.h            |    5 
 net/unix/af_unix.c               |    1 


Index: unixnm.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/ipc/unixnm.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- unixnm.c	27 Oct 2009 03:18:29 -0000	1.16
+++ unixnm.c	8 Aug 2010 02:27:10 -0000	1.17
@@ -63,9 +63,12 @@
 
 	clusternode_t 		socknode;
 	unsigned long		sockino;
+	atomic_t		refcnt;
+	struct rcu_head		rhead;
 };
 static struct list_head unixnm_svr_table[UNIX_HASH_SIZE];
-static __cacheline_aligned_in_smp DEFINE_RWLOCK(unixnm_svr_lock);
+static __cacheline_aligned_in_smp DEFINE_SPINLOCK(unixnm_svr_table_lock);
+static kmem_cache_t *unixnm_svr_entry_cachep;
 
 /* rebuild cache */
 struct unixnm_cache_entry {
@@ -74,9 +77,10 @@
 	struct inode 		*name_inode;
 	struct unix_address 	*name_addr;
 };
-static struct list_head unixnm_cache_list = LIST_HEAD_INIT(unixnm_cache_list);
-static int unixnm_cache_size = 0;
+static LIST_HEAD(unixnm_cache_list);
 static __cacheline_aligned_in_smp DEFINE_SPINLOCK(unixnm_cache_listlock);
+static int unixnm_cache_size = 0;
+static kmem_cache_t *unixnm_cli_entry_cachep;
 
 struct unixnm_rebuild_entry {
 	int hash;
@@ -103,6 +107,7 @@
 cluster_svc_t cluster_unixnm_svc;
 clms_key_svc_t unixnm_key_service;
 
+void __unixnmsvr_put(struct unixnm_svr_entry *);
 
 /*
  * Initialization
@@ -121,11 +126,21 @@
 	int ctr;
 	for (ctr = 0; ctr < UNIX_HASH_SIZE; ++ctr)
 		INIT_LIST_HEAD(&unixnm_svr_table[ctr]);
+
+	unixnm_svr_entry_cachep = kmem_cache_create("unixnm_svr_entry",
+				sizeof(struct unixnm_svr_entry), 0,
+				SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_PANIC,
+				NULL, NULL);
 }
 
 void
 unixnm_init(void)
 {
+	unixnm_cli_entry_cachep = kmem_cache_create("unixnm_cli_entry",
+				sizeof(struct unixnm_cache_entry), 0,
+				SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_PANIC,
+				NULL, NULL);
+
 	unixnm_svr = clms_get_key_server_node(unixnm_key_service, 1);
 
 	if (this_node == unixnm_svr) {
@@ -168,30 +183,46 @@
 	int data_len)
 {
 	struct unixnm_rebuild_entry *rbldent;
+	struct unixnm_svr_entry *svrent;
 	int ctr;
 
 	rbldent = (struct unixnm_rebuild_entry *) buffer;
-	for (ctr = 0; ctr < data_len / sizeof(*rbldent); ++ctr) {
-		struct unixnm_svr_entry *svrent =
-			kzmalloc_nofail(sizeof(*svrent));
 
+#ifdef SSI_SKIP
+	/* No need to hold these mutexes because
+	 * unixnmsvr_server_ready() is not yet called.
+	 * See unixnmsvr_failover().
+	 */
+	down(&unixnm_svr_name_lock);
+	down(&unixnm_svr_ino_lock);
+#endif
+
+	for (ctr = 0; ctr < data_len / sizeof(*rbldent); ++ctr) {
+		svrent = kmem_cache_alloc(unixnm_svr_entry_cachep,
+						GFP_KERNEL|__GFP_NOFAIL);
 		INIT_LIST_HEAD(&svrent->list);
 		if (rbldent->namelen) {
-			svrent->name = kmalloc_nofail(
-						sizeof(rbldent->name));
+			svrent->name_ssidev = 0;
+			svrent->name_ino = 0;
+			svrent->type = 0;
+			svrent->name = kmalloc_nofail(sizeof(rbldent->name));
 			memcpy(svrent->name, &rbldent->name, rbldent->namelen);
 			svrent->namelen = rbldent->namelen;
 		} else {
 			svrent->name_ssidev = rbldent->name_ssidev;
 			svrent->name_ino = rbldent->name_ino;
 			svrent->type = rbldent->type;
+			svrent->name = NULL;
+			svrent->namelen = 0;
 		}
-		svrent->sockino = rbldent->sockino;
 		svrent->socknode = node;
+		svrent->sockino = rbldent->sockino;
+		atomic_set(&svrent->refcnt, 1);
+		INIT_RCU_HEAD(&svrent->rhead);
 
-		write_lock(&unixnm_svr_lock);
-		list_add(&svrent->list, &unixnm_svr_table[rbldent->hash]);
-		write_unlock(&unixnm_svr_lock);
+		spin_lock(&unixnm_svr_table_lock);
+		list_add_rcu(&svrent->list, &unixnm_svr_table[rbldent->hash]);
+		spin_unlock(&unixnm_svr_table_lock);
 		++rbldent;
 	}
 }
@@ -207,12 +238,14 @@
 	struct unixnm_cache_entry *cchent;
 
 	down_write(&unixnm_cache_rebuildlock);
+
 	*data_len = unixnm_cache_size * sizeof(*entry);
-	error = -E2BIG;
-	if (*data_len > buffer_len)
+	if (*data_len > buffer_len) {
+		error = -E2BIG;
 		goto out;
-
+	}
 	entry = (struct unixnm_rebuild_entry *) buffer;
+
 	list_for_each_entry(cchent, &unixnm_cache_list, list) {
 		struct inode *inode = cchent->inode;
 		struct sock *sk = SOCKET_I(inode)->sk;
@@ -221,10 +254,10 @@
 		struct unix_address *name_addr = cchent->name_addr;
 
 		memset(entry, 0, sizeof(*entry));
+
 		if (name_inode) {
 			struct dentry *dentry = unix_sk(sk)->dentry;
-			if (dentry && dentry->d_inode != name_inode)
-				BUG();
+			BUG_ON(dentry && dentry->d_inode != name_inode);
 
 			entry->hash = unixnmsvr_hashino(name_inode->i_ino);
 			entry->name_ssidev = ssidev_get_i_ssidev(name_inode);
@@ -232,8 +265,7 @@
 			entry->type = sk->sk_type;
 		} else {
 			struct unix_address *addr = unix_sk(sk)->addr;
-			if (addr && addr != name_addr)
-				BUG();
+			BUG_ON(addr && addr != name_addr);
 
 			entry->hash = name_addr->hash;
 			memcpy(&entry->name, name_addr->name, name_addr->len);
@@ -258,20 +290,20 @@
 static inline void
 unixnmsvr_nodedown(clusternode_t node)
 {
+	struct unixnm_svr_entry *entry;
 	int hash;
 
-	write_lock(&unixnm_svr_lock);
 	for (hash = 0; hash < UNIX_HASH_SIZE; ++hash) {
-		struct unixnm_svr_entry *entry, *next;
-		list_for_each_entry_safe(entry, next, &unixnm_svr_table[hash], list) {
-			if (entry->socknode == node) {
-				list_del(&entry->list);
-				kfree(entry->name);
-				kfree(entry);
+		rcu_read_lock();
+		list_for_each_entry_rcu(entry, &unixnm_svr_table[hash], list) {
+			if (entry->socknode == node &&
+			    atomic_test_and_add(1, &entry->refcnt)) {
+				__unixnmsvr_put(entry);
+				__unixnmsvr_put(entry); /* final */
 			}
 		}
+		rcu_read_unlock();
 	}
-	write_unlock(&unixnm_svr_lock);
 }
 
 int
@@ -295,22 +327,47 @@
  * Server routines
  */
 
-static inline struct unixnm_svr_entry *
+void
+unixnm_svr_dealloc(struct rcu_head *rhead)
+{
+	struct unixnm_svr_entry *entry =
+			container_of(rhead, struct unixnm_svr_entry, rhead);
+	kfree(entry->name);
+	kmem_cache_free(unixnm_svr_entry_cachep, entry);
+}
+
+void
+__unixnmsvr_put(struct unixnm_svr_entry *entry)
+{
+	if (!atomic_dec_and_lock(&entry->refcnt, &unixnm_svr_table_lock))
+		return;
+	list_del_rcu(&entry->list);
+	spin_unlock(&unixnm_svr_table_lock);
+	call_rcu(&entry->rhead, unixnm_svr_dealloc);
+}
+
+
+static struct unixnm_svr_entry *
 unixnmsvr_getent_byinode(
 	dev_t name_ssidev,
 	unsigned long name_ino)
 {
 	struct unixnm_svr_entry *entry;
 
-	list_for_each_entry(entry,
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry,
 			&unixnm_svr_table[unixnmsvr_hashino(name_ino)], list) {
 		if (entry->name)
 			continue;
 		if (entry->name_ino == name_ino &&
-				entry->name_ssidev == name_ssidev)
-			return entry;
+		    entry->name_ssidev == name_ssidev &&
+		    atomic_test_and_add(1, &entry->refcnt))
+			goto found;
 	}
-	return NULL;
+	entry = NULL;
+found:
+	rcu_read_unlock();
+	return entry;
 }
 
 int
@@ -324,72 +381,80 @@
 	u_long sockino)
 {
 	struct unixnm_svr_entry *entry, *newentry;
+static DECLARE_MUTEX(unixnm_svr_ino_lock);
 
-	*rval = -EREMOTE;
-	if (this_node != unixnm_svr)
+	if (this_node != unixnm_svr) {
+		*rval = -EREMOTE;
 		return 0;
+	}
 
-	*rval = -EUNM_BUG;
-	if (socknode > NSC_MAX_NODE_VALUE || socknode <= 0) {
+	if (unlikely(socknode > NSC_MAX_NODE_VALUE || socknode <= 0)) {
 		printk(KERN_ERR "unixnmsvr_get_byinode: "
 				"bogus node number: %u\n", socknode);
+		*rval = -EUNM_BUG;
 		return 0;
 	}
 
-	read_lock(&unixnm_svr_lock);
-	entry = unixnmsvr_getent_byinode(name_ssidev, name_ino);
-	read_unlock(&unixnm_svr_lock);
-	if (entry)
-		goto entry_exists_out;
-
-	*rval = -ENOMEM;
-	newentry = kzmalloc(sizeof(*newentry), GFP_USER);
-	if (!newentry)
+	newentry = kmem_cache_alloc(unixnm_svr_entry_cachep, GFP_KERNEL);
+	if (!newentry) {
+		*rval = -ENOMEM;
 		return 0;
+	}
 
 	INIT_LIST_HEAD(&newentry->list);
 	newentry->name_ssidev = name_ssidev;
 	newentry->name_ino = name_ino;
 	newentry->type = type;
+	newentry->name = NULL;
+	newentry->namelen = 0;
 	newentry->socknode = socknode;
 	newentry->sockino = sockino;
+	atomic_set(&newentry->refcnt, 1);
+	INIT_RCU_HEAD(&newentry->rhead);
 
-	write_lock(&unixnm_svr_lock);
+	down(&unixnm_svr_ino_lock);
 	entry = unixnmsvr_getent_byinode(name_ssidev, name_ino);
-	if (!entry)
-		list_add(&newentry->list,
+	if (!entry) {
+		spin_lock(&unixnm_svr_table_lock);
+		list_add_rcu(&newentry->list,
 			 &unixnm_svr_table[unixnmsvr_hashino(name_ino)]);
-	write_unlock(&unixnm_svr_lock);
-	if (entry) {
-		kfree(newentry);
-		goto entry_exists_out;
+		spin_unlock(&unixnm_svr_table_lock);
+		up(&unixnm_svr_ino_lock);
+		*rval = 0;
+		return 0;
 	}
+	up(&unixnm_svr_ino_lock);
 
-	*rval = 0;
-	return 0;
+	__unixnmsvr_put(entry);
+	kmem_cache_free(unixnm_svr_entry_cachep, newentry);
 
-entry_exists_out:
 	*rval = -EADDRINUSE;
 	printk(KERN_WARNING "unixnmsvr_get_byinode: filesystem for ssidev %d "
 		"doesn't correctly support exclusive create\n", name_ssidev);
 	return 0;
 }
 
-static inline struct unixnm_svr_entry *
+static struct unixnm_svr_entry *
 unixnmsvr_getent_byname(
 	struct sockaddr_un *sunaddr,
 	int namelen,
 	int hash)
 {
 	struct unixnm_svr_entry *entry;
-	list_for_each_entry(entry, &unixnm_svr_table[hash], list) {
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry, &unixnm_svr_table[hash], list) {
 		if (!entry->name)
 			continue;
 		if (entry->namelen == namelen &&
-		   		memcmp(entry->name, sunaddr, namelen) == 0)
-			return entry;
+		    memcmp(entry->name, sunaddr, namelen) == 0 &&
+		    atomic_test_and_add(1, &entry->refcnt))
+			goto found;
 	}
-	return NULL;
+	entry = NULL;
+found:
+	rcu_read_unlock();
+	return entry;
 }
 
 int
@@ -402,77 +467,80 @@
 {
 	struct sockaddr_un *sunaddr = (struct sockaddr_un *) name;
 	struct unixnm_svr_entry *entry, *newentry;
+static DECLARE_MUTEX(unixnm_svr_name_lock);
 
 	*rval = -EREMOTE;
 	if (this_node != unixnm_svr)
 		return 0;
 
 	*rval = -EUNM_BUG;
-	if (!name) {
+	if (unlikely(!name)) {
 		printk(KERN_ERR "unixnmsvr_get_byname: "
 				"NULL name pointer\n");
 		return 0;
 	}
-	if (namelen < sizeof(sunaddr->sun_family)) {
+	if (unlikely(namelen < sizeof(sunaddr->sun_family))) {
 		printk(KERN_ERR "unixnmsvr_get_byname: "
 				"namelen too small: %d\n", namelen);
 		return 0;
 	}
-	if (namelen > sizeof(*sunaddr)) {
+	if (unlikely(namelen > sizeof(*sunaddr))) {
 		printk(KERN_ERR "unixnmsvr_get_byname: "
 				"namelen too big: %d\n", namelen);
 		return 0;
 	}
-	if (hash > UNIX_HASH_SIZE - 1) {
+	if (unlikely(hash > UNIX_HASH_SIZE - 1)) {
 		printk(KERN_ERR "unixnmsvr_get_byname: "
 				"hash too big: %d\n", hash);
 		return 0;
 	}
-	if (socknode > NSC_MAX_NODE_VALUE || socknode <= 0) {
+	if (unlikely(socknode > NSC_MAX_NODE_VALUE || socknode <= 0)) {
 		printk(KERN_ERR "unixnmsvr_get_byname: "
 				"bogus node number: %u\n", socknode);
 		return 0;
 	}
 
-	read_lock(&unixnm_svr_lock);
-	entry = unixnmsvr_getent_byname(sunaddr, namelen, hash);
-	read_unlock(&unixnm_svr_lock);
-	if (entry)
-		goto entry_exists_out;
-
 	*rval = -ENOMEM;
-	newentry = kzmalloc(sizeof(*newentry), GFP_USER);
+
+	newentry = kmem_cache_alloc(unixnm_svr_entry_cachep, GFP_KERNEL);
 	if (!newentry)
 		return 0;
 
 	INIT_LIST_HEAD(&newentry->list);
-	newentry->name = kmalloc(namelen, GFP_USER);
+	newentry->name_ssidev = 0;
+	newentry->name_ino = 0;
+	newentry->type = 0;
+
+	newentry->name = kmalloc(namelen, GFP_KERNEL);
 	if (!newentry->name) {
-		kfree(newentry);
+		kmem_cache_free(unixnm_svr_entry_cachep, newentry);
 		return 0;
 	}
-
 	memcpy(newentry->name, sunaddr, namelen);
+
 	newentry->namelen = namelen;
 	newentry->socknode = socknode;
 	newentry->sockino = sockino;
+	atomic_set(&newentry->refcnt, 1);
+	INIT_RCU_HEAD(&newentry->rhead);
 
-	write_lock(&unixnm_svr_lock);
+	down(&unixnm_svr_name_lock);
 	entry = unixnmsvr_getent_byname(sunaddr, namelen, hash);
-	if (!entry)
-		list_add(&newentry->list,
+	if (!entry) {
+		spin_lock(&unixnm_svr_table_lock);
+		list_add_rcu(&newentry->list,
 				&unixnm_svr_table[hash]);
-	write_unlock(&unixnm_svr_lock);
-	if (entry) {
-		kfree(newentry->name);
-		kfree(newentry);
-		goto entry_exists_out;
+		spin_unlock(&unixnm_svr_table_lock);
+		up(&unixnm_svr_name_lock);
+		*rval = 0;
+		return 0;
 	}
+	up(&unixnm_svr_name_lock);
 
-	*rval = 0;
-	return 0;
+	__unixnmsvr_put(entry);
+	kfree(newentry->name);
+	kmem_cache_free(unixnm_svr_entry_cachep, newentry);
 
-entry_exists_out:
 	*rval = -EADDRINUSE;
 	return 0;
 }
@@ -494,34 +562,34 @@
 		return 0;
 
 	*rval = -EUNM_BUG;
-	if (!socknode) {
+	if (unlikely(!socknode)) {
 		printk(KERN_ERR "unixnmsvr_find_byinode: "
 				"NULL socknode pointer\n");
 		return 0;
 	}
-	if (!sockino) {
+	if (unlikely(!sockino)) {
 		printk(KERN_ERR "unixnmsvr_find_byinode: "
 				"NULL sockino pointer\n");
 		return 0;
 	}
 
-	read_lock(&unixnm_svr_lock);
 	entry = unixnmsvr_getent_byinode(name_ssidev, name_ino);
-
-	*rval = -ECONNREFUSED;
-	if (!entry)
+	if (!entry) {
+		*rval = -ECONNREFUSED;
 		goto out;
-
-	*rval = -EPROTOTYPE;
-	if (entry->type != type)
+	}
+	if (entry->type != type) {
+		*rval = -EPROTOTYPE;
 		goto out;
+	}
 
 	*rval = 0;
 	*socknode = entry->socknode;
 	*sockino = entry->sockino;
 
 out:
-	read_unlock(&unixnm_svr_lock);
+	if (entry)
+		__unixnmsvr_put(entry);
 	return 0;
 }
 
@@ -541,41 +609,40 @@
 		return 0;
 
 	*rval = -EUNM_BUG;
-	if (!socknode) {
+	if (unlikely(!socknode)) {
 		printk(KERN_ERR "unixnmsvr_find_byname: "
 				"NULL socknode pointer\n");
 		return 0;
 	}
-	if (!sockino) {
+	if (unlikely(!sockino)) {
 		printk(KERN_ERR "unixnmsvr_find_byname: "
 				"NULL sockino pointer\n");
 		return 0;
 	}
-	if (!name) {
+	if (unlikely(!name)) {
 		printk(KERN_ERR "unixnmsvr_find_byname: "
 				"NULL name pointer\n");
 		return 0;
 	}
-	if (namelen > sizeof(*sunaddr)) {
+	if (unlikely(namelen > sizeof(*sunaddr))) {
 		printk(KERN_ERR "unixnmsvr_find_byname: "
 				"namelen too big: %d\n", hash);
 		return 0;
 	}
-	if (hash > UNIX_HASH_SIZE - 1) {
+	if (unlikely(hash > UNIX_HASH_SIZE - 1)) {
 		printk(KERN_ERR "unixnmsvr_find_byname: "
 				"hash too big: %d\n", hash);
 		return 0;
 	}
 
-	*rval = -ECONNREFUSED;
-	read_lock(&unixnm_svr_lock);
 	entry = unixnmsvr_getent_byname(sunaddr, namelen, hash);
 	if (entry) {
-		*rval = 0;
 		*socknode = entry->socknode;
 		*sockino = entry->sockino;
-	}
-	read_unlock(&unixnm_svr_lock);
+		__unixnmsvr_put(entry);
+		*rval = 0;
+	} else
+		*rval = -ECONNREFUSED;
 
 	return 0;
 }
@@ -588,46 +655,43 @@
 	clusternode_t socknode,
 	u_long sockino)
 {
-	struct unixnm_svr_entry *tmp, *entry = NULL;
+	struct unixnm_svr_entry *entry;
 
 	*rval = -EREMOTE;
 	if (this_node != unixnm_svr)
 		return 0;
 
 	*rval = -EUNM_BUG;
-	if (hash < 0 || hash > (UNIX_HASH_SIZE-1)) {
+	if (unlikely(hash < 0 || hash > (UNIX_HASH_SIZE-1))) {
 		printk(KERN_ERR "unixnmsvr_put: "
 				"bogus hash value: %d\n", hash);
 		return 0;
 	}
-	if (socknode > NSC_MAX_NODE_VALUE || socknode <= 0) {
+	if (unlikely(socknode > NSC_MAX_NODE_VALUE || socknode <= 0)) {
 		printk(KERN_ERR "unixnmsvr_put: "
 				"bogus node number: %u\n", socknode);
 		return 0;
 	}
 
-	write_lock(&unixnm_svr_lock);
-	list_for_each_entry(tmp, &unixnm_svr_table[hash], list) {
-		if (tmp->socknode == socknode &&
-				tmp->sockino == sockino) {
-			entry = tmp;
-			list_del(&entry->list);
-			break;
-		}
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry, &unixnm_svr_table[hash], list) {
+		if (entry->socknode == socknode &&
+		    entry->sockino == sockino &&
+		    atomic_test_and_add(1, &entry->refcnt))
+			goto found;
 	}
-	write_unlock(&unixnm_svr_lock);
-
-	*rval = -EUNM_BUG;
-	if (!entry) {
+	entry = NULL;
+found:
+	rcu_read_unlock();
+	if (entry) {
+		__unixnmsvr_put(entry);
+		__unixnmsvr_put(entry); /* final */
+		*rval = 0;
+	} else {
 		printk(KERN_ERR "unixnmsvr_put: "
 				"entry not found for node %u and ino %ld\n",
 				socknode, sockino);
-		return 0;
 	}
-
-	*rval = 0;
-	kfree(entry->name);
-	kfree(entry);
 	return 0;
 }
 
@@ -715,7 +779,7 @@
 	struct unixnm_cache_entry *entry;
 	int error, ret;
 
-	entry = kmalloc(sizeof(*entry), GFP_USER);
+	entry = kmem_cache_alloc(unixnm_cli_entry_cachep, GFP_KERNEL);
 	if (!entry)
 		return -ENOMEM;
 
@@ -738,16 +802,20 @@
 	entry->inode = inode;
 	entry->name_inode = name_inode;
 	entry->name_addr = NULL;
+
 	spin_lock(&unixnm_cache_listlock);
 	++unixnm_cache_size;
 	list_add(&entry->list, &unixnm_cache_list);
 	spin_unlock(&unixnm_cache_listlock);
+
+	unix_sk(sock->sk)->ssi_unixnm_entry = (void *)entry;
 	entry = NULL;
 
 unlock_out:
 	up_read(&unixnm_cache_rebuildlock);
 rpc_out:
-	kfree(entry);
+	if (entry)
+		kmem_cache_free(unixnm_cli_entry_cachep, entry);
 	return error;
 }
 
@@ -764,7 +832,7 @@
 	struct unixnm_cache_entry *entry;
 	int error, ret;
 
-	entry = kmalloc(sizeof(*entry), GFP_USER);
+	entry = kmem_cache_alloc(unixnm_cli_entry_cachep, GFP_KERNEL);
 	if (!entry)
 		return -ENOMEM;
 
@@ -791,12 +859,15 @@
 	++unixnm_cache_size;
 	list_add(&entry->list, &unixnm_cache_list);
 	spin_unlock(&unixnm_cache_listlock);
+
+	unix_sk(sock->sk)->ssi_unixnm_entry = (void *)entry;
 	entry = NULL;
 
 unlock_out:
 	up_read(&unixnm_cache_rebuildlock);
 rpc_out:
-	kfree(entry);
+	if (entry)
+		kmem_cache_free(unixnm_cli_entry_cachep, entry);
 	return error;
 }
 
@@ -874,7 +945,7 @@
 	struct unix_sock *options = unix_sk(sock->sk);
 	int hash;
 
-	struct unixnm_cache_entry *tmp, *entry = NULL;
+	struct unixnm_cache_entry *entry;
 	int error, ret;
 
 	hash = options->dentry ?
@@ -882,6 +953,10 @@
 		options->addr->hash;
 	SSI_ASSERT(hash >= 0 && hash < UNIX_HASH_SIZE);
 
+	entry = (struct unixnm_cache_entry *) options->ssi_unixnm_entry;
+	options->ssi_unixnm_entry = NULL;
+	SSI_ASSERT(entry);
+
 rpc_repeat:
 	down_read(&unixnm_cache_rebuildlock);
 	if (this_node == unixnm_svr)
@@ -899,26 +974,17 @@
 	}
 
 	spin_lock(&unixnm_cache_listlock);
-	list_for_each_entry(tmp, &unixnm_cache_list, list) {
-		if (tmp->inode == inode) {
-			entry = tmp;
-			break;
-		}
-	}
-	if (!entry) {
-		printk(KERN_EMERG "unixnm_put: entry missing from cache\n");
-		BUG();
-	}
 	--unixnm_cache_size;
 	list_del(&entry->list);
 	spin_unlock(&unixnm_cache_listlock);
 
 	up_read(&unixnm_cache_rebuildlock);
-	kfree(entry);
+	kmem_cache_free(unixnm_cli_entry_cachep, entry);
 	return;
 
 rpc_out:
 	BUG();
+	for (;;) ; /* no return */
 }
 
 


------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev