[SSI] openssi/kernel/ipc sem.c,1.35,1.36

Roger Tsang <[email protected]> Sat, 03 Apr 2010 19:41:54 +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-serv30015/kernel/ipc

Modified Files:
      Tag: OPENSSI-FC
	sem.c 
Log Message:
- sys_semctl()
  - Move SSI code into ssi_semctl().
  - Handle cli_ripc_semctl() error -EAGAIN.
  - Fix semctl_nolock() deadlock with destination node when both nodes are doing RPC for SEM_INFO command.
- semctl_nolock()
  - Move SSI code to ssi_semctl_nolock_info().
  - Handle cli_ripc_semctl() error -EAGAIN.
  - Fix race with sys_semctl() over global variable "remote_cmd".
- Fix alloc_semundo() sem_semundo struct memory leak; assigning sem_semundo struct to sem_array that is going away when lost race with ipc_rmid().
- Remove redundant in ssi_semop() which is mostly taken from original sys_semtimedop().
- Fix ssi_semop() dereferencing invalid sem_semundo struct if lost race with ssi_semexit() though this is unlikely to occur because in sem_exit() the last thread removes the the sem_semundo struct.
- Enable debug message in freeundos().
- sem_exit() handle cli_ripc_semexit() error -EAGAIN.
- Remove ugly goto's in __ssi_semexit().


Index: sem.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/sem.c,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -d -r1.35 -r1.36
--- sem.c	2 Apr 2010 20:42:31 -0000	1.35
+++ sem.c	3 Apr 2010 19:41:51 -0000	1.36
@@ -103,7 +103,6 @@
 #endif /* CONFIG_SSI */
 
 #ifdef CONFIG_SSI
-static int remote_cmd=FALSE;
 #define SEM_MAX_ID		(local_view ? sem_ids.max_id : size-1)
 #define SEM_IPC_ID(i,seq)	(local_view ? sem_buildid(i,seq) : ipc_id)
 #define PRINT_HEADER len += sprintf(buffer, "       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime       view    node_num\n")
@@ -139,8 +138,6 @@
 #define sc_semmni	(sem_ctls[3])
 
 #ifdef CONFIG_SSI
-void ssi_semexit(int semid, pid_t pid);
-
 static void freeundos(int);
 static clusternode_t sem_get_svr_node(int);
 static void sem_set_svr_node(int, clusternode_t);
@@ -701,6 +698,58 @@
 	}
 }
 
+#ifdef CONFIG_SSI
+int
+ssi_semctl_nolock_info(
+	struct seminfo *seminfo,
+	union semun arg)
+{
+	ssi_procstate_t pstate;
+	nsc_nodelist_t *nl;
+	nsc_nlcookie_t cookie = CLUSTERNODE_INVAL;
+	clusternode_t svrnode;
+	int status, rval, max_id = 0;
+
+	ssi_procstate_get(&pstate);
+
+	nl = clms_get_nsc_nodelist(CLMS_NODE_UP);
+	while ((svrnode = nsc_nodelist_get_next(&cookie, nl))
+					!= CLUSTERNODE_INVAL) {
+		if (svrnode == this_node)
+			continue;
+		memset (arg.__buf, 0, sizeof(struct seminfo));
+retry:
+		status = cli_ripc_semctl(svrnode, &rval, -1, 0, SEM_INFO,
+							&pstate, &arg, 1);
+		if (status == -EREMOTE)
+			continue;
+		if (status) {
+			idelay(HZ/10);
+			goto retry;
+		}
+		if (arg.__buf->semusz) {
+			seminfo->semusz += arg.__buf->semusz;
+			seminfo->semaem += arg.__buf->semaem;
+			max_id += rval;
+		}
+	}
+	NSC_NODELIST_FREE(nl);
+
+	/* Now obtain sem_ids.sem mutex because
+	 * cli_ripc_semctl() could deadlock with
+	 * another incoming RPC from destination node
+	 * that already holds sem_ids.sem mutex.
+	 */
+	down(&sem_ids.sem);
+	seminfo->semusz += sem_ids.in_use;
+	seminfo->semaem += used_sems;
+	max_id += sem_ids.max_id;
+	up(&sem_ids.sem);
+
+	return max_id;
+}
+#endif /* CONFIG_SSI */
+
 static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	int err = -EINVAL;
@@ -712,12 +761,6 @@
 	{
 		struct seminfo seminfo;
 		int max_id;
-#ifdef CONFIG_SSI
-		clusternode_t svrnode;
-		ssi_procstate_t pstate;
-		nsc_nodelist_t *nl;
-		nsc_nlcookie_t cookie;
-#endif /* CONFIG_SSI */
 
 		err = security_sem_semctl(NULL, cmd);
 		if (err)
@@ -732,43 +775,15 @@
 		seminfo.semmnu = SEMMNU;
 		seminfo.semmap = SEMMAP;
 		seminfo.semume = SEMUME;
-		down(&sem_ids.sem);
-		if (cmd == SEM_INFO) {
 #ifdef CONFIG_SSI
-			if (!ssi_get_localview() && (remote_cmd == FALSE))
-			{
-				ssi_procstate_get(&pstate);
-				max_id = 0;
-				nl = clms_get_nsc_nodelist(CLMS_NODE_UP);
-				cookie = CLUSTERNODE_INVAL;
-				svrnode = nsc_nodelist_get_next(&cookie, nl);
-				for (;svrnode != CLUSTERNODE_INVAL;
-				   svrnode = nsc_nodelist_get_next(&cookie,nl))
-				{
-					if( svrnode != this_node )
-					{
-						memset (arg.__buf, 0,
-							sizeof(struct seminfo));
-						cli_ripc_semctl(svrnode, &err, -1, 0, SEM_INFO, &pstate, &arg, 1);
-						if (arg.__buf->semusz)
-						{
-							seminfo.semusz +=
-							      arg.__buf->semusz;
-							seminfo.semaem +=
-							      arg.__buf->semaem;
-							max_id += err;
-							err = 0;
-						}
-					}
-				}
-				NSC_NODELIST_FREE(nl);
-				seminfo.semusz += sem_ids.in_use;
-				seminfo.semaem += used_sems;
-				max_id += sem_ids.max_id;
-				goto out_up;
-			}
-			remote_cmd = FALSE;
+		if (cmd == SEM_INFO &&
+		    !ssi_get_localview() && !ssi_isremote()) {
+			max_id = ssi_semctl_nolock_info(&seminfo, arg);
+			goto out_info;
+		}
 #endif /* CONFIG_SSI */
+		down(&sem_ids.sem);
+		if (cmd == SEM_INFO) {
 			seminfo.semusz = sem_ids.in_use;
 			seminfo.semaem = used_sems;
 		} else {
@@ -776,10 +791,10 @@
 			seminfo.semaem = SEMAEM;
 		}
 		max_id = sem_ids.max_id;
+		up(&sem_ids.sem);
 #ifdef CONFIG_SSI
-out_up:
+out_info:
 #endif /* CONFIG_SSI */
-		up(&sem_ids.sem);
 		if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) 
 			return -EFAULT;
 		return (max_id < 0) ? 0: max_id;
@@ -1122,66 +1137,67 @@
 	return err;
 }
 
-asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
-{
-	int err = -EINVAL;
-	int version;
-
 #ifdef CONFIG_SSI
+static int
+ssi_semctl(
+	int semid,
+	int semnum,
+	int cmd,
+	union semun arg,
+	int *err)
+{
+	ssi_procstate_t pstate;
 	clusternode_t svr_node;
-	int rval;
-	int tmpcmd = cmd;
+	int status, rval;
 
-	remote_cmd = FALSE;
+	svr_node = sem_get_svr_node(semid);
+	if (!svr_node) {
+namesvr_go:
+		svr_node = sem_find_svr_node(semid);
+		if (!svr_node) {
+			*err = -EINVAL;
+			return 0;
+		}
+		sem_set_svr_node(semid, svr_node);
+	}
+	if (svr_node == this_node)
+		return -ESRCH;
 
-	version = ipc_parse_version(&cmd);
-	if ((cmd == SEM_INFO) || (cmd == IPC_INFO)) {
-		svr_node = this_node;
-		if (semid == -1) {
-			remote_cmd=TRUE;
-			semid = 0;
+	ssi_procstate_get(&pstate);
+retry:
+	status = cli_ripc_semctl(svr_node, &rval, semid,
+				 semnum, cmd, &pstate, &arg, 1);
+	if (status) {
+		if (status != -EREMOTE) {
+			idelay(HZ/10);
+			goto retry;
 		}
-	} else
-		svr_node = 0;
-	cmd = tmpcmd;
+		sem_set_svr_node(semid, 0);
+		goto namesvr_go;
+	}
+	if (rval == 0 && cmd == IPC_RMID) {
+		/* If we are able to invalidate server semaphore
+		   objects, delete the local objects. */
+		freeundos(semid);
+		sem_set_svr_node(semid, 0);
+	}
+	*err = rval;
+	return 0;
+}
 #endif /* CONFIG_SSI */
 
+asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
+{
+	int err = -EINVAL;
+	int version;
+
 	if (semid < 0)
 		return -EINVAL;
 
 #ifdef CONFIG_SSI
-	if (svr_node != this_node &&
-	    semid >= 0 && cmd >= 0) {
-namesvr_go:
-		svr_node = sem_get_svr_node(semid);
-		if (!svr_node) {
-			svr_node = sem_find_svr_node(semid);
-			if (!svr_node)
-				return -EINVAL;
-			sem_set_svr_node(semid, svr_node);
-		}
-
-		if (svr_node != this_node) {
-			ssi_procstate_t pstate;
-			int status;
-
-			ssi_procstate_get(&pstate);
-			status = cli_ripc_semctl(svr_node, &rval, semid,
-						 semnum, cmd, &pstate, &arg, 1);
-			if (status) {
-				sem_set_svr_node(semid, 0);
-				idelay(HZ/10);
-				goto namesvr_go;
-			}
-			if (rval == 0 && cmd == IPC_RMID) {
-				/* If we are able to invalidate server semaphore
-				   objects, delete the local objects. */
-				freeundos(semid);
-				sem_set_svr_node(semid, 0);
-			}
-			return rval;
-		}
-		cmd = tmpcmd;
+	if (cmd != SEM_INFO && cmd != IPC_INFO && cmd >= 0) {
+		if (!ssi_semctl(semid, semnum, cmd, arg, &err))
+			return err;
 	}
 #endif /* CONFIG_SSI */
 
@@ -1409,18 +1425,23 @@
 	lock_semundo();
 	if ((un = lookup_undo(undo_list, semid)))
 		un->semid =-1;
-	/* else */
+	else
 		/* SSI_XXX: Needed anymore? */
-		/* printk ("freeundos undo list error id=%d\n", semid); */
+		printk(KERN_DEBUG "freeundos: undo list error id=%d\n", semid);
 	unlock_semundo();
 }
 
-static int alloc_semundo(struct sem_array *sma, struct sem_semundo** unp, int semid,int alter)
+/* Called with sem_array locked.
+ * On error returns with sem_array unlocked.
+ */
+static int alloc_semundo(struct sem_array *sma, struct sem_semundo** unp, int alter)
 {
 	int size, nsems;
 	struct sem_semundo *un;
 
 	nsems = sma->sem_nsems;
+	ipc_rcu_getref(sma);
+	sem_unlock(sma);
 
 	size = sizeof(struct sem_semundo) + sizeof(short)*nsems;
 
@@ -1434,193 +1455,51 @@
 
 	ipc_lock_by_ptr(&sma->sem_perm);
 	ipc_rcu_putref(sma);
+	if (sma->sem_perm.deleted) {
+		/* ipc_rmid() got to it while we slept */
+		sem_unlock(sma);
+		kfree(un);
+		return -EIDRM;
+	}
 	un->semadj = (short *) &un[1];
 	un->id_next = sma->undo;
 	un->pid = current->tgid;
 	sma->undo = un;
-	sem_unlock(sma);
+
 	*unp = un;
 	return 0;
 }
 
-long ssi_semop(int semid, struct sembuf *tsops, unsigned nsops,
-		const struct timespec *timeout)
+/*
+ * Called with sem locked.
+ * Returns with sem unlocked on error.
+ */
+static struct sem_semundo *ssi_find_undo(struct sem_array *sma, int alter)
 {
-	int error = -EINVAL;
-	struct sem_array *sma;
-	struct sembuf fast_sops[SEMOPM_FAST];
-	struct sembuf* sops = fast_sops, *sop;
 	struct sem_semundo *un;
-	int undos = 0, decrease = 0, alter = 0;
-	struct sem_queue queue;
-	unsigned long jiffies_left = 0;
-	int max;
-
-	if(nsops > SEMOPM_FAST) {
-		sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
-		if(sops==NULL)
-			return -ENOMEM;
-	}
-	if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {
-		error=-EFAULT;
-		goto out_free;
-	}
-	if (timeout) {
-		struct timespec _timeout;
-		if (copy_from_user(&_timeout, timeout, sizeof(*timeout))) {
-			error = -EFAULT;
-			goto out_free;
-		}
-		if (_timeout.tv_sec < 0 || _timeout.tv_nsec < 0 ||
-		    _timeout.tv_nsec >= 1000000000L) {
-			error = -EINVAL;
-			goto out_free;
-		}
-		jiffies_left = timespec_to_jiffies(&_timeout);
-	}
-	max = 0;
-	for (sop = sops; sop < sops + nsops; sop++) {
-		if (sop->sem_num >= max)
-			max = sop->sem_num;
-		if (sop->sem_flg & SEM_UNDO)
-			undos++;
-		if (sop->sem_op < 0)
-			decrease = 1;
-		if (sop->sem_op > 0)
-			alter = 1;
-	}
-	alter |= decrease;
-
-	if (undos) {
-		sma = sem_lock(semid);
-		if (sma == NULL)
-			goto out_free;
-		error = -EIDRM;
-		if (sem_checkid(sma,semid))
-			goto out_unlock_free;
-
-		un = sma->undo;
-
-		/* Make sure we have an undo structure
-		 * for this process and this semaphore set.
-		 */
-		while(un != NULL) {
-			/* Bug [ 1984656 ] semaphore undo count
-			   sometimes screws up:
-			   we need to check thread group id, not
-			   [effective] pid, undo lists are shared by
-		           all threads in process. */
-			if(un->pid==current->tgid)
-				break;
-			un=un->id_next;
-		}
-
-		if (!un) { /* No sem_undo struct already exists */
-			ipc_rcu_getref(sma);
-			sem_unlock(sma);
-			error = alloc_semundo(sma,&un,semid,alter);
-			if (error)
-				goto out_free;
-		} else
-			sem_unlock(sma);
-	} else
-		un = NULL;
-
-	sma = sem_lock(semid);
-	error=-EINVAL;
-	if(sma==NULL)
-		goto out_free;
-	error = -EIDRM;
-	if (sem_checkid(sma,semid))
-		goto out_unlock_free;
-
-	error = -EFBIG;
-	if (max >= sma->sem_nsems)
-		goto out_unlock_free;
-
-	error = -EACCES;
-	if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
-		goto out_unlock_free;
-
-	error = security_sem_semop(sma, sops, nsops, alter);
-	if (error)
-		goto out_unlock_free;
-
-	error = try_atomic_semop (sma, sops, nsops, un, current->tgid);
-	if (error <= 0) {
-		if (alter && error == 0)
-			update_queue (sma);
-		goto out_unlock_free;
-	}
-
-	/* We need to sleep on this operation, so we put the current
-	 * task into the pending queue and go to sleep.
-	 */
-
-	queue.sma = sma;
-	queue.sops = sops;
-	queue.nsops = nsops;
-	queue.undo = un;
-	queue.pid = current->tgid;
-	queue.id = semid;
-	queue.alter = alter;
-	if (alter)
-		append_to_queue(sma ,&queue);
-	else
-		prepend_to_queue(sma ,&queue);
-
-	queue.status = -EINTR;
-	queue.sleeper = current;
-	current->state = TASK_INTERRUPTIBLE;
-	sem_unlock(sma);
-
-	if (timeout)
-		jiffies_left = schedule_timeout(jiffies_left);
-	else
-		schedule();
-
-	error = queue.status;
-	while(unlikely(error == IN_WAKEUP)) {
-		cpu_relax();
-		error = queue.status;
-	}
-
-	if (error != -EINTR) {
-		/* fast path: update_queue already obtained all requested
-		 * resources */
-		goto out_free;
-	}
+	int error;
 
-	sma = sem_lock(semid);
-	if(sma==NULL) {
-		if(queue.prev != NULL)
-			BUG();
-		error = -EIDRM;
-		goto out_free;
-	}
+	un = sma->undo;
 
-	/*
-	 * If queue.status != -EINTR we are woken up by another process
+	/* Make sure we have an undo structure
+	 * for this process and this semaphore set.
 	 */
-	error = queue.status;
-	if (error != -EINTR) {
-		goto out_unlock_free;
+	while(un != NULL) {
+		/* Bug [ 1984656 ] semaphore undo count
+		   sometimes screws up:
+		   we need to check thread group id, not
+		   [effective] pid, undo lists are shared by
+		   all threads in process. */
+		if(un->pid==current->tgid)
+			return un;
+		un=un->id_next;
 	}
 
-	/*
-	 * If an interrupt occurred we have to clean up the queue
-	 */
-	if (timeout && jiffies_left == 0)
-		error = -EAGAIN;
-	remove_from_queue(sma,&queue);
-	goto out_unlock_free;
+	error = alloc_semundo(sma, &un, alter);
+	if (error)
+		return ERR_PTR(error);
 
-out_unlock_free:
-	sem_unlock(sma);
-out_free:
-	if(sops != fast_sops)
-		kfree(sops);
-	return error;
+	return un;
 }
 
 int undocheck(struct sembuf* sops,int semid, int nsops)
@@ -1632,7 +1511,7 @@
 
 	for (sop = sops; sop < sops + nsops; sop++) {
 		if (sop->sem_flg & SEM_UNDO)
-		undos++;
+			undos++;
 	}
 
 	if (undos) {
@@ -1661,64 +1540,95 @@
 
 	for (up = &undo_list->proc_list; (u = *up); *up = u->proc_next, kfree(u));
 }
+
+int
+ssi_semtimedop(
+	int semid,
+	struct sembuf __user *tsops,
+	unsigned nsops,
+	const struct timespec __user *timeout,
+	int *error)
+{
+	ssi_procstate_t pstate;
+	ics_userbuf_t utsops;
+	ics_userbuf_t utimeout;
+	clusternode_t svr_node;
+	int status, rval;
+
+	svr_node = sem_get_svr_node(semid);
+	if (!svr_node) {
+namesvr_op_go:
+		svr_node = sem_find_svr_node(semid);
+		if (!svr_node) {
+			*error = -EINVAL;
+			return 0;
+		}
+		sem_set_svr_node(semid, svr_node);
+	}
+	if (svr_node == this_node)
+		return -ESRCH;
+
+	ssi_procstate_get(&pstate);
+	ics_userbuf_set(&utsops, tsops, nsops * sizeof(*tsops));
+	ics_userbuf_set(&utimeout, timeout, sizeof(*timeout));
+retry:
+	status = cli_ripc_semop(svr_node, &rval, semid, nsops,
+		       &pstate, &utsops, &utimeout);
+	if (status) {
+		if (status != -EREMOTE) {
+			idelay(HZ/10);
+			goto retry;
+		}
+		sem_set_svr_node(semid, 0);
+		goto namesvr_op_go;
+	}
+	*error = rval;
+	return 0;
+}
 #endif /* CONFIG_SSI */
 
 asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
 			unsigned nsops, const struct timespec __user *timeout)
 {
-	int error = -EINVAL;
 #ifdef CONFIG_SSI
-	clusternode_t svr_node;
-#else
+	int error;
+
+	if (nsops < 1 || semid < 0)
+		return -EINVAL;
+	if (nsops > sc_semopm)
+		return -E2BIG;
+
+	if (ssi_semtimedop(semid, tsops, nsops, timeout, &error))
+		error = ssi_semop(semid, tsops, nsops, timeout);
+	if(!error)
+		undocheck(tsops, semid, nsops);
+	return error;
+}
+
+long ssi_semop(int semid, struct sembuf *tsops, unsigned nsops,
+		const struct timespec *timeout)
+{
+#endif /* CONFIG_SSI */
+	int error = -EINVAL;
 	struct sem_array *sma;
 	struct sembuf fast_sops[SEMOPM_FAST];
 	struct sembuf* sops = fast_sops, *sop;
+#ifdef CONFIG_SSI
+	struct sem_semundo *un;
+#else
 	struct sem_undo *un;
+#endif
 	int undos = 0, decrease = 0, alter = 0, max;
 	struct sem_queue queue;
 	unsigned long jiffies_left = 0;
-#endif /* CONFIG_SSI */
 
+#ifndef CONFIG_SSI
 	if (nsops < 1 || semid < 0)
 		return -EINVAL;
 	if (nsops > sc_semopm)
 		return -E2BIG;
+#endif /* !CONFIG_SSI */
 
-#ifdef CONFIG_SSI
-namesvr_op_go:
-	svr_node = sem_get_svr_node(semid);
-	if (!svr_node) {
-		svr_node = sem_find_svr_node(semid);
-		if (!svr_node)
-			return -EINVAL;
-		sem_set_svr_node(semid, svr_node);
-	}
-	if (svr_node != this_node) {
-		ssi_procstate_t pstate;
-		ics_userbuf_t utsops;
-		ics_userbuf_t utimeout;
-		int status;
-
-		ssi_procstate_get(&pstate);
-		ics_userbuf_set(&utsops, tsops, nsops * sizeof(*tsops));
-		ics_userbuf_set(&utimeout, timeout, sizeof(*timeout));
-
-		status = cli_ripc_semop(svr_node, &error, semid, nsops,
-			       &pstate, &utsops, &utimeout);
-		if (status) {
-			sem_set_svr_node(semid, 0);
-			idelay(HZ/10);
-			goto namesvr_op_go;
-		}
-		if (!error)
-			undocheck(tsops, semid, nsops);
-	} else {
-		error = ssi_semop(semid, tsops, nsops, timeout);
-		if(!error)
-			undocheck(tsops, semid, nsops);
-	}
-	return error;
-#else /* CONFIG_SSI */
 	if(nsops > SEMOPM_FAST) {
 		sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
 		if(sops==NULL)
@@ -1754,6 +1664,7 @@
 	}
 	alter |= decrease;
 
+#ifndef CONFIG_SSI
 retry_undos:
 	if (undos) {
 		un = find_undo(semid);
@@ -1763,6 +1674,7 @@
 		}
 	} else
 		un = NULL;
+#endif /* !CONFIG_SSI */
 
 	sma = sem_lock(semid);
 	error=-EINVAL;
@@ -1771,6 +1683,17 @@
 	error = -EIDRM;
 	if (sem_checkid(sma,semid))
 		goto out_unlock_free;
+#ifdef CONFIG_SSI
+	if (undos) {
+		un = ssi_find_undo(sma, alter);
+		if (IS_ERR(un)) {
+			error = PTR_ERR(un);
+			goto out_free;
+		}
+	} else
+		un = NULL;
+	/* SSI: there is no un->semid. sem_lock must be held throughout */
+#else /* CONFIG_SSI */
 	/*
 	 * semid identifies are not unique - find_undo may have
 	 * allocated an undo structure, it was invalidated by an RMID
@@ -1780,6 +1703,7 @@
 		sem_unlock(sma);
 		goto retry_undos;
 	}
+#endif /* !CONFIG_SSI */
 	error = -EFBIG;
 	if (max >= sma->sem_nsems)
 		goto out_unlock_free;
@@ -1866,7 +1790,6 @@
 	if(sops != fast_sops)
 		kfree(sops);
 	return error;
-#endif /* !CONFIG_SSI */
 }
 
 asmlinkage long sys_semop (int semid, struct sembuf __user *tsops, unsigned nsops)
@@ -1930,12 +1853,14 @@
 	return svr_node;
 }
 
+/* Called with sem_array locked */
 static inline void __ssi_semexit(int semid, pid_t pid, struct sem_array *sma)
 {
 	struct sem_semundo *un, **unp;
 	int nsems, i;
 
 	if (sem_checkid(sma, semid)) {
+		sem_unlock(sma);
 		/* [ ssic-linux-Bugs-1941808 ] semundo structures confused.
 		 * sem_checkid() failure here is not a bug because in OpenSSI
 		 * tsk->sysvsem.undo_list (struct sem_undo) is separated from
@@ -1945,21 +1870,24 @@
 		 */
 		printk(KERN_DEBUG "%s: stale undo sem %d for pid %d\n",
 					__FUNCTION__, semid, pid);
-		goto out_unlock;
+		return;
 	}
 
 	/* remove u from the sma->undo list */
 	for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
 		/* u == un */
-		if (pid == un->pid)
-			goto found;
+		if (pid == un->pid) {
+			*unp = un->id_next;
+			break;
+		}
+	}
+	if (!un) {
+		sem_unlock(sma);
+		printk(KERN_WARNING "%s: missing undo sem %d for pid %d\n",
+					__FUNCTION__, semid, pid);
+		return;
 	}
-	printk(KERN_WARNING "%s: missing undo sem %d for pid %d\n",
-				__FUNCTION__, semid, pid);
-	goto out_unlock;
 
-found:
-	*unp = un->id_next;
 	/* perform adjustments registered in u */
 	nsems = sma->sem_nsems;
 	for (i = 0; i < nsems; i++) {
@@ -1989,13 +1917,25 @@
 	sma->sem_otime = get_seconds();
 	/* maybe some queued-up processes were waiting for this */
 	update_queue(sma);
+	sem_unlock(sma);
 
 	/* Unlike base code we must free our sem_semundo, no-one else will
 	   do it for us */
 	kfree (un);
+}
 
-out_unlock:
-	sem_unlock(sma);
+void ssi_semexit(int semid, pid_t pid)
+{
+	struct sem_array *sma;
+
+	if(semid == -1)
+		return;
+
+	sma = sem_lock(semid);
+	if (sma == NULL)
+		return;
+
+	__ssi_semexit(semid, pid, sma);
 }
 #endif /* CONFIG_SSI */
 
@@ -2045,11 +1985,16 @@
 
 		if (svr_node != this_node) {
 			ssi_procstate_t pstate;
-			int rval;
+			int status, rval;
 
 			ssi_procstate_get(&pstate);
-			cli_ripc_semexit(svr_node, &rval, &pstate,
+retry:
+			status = cli_ripc_semexit(svr_node, &rval, &pstate,
 						u->semid, current->tgid);
+			if (status && status != -EREMOTE) {
+				idelay(HZ/10);
+				goto retry;
+			}
 			/* Ignoring -EREMOTE */
 		} else
 			ssi_semexit(u->semid, current->tgid);
@@ -2258,19 +2203,6 @@
 #endif
 
 #ifdef CONFIG_SSI
-void ssi_semexit(int semid, pid_t pid)
-{
-	struct sem_array *sma;
-       
-	if(semid == -1)
-		return;
-	sma = sem_lock(semid);
-	if (sma == NULL)
-		return;
-
-	__ssi_semexit(semid, pid, sma);
-}
-
 /* Go thru the sem_semundo structures; for each pid in there, see if it
  * is dead, and if dead undo the semaphore operations.
  */
@@ -2293,7 +2225,7 @@
 	 * existing semaphores at the time of node down event.
 	 */
 	/* SMP safe because sem_ids.entries->size does not shrink */
-	down(&sem_ids.sem);
+	down(&sem_ids.sem); /* ensure existing operations are done */
 	max_id = sem_ids.entries->size;
 	up(&sem_ids.sem);
 


------------------------------------------------------------------------------
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