[SSI] openssi/kernel/ipc msg.c, 1.16, 1.17 sem.c, 1.32, 1.33 shm.c, 1.27, 1.28 util.c, 1.10, 1.11 util.h, 1.12, 1.13

Roger Tsang <[email protected]> Fri, 05 Mar 2010 06:30:23 +0000
Newsgroups gmane.linux.cluster.ssic.cvs
Message-ID <[email protected]>
Update of /cvsroot/ssic-linux/openssi/kernel/ipc
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv9483/kernel/ipc

Modified Files:
      Tag: OPENSSI-FC
	msg.c sem.c shm.c util.c util.h 
Log Message:
IPC:
- Fix partially initialized shmid_kernel_svr.shm_perm structure.
- Fix ipc/sem.c:exit_sem() GCC warning: ISO C90 forbids mixed declarations and
  code.
- Split ssi_shm_setup() into separate functions ssi_shm_setup_client/new() to
  reduce stack usage in some paths.

IPC (#ifdef IPC_SHM_RACE_FIX):
- Fix shm_svr_rmid() called without spinlock for the ID.
- Fix race deferencing invalid struct shmid_kernel, shmid_kernel_svr.
- Enable lockfree shmid_kernel_svr IPC id lookup. Use ipc_rcu_alloc and IPC
  reference counting.
- Reduce contention. Avoid the ipc_ids mutex. Use per IPC id spinlock.
- Fix cli_ipcname_findid() race with cli_ipcname_getid() could overwrite
  existing IPC segment.
- Fix non-critical section under shm_ids.sem lock in shm_create_cli_entry().
- Prevent re-acquire shm_ids.sem in shm_destroy() path. ripc_shm_rmid() no
  longer returns with shm_ids.sem unlocked.
- Remove contention in shmem_svr_lookup(); no longer acquire shm_ids_svr.sem.
- Fix do_shmat() possible hang calling dput() while holding spinlock.
- Fix cfs_shm_node_mnts[] race.
- Fix inode leak in ssi_shm_setup() error path when do_shm_register() fails.

IPC (#ifdef IPC_SHM_LOCK_DEST_FIX):
- Fix [ ssic-linux-Bug 2838006 ] Corrupt SHM_LOCK_DEST flag.
- Refactor ipc_shm_nodedown() for SHM_LOCK_DEST flag. Use SHM_LOCK_DEST flag.
- Fix ripc_drop_locks() error path dereferencing NULL pointer in
  ipc_drop_locks().

IPC (#ifdef CFS_IPCSHM_DENTRY):
- ssi_shm_setup_client() use d_instantiate_unique() to prevent duplicate
  entries.

 cluster/ssi/cfs/cfs_ipcshm.c     |  422 ++++++++++++++++++-----------
 cluster/ssi/cfs/cfsproc.c        |    6 
 cluster/ssi/ipc/ipcshm_svr.c     |  280 +++++++++++--------
 cluster/ssi/ipc/namesvr_func.c   |   12 
 cluster/ssi/vproc/reopen.c       |   30 +-
 include/cluster/ssi/cfs/cfs_fs.h |   16 +
 include/cluster/ssi/ipc/shm.h    |   13 
 include/linux/shm.h              |    7 
 ipc/msg.c                        |    6 
 ipc/sem.c                        |   17 -
 ipc/shm.c                        |  450 ++++++++++++++++++++-----------
 ipc/util.c                       |   18 -
 ipc/util.h                       |    5 
 mm/shmem.c                       |    9 
 14 files changed, 845 insertions(+), 446 deletions(-)


Index: util.h
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/util.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- util.h	17 Jan 2010 11:57:05 -0000	1.12
+++ util.h	5 Mar 2010 06:30:21 -0000	1.13
@@ -34,11 +34,6 @@
 	int max_id;
 	unsigned short seq;
 	unsigned short seq_max;
-#ifdef CONFIG_SSI
-#ifdef IPC_SHM_RACE_FIX
-	int lock_dest_id; /* id of entry locked for destroy aka. SHM_LOCK_DEST */
-#endif
-#endif
 	struct semaphore sem;	
 	struct ipc_id_ary nullentry;
 	struct ipc_id_ary* entries;

Index: sem.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/sem.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- sem.c	2 Feb 2010 05:19:30 -0000	1.32
+++ sem.c	5 Mar 2010 06:30:21 -0000	1.33
@@ -321,10 +321,16 @@
 			return retval;
 		}
 	}
+#ifdef IPC_SHM_RACE_FIX
+	SSI_ASSERT(server == this_node);
+#else
 	up(&sem_ids.sem);
+#endif
 	retval = cli_ipcname_getid(NAME_SERVICE_SEM, key, semflg, &newid,
 					&server, ssi_get_localview(), &create);
+#ifndef IPC_SHM_RACE_FIX
 	down(&sem_ids.sem);
+#endif
 	if (!retval) {
 		retval = newid;
 		if (!create)
@@ -1980,6 +1986,12 @@
 {
 	struct sem_undo_list *undo_list;
 	struct sem_undo *u, **up;
+#ifdef CONFIG_SSI
+	ssi_procstate_t pstate;
+	key_t key;
+	clusternode_t svr_node=0;
+	int rval, flags, view, sz;
+#endif
 
 	undo_list = tsk->sysvsem.undo_list;
 	if (!undo_list)
@@ -1989,11 +2001,6 @@
 		return;
 
 #ifdef CONFIG_SSI
-	int rval, flags, view, sz;
-	clusternode_t svr_node=0;
-	ssi_procstate_t pstate;
-	key_t key;
-
 	/* There's no need to hold the semundo list lock, as current
          * is the last task exiting for this undo list.
 	 */

Index: shm.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/shm.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- shm.c	2 Feb 2010 05:19:30 -0000	1.27
+++ shm.c	5 Mar 2010 06:30:21 -0000	1.28
@@ -72,6 +72,36 @@
 #define PRINT_HEADER \
 	len += sprintf(buffer, "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime       view   node_num\n");
 
+#ifdef IPC_SHM_RACE_FIX
+struct shmid_kernel *shm_cli_get(int id)
+{
+	return shm_get(id);
+}
+struct shmid_kernel_svr *shm_svr_get(int id)
+{
+	return (struct shmid_kernel_svr *) ipc_get(&shm_ids_svr, id);
+}
+struct shmid_kernel *shm_cli_lock(int id)
+{
+	return shm_lock(id);
+}
+void shm_cli_unlock(struct shmid_kernel *shp)
+{
+	shm_unlock(shp);
+}
+struct shmid_kernel_svr *shm_svr_lock(int id)
+{
+	return (struct shmid_kernel_svr *) ipc_lock(&shm_ids_svr, id);
+}
+void shm_svr_unlock(struct shmid_kernel_svr *svp)
+{
+	ipc_unlock(&(svp)->shm_perm);
+}
+int shm_sem_owned(void)
+{
+	return sem_owned(&shm_ids.sem);
+}
+#else /* IPC_SHM_RACE_FIX */
 inline struct shmid_kernel_svr *shm_svr_get(int id)
 {
 	return ((struct shmid_kernel_svr *)ipc_get(&shm_ids_svr,id));
@@ -81,9 +111,11 @@
 {
 	return ((struct shmid_kernel *)ipc_get(&shm_ids,id));
 }
+#endif /* !IPC_SHM_RACE_FIX */
+
 static int newseg (key_t, int, size_t, struct file *, int, int);
 
-#else
+#else /* CONFIG_SSI */
 
 #define SHM_MAX_ID	shm_ids.max_id
 #define SHM_IPC_ID(i,seq)	shm_buildid(i,seq)
@@ -132,7 +164,7 @@
 inline struct shmid_kernel *shm_rmid(int id)
 #else
 static inline struct shmid_kernel *shm_rmid(int id)
-#endif /* CONFIG_SSI */
+#endif /* !CONFIG_SSI */
 {
 	return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
 }
@@ -143,7 +175,7 @@
 	return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni, shp->id);
 #else
 	return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
-#endif /* CONFIG_SSI */
+#endif /* !CONFIG_SSI */
 }
 
 
@@ -283,6 +315,7 @@
 };
 
 #ifdef CONFIG_SSI
+/* Must be called with shm_ids.sem locked */
 static int newseg (key_t key, int shmflg, size_t size, struct file *fp,
 							int view, int newid)
 #else
@@ -587,11 +620,20 @@
 
 			if ((cmd^IPC_64) == IPC_RMID) {
 				/* if its local & svr is down, then remove it */
+#ifdef IPC_SHM_RACE_FIX
+				shp = shm_cli_lock(shmid);
+				if (!shp)
+					return -EINVAL;
+				if (shp->shm_node != this_node)
+					svrnode = 0;
+				shm_cli_unlock(shp);
+#else
 				shp = shm_cli_get(shmid);
 				if (!shp)
 					return -EINVAL;
 				if (shp->shm_node != this_node)
 					svrnode = 0;
+#endif
 			}
 			else
 				return -EINVAL;
@@ -1014,7 +1056,7 @@
 		err = -EINVAL;
 		goto out;
 	}
-#endif /* CONFIG_SSI */
+#endif /* !CONFIG_SSI */
 	err = shm_checkid(shp,shmid);
 	if (err) {
 #ifdef CONFIG_SSI
@@ -1045,44 +1087,79 @@
 	/* Setup for remote access */
 	if (shp->shm_file->f_op != &cfs_shm_file_operations) {
 			struct dentry *de;
+#ifndef IPC_SHM_RACE_FIX
 			struct vfsmount *new_mnt=NULL;
+#else
+			struct dentry *old_dentry = NULL;
+			struct vfsmount *old_mnt = NULL;
 
+			ipc_rcu_getref(shp);
+#endif /* IPC_SHM_RACE_FIX */
 			shm_unlock(shp);
-			de = ssi_shm_setup(shp->shm_node, shp->id, 0, 
+			de = ssi_shm_setup(shp->shm_node, shp->id, 0,
 						shp->shm_perm.key);
 			down (&shm_ids.sem);
+#ifdef IPC_SHM_RACE_FIX
+			ipc_lock_by_ptr(&shp->shm_perm);
+			ipc_rcu_putref(shp);
+			if (!shm_get(shmid)) {
+				shm_unlock(shp);
+				up (&shm_ids.sem);
+				dput(de);
+				return -EINVAL;
+			}
+#else
 			shp = shm_lock(shmid);
 			if (!shp) {
 				dput(de);
 				up (&shm_ids.sem);
 				return -EINVAL;
 			}
+#endif /* !IPC_SHM_RACE_FIX */
 
 			if (shp->shm_file->f_op == &cfs_shm_file_operations) {
+#ifdef IPC_SHM_RACE_FIX
+				old_dentry = de;
+#else
 				dput(de);
+#endif
 				goto cont;
 			}
 
 			if (de) {
 				/* switch file to cfs and cleanup */
+#ifdef IPC_SHM_RACE_FIX
+				old_dentry = shp->shm_file->f_dentry;
+				shp->shm_file->f_dentry = de;
+
+				old_mnt = shp->shm_file->f_vfsmnt;
+				shp->shm_file->f_vfsmnt = mntget(
+					cfs_shm_node_mnts[shp->shm_node]);
+#else
 				dput(shp->shm_file->f_dentry);
 				mntput(shp->shm_file->f_vfsmnt);
 				new_mnt = (struct vfsmount *)
 					cfs_shm_node_mnts[shp->shm_node];
 				shp->shm_file->f_dentry = de;
 				shp->shm_file->f_vfsmnt = mntget(new_mnt);
+#endif
 				shp->shm_file->f_op = &cfs_shm_file_operations;
 				shp->shm_file->f_mapping =
 						de->d_inode->i_mapping;
 			}
 			else {
-				shp->shm_node = 0;
-				shm_destroy(shp);
+				ssi_local_destroy(shp);
 				up(&shm_ids.sem);
 				return -EINVAL;
 			}
 cont:
 			up(&shm_ids.sem);
+#ifdef IPC_SHM_RACE_FIX
+			if (old_dentry)
+				dput(old_dentry);
+			if (old_mnt)
+				mntput(old_mnt);
+#endif
 	}
 #endif /* CONFIG_SSI */
 	file = shp->shm_file;
@@ -1130,13 +1207,12 @@
 ssi_err:
 	if (shp->shm_node != this_node &&
 			shp->shm_file->f_op != &cfs_shm_file_operations) {
-		shp->shm_node = 0;
 		shm_unlock(shp);
 		down (&shm_ids.sem);
 		if(!(shp = shm_lock(shmid)))
 			BUG();
-		shm_destroy(shp);
-		up (&shm_ids.sem);
+		ssi_local_destroy(shp);
+		up(&shm_ids.sem);
 	}
 	else
 		shm_unlock(shp);
@@ -1190,10 +1266,11 @@
 		 */
 #ifdef CONFIG_SSI
 		if ((vma->vm_ops==&cfs_shm_vm_ops || is_vm_hugetlb_page(vma)) &&
+			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
 #else
 		if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
-#endif /* CONFIG_SSI */
 			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
+#endif /* CONFIG_SSI */
 
 
 			size = vma->vm_file->f_dentry->d_inode->i_size;
@@ -1222,10 +1299,11 @@
 		/* finding a matching vma now does not alter retval */
 #ifdef CONFIG_SSI
 		if ((vma->vm_ops==&cfs_shm_vm_ops || is_vm_hugetlb_page(vma)) &&
+			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
 #else
 		if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
-#endif /* CONFIG_SSI */
 			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
+#endif /* CONFIG_SSI */
 
 			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
 		vma = next;
@@ -1238,11 +1316,9 @@
 #ifdef CONFIG_SSI
 struct shmid_kernel_svr *shm_svr_rmid(int id)
 {
-	struct shmid_kernel_svr *svr;
-
-	svr = (struct shmid_kernel_svr *)ipc_rmid(&shm_ids_svr,id);
-	return svr;
+	return (struct shmid_kernel_svr *)ipc_rmid(&shm_ids_svr,id);
 }
+
 int shm_svr_addid(struct shmid_kernel_svr *shm_svr)
 {
 	struct ipc_ids *ids = &shm_ids_svr;
@@ -1250,6 +1326,9 @@
 	struct kern_ipc_perm *new = &(shm_svr->shm_perm);
 	int size;
 
+	spin_lock_init(&new->lock);
+	new->deleted = 0;
+
 	down(&shm_ids_svr.sem);
 	size = ipc_grow_ary(ids,shmsvrsz+1);
 	ids->in_use++;
@@ -1267,14 +1346,24 @@
 clusternode_t
 shm_get_svrnode(struct dentry *de)
 {
-	int id = de->d_inode->i_ino;
 	struct shmid_kernel *shp;
+#ifdef IPC_SHM_RACE_FIX
+	clusternode_t node;
 
+	shp = shm_lock(de->d_inode->i_ino);
+	if (!shp)
+		return CLUSTERNODE_INVAL;
+	node = shp->shm_node;
+	shm_unlock(shp);
+	return node;
+#else /* IPC_SHM_RACE_FIX */
+	int id = de->d_inode->i_ino;
 	shp = shm_get(id);
 	if (shp)
 		return shp->shm_node;
 	else 
 		return CLUSTERNODE_INVAL;
+#endif /* !IPC_SHM_RACE_FIX */
 }
 
 /**
@@ -1284,24 +1373,25 @@
 int 
 shm_create_cli_entry(struct file **filepp)
 {
-	struct file *file = *filepp;
-	struct file *old_file = NULL;
-	int shmid = file->f_dentry->d_inode->i_ino;
+	struct file *old_file, *file = *filepp;
 	struct shmid_kernel *shp;
 	clusternode_t svrnode;
 	key_t key;
 	long id;
-	int flags;
-	int view=0;
-	int sz;
+	int shmid = file->f_dentry->d_inode->i_ino;
+	int flags, sz, view=0;
 
 	BUG_ON(strncmp(file->f_dentry->d_name.name, "SYSV", 4));
 
 	/* create client */
+#ifndef IPC_SHM_RACE_FIX
 	down(&shm_ids.sem);
+#endif
 	shp = shm_lock(shmid);
 	if (!shp) {
+#ifndef IPC_SHM_RACE_FIX
 		up(&shm_ids.sem);
+#endif
 		if (cli_ipcname_findid(NAME_SERVICE_SHM, shmid, 
 							&key,
 							&svrnode,
@@ -1312,8 +1402,12 @@
 
 		down(&shm_ids.sem);
 		shp = shm_lock(shmid);
-		if (shp)
+		if (shp) {
+#ifdef IPC_SHM_RACE_FIX
+			up(&shm_ids.sem);
+#endif
 			goto found;
+		}
 		id = newseg(key, flags, sz, file, view, shmid);
 		if (id < 0) {
 			up(&shm_ids.sem);
@@ -1321,25 +1415,33 @@
 		}
 		shp = shm_lock(shmid);
 		shp->shm_node = svrnode;
+#ifdef IPC_SHM_RACE_FIX
+		up(&shm_ids.sem);
+#endif
 	}
 found:
 	if (shmid != shp->id) {
-		printk("Failed to create new cli entry, failing migrate\n");
 		shm_unlock(shp);
+#ifndef IPC_SHM_RACE_FIX
 		up(&shm_ids.sem);
+#endif
+		printk(KERN_WARNING "%s: Failed to create new cli entry, "
+			"failing migrate\n", __FUNCTION__);
 		return -EINVAL;
 	}
-	else {
-		if (shp->shm_file != file) {
-			old_file = file;
-			*filepp = file = shp->shm_file;
-		}
-	}
+
+	if (shp->shm_file != file) {
+		old_file = file;
+		*filepp = file = shp->shm_file;
+	} else
+		old_file = NULL;
 	get_file(file);
 	shp->shm_file->f_op = &cfs_shm_file_operations;
 	shp->shm_file->f_mode |= (FMODE_WRITE|FMODE_READ);
 	shm_unlock(shp);
+#ifndef IPC_SHM_RACE_FIX
 	up(&shm_ids.sem);
+#endif
 	if (old_file)
 		fput(old_file);
 	return 0;
@@ -1348,10 +1450,46 @@
 int 
 ipcname_failover_create(key_t key, int shmid, int size, clusternode_t svrnode, int view)
 {
-	int id;
 	struct shmid_kernel *shp;
+	int id;
 
 	/* see if client already exists */
+#ifdef IPC_SHM_RACE_FIX
+	shp = shm_lock(shmid);
+	if (shp)
+		goto found;
+
+	down(&shm_ids.sem);
+	shp = shm_lock(shmid);
+	if (shp) {
+		up(&shm_ids.sem);
+		goto found;
+	}
+
+	/* create client */
+	id = newseg(key, 0, size, NULL, view, shmid);
+	if (id < 0) {
+		up(&shm_ids.sem);
+		printk(KERN_WARNING "%s: Unable create new segment %d\n",
+			__FUNCTION__, shmid);
+		return -EINVAL;
+	}
+	shp = shm_lock(shmid);
+	shp->shm_node = svrnode;
+	shm_unlock(shp);
+	up(&shm_ids.sem);
+	return 0;
+found:
+	if (shp->id != shmid || shp->shm_perm.key != key ||
+	    shp->shm_node != svrnode) {
+		shm_unlock(shp);
+		printk(KERN_WARNING "%s: Different shp already "
+			"exists %d %d\n", __FUNCTION__, shp->id, shmid);
+		return -EINVAL;
+	}
+	shm_unlock(shp);
+	return 0;
+#else /* IPC_SHM_RACE_FIX */
 	down(&shm_ids.sem);
 	shp = shm_cli_get(shmid);
 	if (shp) {
@@ -1370,136 +1508,110 @@
 	shm_unlock(shp);
 	up(&shm_ids.sem);
 	return 0;
+#endif /* !IPC_SHM_RACE_FIX */
 }
 
 void
 ipc_shm_nodedown(clusternode_t node)
 {
-	int id;
-	struct shmid_kernel *shp;
-#ifdef IPC_SHM_LOCK_DEST_FIX
-	struct ipc_id_ary* entries;
-	int max_id, shm_id, shm_ids_sem_held, shm_node_found = 1;
-#else
 	struct ipc_ids *ids = &shm_ids;
+	struct shmid_kernel *shp;
+	int id;
+#ifdef IPC_SHM_RACE_FIX
+	struct vfsmount *mnt;
+	int sem_held;
+	int last_id, max_id;
+	char retry, use_bitmap, shm_lock_dest;
+	DECLARE_BITMAP(retry_bitmap, IPCMNI);
+
+	bitmap_zero(retry_bitmap, IPCMNI);
+	retry = use_bitmap = shm_lock_dest = 0;
 #endif
 
 	icssvr_nodedown_svc_wait(node, cluster_ipc_svc);
 
-#ifdef IPC_SHM_LOCK_DEST_FIX
-again:
-	shm_ids_sem_held = 1;
-	if (shm_node_found) {
-		/* Cannot call down() since we are not certain if a SHM segment
-		 * for DOWN node has shm_ids.sem for SHM_LOCK_DEST.
-		 */
-		while (down_trylock(&shm_ids.sem)) {
-			if (shm_ids.lock_dest_id != -1) {
-				/* SHM_LOCK_DEST for some segment not necessarily
-				 * the segment for DOWN node.
-				 */
-				shm_ids_sem_held = 0;
-				break;
-			}
-			nidelay(HZ/20);
-		}
-		/* If none of the SHM segments for DOWN node
-		 * has SHM_LOCK_DEST we can call down().
-		 */
-		shm_node_found = 0;
-	} else
-		down(&shm_ids.sem);
-
- 	max_id = shm_ids_sem_held ? shm_ids.max_id : shm_ctlmni;
- 	for (id = 0; id <= max_id; id++) {
-		if (!shm_ids_sem_held) {
-			/* avoid races; based on ipc_lock() */
-			rcu_read_lock();
-			entries = rcu_dereference(shm_ids.entries);
-			shp = (struct shmid_kernel *)entries->p[id];
-			if (!shp || shp->shm_perm.deleted) {
-				rcu_read_unlock();
-				continue;
-			}
-			if (shp->shm_node != node) {
-				rcu_read_unlock();
-				continue;
-			}
-			shm_id = shp->id;
-			rcu_read_unlock();
-
-			/* barrier for shm_ids.lock_dest_id */
-			shm_ids_sem_held = !down_trylock(&shm_ids.sem);
-			if (shm_ids_sem_held) {
-				if (id != 0)
-					id = -1; /* restart for loop */
-				max_id = shm_ids.max_id;
-			}
-
-			shm_node_found = 1;
-
-			if (shm_id != shm_ids.lock_dest_id)
-				continue;
-			/* Now we can obtain shm_ids.sem without possibility of
-			 * deadlock since this segment has shm_ids.lock_dest_id
-			 * (SHM_LOCK_DEST). Even if we raced we don't expect
-			 * another thread for DOWN node to acquire SHM_LOCK_DEST.
-			 */
-		} else {
-			/* shm_ids.sem held */
-			shp = (struct shmid_kernel *)shm_ids.entries->p[id];
-			if (!shp)
-				continue;
-			if (shp->shm_node == this_node)
-				shm_svr_unregister(shp->id, node);
-			if (shp->shm_node != node)
-				continue;
-			shm_id = shp->id;
-		}
+#ifdef IPC_SHM_RACE_FIX
+	write_lock(&cfs_shm_node_mnts_lock);
+	mnt = mntget(cfs_shm_node_mnts[node]);
+	cfs_shm_node_mnts[node] = NULL;
+	write_unlock(&cfs_shm_node_mnts_lock);
+	mntput(mnt);
 
-		shp = (struct shmid_kernel *)ipc_get_locks(shm_id, &shm_ids, 0);
+	sem_held = !down_trylock(&ids->sem);
+	max_id = sem_held ? ids->max_id : shm_ctlmni;
 
-		if (!shm_ids_sem_held) {
-			shm_ids_sem_held = 1;
-			if (!shp || shp->id != shm_ids.lock_dest_id) {
-				/* Lost race with ripc_shm_rmid(), etc. */
-				if (shp) {
-					ipc_drop_locks(shp->id,
-							(struct kern_ipc_perm *)shp,
-							&shm_ids, 0);
-					shp = (struct shmid_kernel *)
-						ipc_get_locks(shm_id, &shm_ids, 1);
-				} else
-					down(&shm_ids.sem);
-				max_id = shm_ids.max_id;
-			} else {
-				/* shm_ids.sem held for SHM_LOCK_DEST */
-				max_id = shm_ids.max_id; /* avoided barrier */
-			}
-			if (id != 0)
-				id = -1; /* restart for loop */
+	SSI_ASSERT(max_id < IPCMNI);
+	last_id = max_id;
+again:
+ 	for (id = 0; id <= max_id; id++) {
+		if (use_bitmap && !test_bit(id, retry_bitmap)) {
+			id = find_next_bit(retry_bitmap, max_id+1, id+1);
+			if (id > max_id)
+				break;
 		}
-		/* shm_ids.sem held */
+		shp = shm_lock(id);
 		if (!shp)
 			continue;
-
-		shp->shm_flags |= SHM_DEST;
+		if (shp->shm_node == this_node) {
+			SSI_ASSERT(shp->id == id);
+			shm_unlock(shp);
+			shm_svr_unregister(id, node);
+			continue;
+		} else if (shp->shm_node != node) {
+			shm_unlock(shp);
+			continue;
+		}
+		if (!sem_held) {
+			/* SSI_XXX: Could be faster if we tracked the ID */
+			if (shp->shm_flags & SHM_LOCK_DEST) {
+				if (last_id > id)
+					last_id = id;
+				shm_lock_dest = 1;
+				sem_held = 1;
+			} else
+				sem_held = !down_trylock(&ids->sem);
+		}
 		if (shp->shm_nattch == 0) {
-			SSI_ASSERT(shm_ids_sem_held);
-
+			if (!sem_held) {
+				if (!(shp->shm_flags & SHM_DEST))
+					shp->shm_flags |= SHM_DEST;
+				shm_unlock(shp);
+				__set_bit(id, retry_bitmap);
+				if (!retry)
+					retry = 1;
+				continue; /* looking for SHM_LOCK_DEST */
+			}
+			SSI_ASSERT(shp->id == id);
 			ssi_local_destroy(shp);
-			cli_ipcname_rmid(NAME_SERVICE_SHM, shm_id);
-			/* ssi_local_destroy() released shp.shm_perm.lock */
-			/* shm_ids.sem still held */
-		} else
-			ipc_drop_locks(shp->id, (struct kern_ipc_perm *)shp,
-					&shm_ids, 0);
+			cli_ipcname_rmid(NAME_SERVICE_SHM, id);
+		} else {
+			if (!(shp->shm_flags & SHM_DEST))
+				shp->shm_flags |= SHM_DEST;
+			shm_unlock(shp);
+		}
 	}
-	if (!shm_ids_sem_held)
+	if (retry) {
+		retry = 0;
+		if (shm_lock_dest) {
+			/* SHM_LOCK_DEST flag encountered.
+			 * ids->sem was held the whole time
+			 * so our retry_bitmap is accurate.
+			 */
+			SSI_ASSERT(sem_held);
+			if (last_id == 0)
+				goto out;
+			max_id = last_id - 1;
+			use_bitmap = 1;
+		} else if (!sem_held) {
+			down(&ids->sem);
+			sem_held = 1;
+		}
 		goto again;
-
-	up(&shm_ids.sem);
-#else /* !IPC_SHM_LOCK_DEST_FIX */
+	}
+out:
+	if (sem_held)
+		up(&ids->sem);
+#else /* IPC_SHM_RACE_FIX */
  	for (id = 0; id <= ids->max_id; id++) {
 		if(ids->entries->p[id] == NULL)
 			continue;
@@ -1513,11 +1625,10 @@
 				if (shp->shm_nattch == 0) {
 					int id = shp->id;
 					ssi_local_destroy(shp);
-					cli_ipcname_rmid(NAME_SERVICE_SHM, id);
 					/* ssi_local_destroy released shp.shm_perm.lock */
+					cli_ipcname_rmid(NAME_SERVICE_SHM, id);
 					up(&shm_ids.sem);
-				}
-				else {
+				} else {
 					shp->shm_flags |= SHM_DEST;
 					ipc_drop_locks(shp->id,
 						(struct kern_ipc_perm *)shp,
@@ -1538,13 +1649,14 @@
 			}
 		}
 	}
-#endif /* !IPC_SHM_LOCK_DEST_FIX */
 	if (cfs_shm_node_mnts[node]) {
 		mntput(cfs_shm_node_mnts[node]);
 		cfs_shm_node_mnts[node] = NULL;
 	}
+#endif /* !IPC_SHM_RACE_FIX */
 }
 
+/* Called with shm_ids.sem or shp locked */
 long 
 shm_get_segsize(struct shmid_kernel *shp)
 {
@@ -1559,6 +1671,7 @@
 	return i_size_read(shp->shm_file->f_dentry->d_inode);
 }
 
+/* Called with shm_ids.sem or shp locked */
 long 
 shm_get_cpid(struct shmid_kernel *shp)
 {
@@ -1623,10 +1736,16 @@
 	}
 	newid = -1;
 	create = size;
+#ifdef IPC_SHM_RACE_FIX
+	SSI_ASSERT(server == this_node);
+#else
 	up(&shm_ids.sem);
-	retval = cli_ipcname_getid(NAME_SERVICE_SHM, key, shmflg, &newid, 
+#endif
+	retval = cli_ipcname_getid(NAME_SERVICE_SHM, key, shmflg, &newid,
 					&server, ssi_get_localview(), &create);
+#ifndef IPC_SHM_RACE_FIX
 	down(&shm_ids.sem);
+#endif
 	if (!retval) {
 		retval = newid;
 
@@ -1656,9 +1775,8 @@
 			/* create  and fill server structure */
 			if (shm_svr_create(shp, newid, size, key, shmflg) < 0) {
 				cli_ipcname_rmid(NAME_SERVICE_SHM, newid);	
-				shm_lock(newid);
-				shp->shm_node = 0;
-				shm_destroy(shp);
+				shp = shm_lock(newid);
+				ssi_local_destroy(shp);
 				retval = -EINVAL;
 				goto out_nolock;
 			}
@@ -1672,9 +1790,38 @@
 		 */
 		if (create) {
 			struct dentry *newde;
+#ifdef IPC_SHM_RACE_FIX
+			struct dentry *old_dentry;
 
 			/* go register with server, create cfs stuff */
 			newde = ssi_shm_setup(server, newid, size, key);
+
+			shp = shm_lock(newid);
+			if (!shp) {
+				dput(newde);
+				retval = -ESRCH;
+				goto out_nolock;
+			}
+			if (!newde) {
+				shm_destroy(shp);
+				retval = -ESRCH;
+				goto out_nolock;
+			}
+
+			/* switch file to cfs and cleanup */
+			old_dentry = shp->shm_file->f_dentry;
+			shp->shm_file->f_dentry = newde;
+			shp->shm_file->f_op = &cfs_shm_file_operations;
+			shp->shm_file->f_mapping = newde->d_inode->i_mapping;
+			shp->shm_node = server;
+			shm_unlock(shp);
+			up(&shm_ids.sem);
+
+			dput(old_dentry);
+			return retval;
+#else /* IPC_SHM_RACE_FIX */
+			/* go register with server, create cfs stuff */
+			newde = ssi_shm_setup(server, newid, size, key);
 			if (newde) {
 				/* switch file to cfs and cleanup */
 				dput(shp->shm_file->f_dentry);
@@ -1690,6 +1837,7 @@
 				retval = -ESRCH;
 				goto out_nolock;
 			}
+#endif /* !IPC_SHM_RACE_FIX */
 		}
 	}
 out_nolock:

Index: util.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/util.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- util.c	13 Feb 2010 14:50:14 -0000	1.10
+++ util.c	5 Mar 2010 06:30:21 -0000	1.11
@@ -75,11 +75,6 @@
 		 else
 		 	ids->seq_max = seq_limit;
 	}
-#ifdef CONFIG_SSI
-#ifdef IPC_SHM_RACE_FIX
-	ids->lock_dest_id = -1;
-#endif
-#endif
 
 	ids->entries = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*size +
 				     sizeof(struct ipc_id_ary));
@@ -234,15 +229,6 @@
 	if (table)
 		up(&ids->sem);
 }
-
-#ifdef IPC_SHM_LOCK_DEST_FIX
-/* Called with ids.sem held */
-void
-ipc_lock_dest_id(struct ipc_ids *ids, int id)
-{
-	ids->lock_dest_id = id; /* SHM_LOCK_DEST */
-}
-#endif
 #endif /* CONFIG_SSI */
 
 /**
@@ -272,7 +258,11 @@
 #ifdef CONFIG_SSI
 	if (newid >= 0) {
 		id = newid%SEQ_MULTIPLIER;
+		/* Make ipc_checkid() pass */
 		ids->seq = newid/SEQ_MULTIPLIER;
+#ifdef IPC_SHM_RACE_FIX
+		BUG_ON(ids->entries->p[id] != NULL);
+#endif
 		goto found;
 	}
 #endif

Index: msg.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/msg.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- msg.c	2 Feb 2010 05:19:30 -0000	1.16
+++ msg.c	5 Mar 2010 06:30:21 -0000	1.17
@@ -340,10 +340,16 @@
 		}
 	}
 	newid = -1;
+#ifdef IPC_SHM_RACE_FIX
+	SSI_ASSERT(server == this_node);
+#else
 	up(&msg_ids.sem);
+#endif
 	retval = cli_ipcname_getid(NAME_SERVICE_MSG, key, msgflg, &newid,
 				   &server, ssi_get_localview(), &create);
+#ifndef IPC_SHM_RACE_FIX
 	down(&msg_ids.sem);
+#endif
 	if (!retval)
 	{
 		retval = newid;


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev