[SSI] openssi/kernel/cluster/ssi/vproc dvp_move.c,1.15,1.16

Roger Tsang <[email protected]>
Newsgroups gmane.linux.cluster.ssic.cvs
Message-ID <[email protected]>
Update of /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/vproc
In directory fdv4jf1.ch3.sourceforge.com:/tmp/cvs-serv4775/cluster/ssi/vproc

Modified Files:
      Tag: OPENSSI-FC
	dvp_move.c 
Log Message:
VPROC:
- Fix get_move_data() race with put_move_data().
- Fix struct move_data reference count bug in the following:
  - task_struct->execnode
  - rvp_remote_args->migrate_args.data
  - move_data->m_threadlist
  - move_data->m_list


Index: dvp_move.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/vproc/dvp_move.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- dvp_move.c	27 Oct 2009 03:18:29 -0000	1.15
+++ dvp_move.c	2 Nov 2009 03:45:33 -0000	1.16
@@ -152,12 +152,10 @@
 		set_mb(h->mh_state, new_state);
 		wake_up_all(&h->mh_wqh);
 	} else if (state != PM_ABORT && function) {
-		/* spin_unlock(&h->mh_lock); */
 		printk(KERN_WARNING
 		       "%s, line %d:header (id %d) in bad state,"
 		       " expected %d, seen %d\n",
 		       function, line, h->mh_id, expected_state, state);
-		/* spin_lock(&h->mh_lock); */
 	}
 
 	return error;
@@ -181,16 +179,14 @@
 	state = d->m_state;
 	if (state == expected_state) {
 		h->mh_done += incr;
-		set_mb(d->m_state, new_state);
+		d->m_state = new_state;
 		error = ((h->mh_done == h->mh_wanted) ? 1 : 0);
 	} else if (state != PM_ABORT && function) {
-		/* spin_unlock(&h->mh_lock); */
 		printk(KERN_WARNING
 		       "%s, line %d:data (id %d pid %d) in bad state,"
 		       " expected %d, seen %d\n",
 		       function, line, h->mh_id, d->m_pid,
 		       expected_state, state);
-		/* spin_lock(&h->mh_lock); */
 	}
 
 	return error;
@@ -239,6 +235,7 @@
 }
 #endif /* !VPROC_RCU_MOVEMENT_LIST */
 
+/* Caller holds reference to move_header */
 static inline struct move_header *
 get_move_header(struct move_header *h)
 {
@@ -279,16 +276,26 @@
 #endif
 }
 
+/* Caller holds reference to move_data */
 static inline struct move_data *
 get_move_data(struct move_data *d)
 {
-	if (d) {
-		BUG_ON(d->m_magic != ((u_long)&d->m_magic) + 1);
-		atomic_inc(&d->m_refcnt);
-	}
+	BUG_ON(d->m_magic != ((u_long)&d->m_magic) + 1);
+	atomic_inc(&d->m_refcnt);
 	return d;
 }
 
+/* Called under movement_list_lock */
+static inline struct move_data *
+__get_move_data(struct move_data *d)
+{
+	if (!d)
+		return NULL;
+	if (!d->m_magic)
+		return NULL; /* Lost race with free_move_data() */
+	return get_move_data(d);
+}
+
 /* Might acquire movement_list_lock, mh_lock */
 static void
 put_move_data(struct move_data *d)
@@ -300,12 +307,13 @@
 		panic("%s:move_data %p has invalid magic number %p\n",
 		      __FUNCTION__, d, (void *)d->m_magic);
 	BUG_ON(!atomic_read(&d->m_refcnt));
-	if (atomic_dec_and_test(&d->m_refcnt))
+	if (atomic_dec_and_lock(&d->m_refcnt, &movement_list_lock))
 		free_move_data(d);
 }
 
 /* Called under movement_list_lock.
  * Returns with movement_list_lock unlocked.
+ * Might acquire mh_lock.
  */
 static void
 clear_task_execnode(struct task_struct *p, struct move_data *d)
@@ -317,22 +325,29 @@
 		spin_unlock(&movement_list_lock);
 		goto out;
 	}
+
 	p->execnode = NULL;
 	h = d->m_mhp;
+
 	spin_lock(&h->mh_lock);
+
 	if (d->m_taskp != p)
 		panic("%s:move_data %p m_taskp %p != %p\n",
 		      __FUNCTION__, d, d->m_taskp, p);
+	put_task_struct(d->m_taskp);
 	d->m_taskp = NULL;
-	state = d->m_state;
+
 	spin_unlock(&movement_list_lock);
+
+	state = d->m_state;
+
 	if (list_empty(&d->m_list)) {
 		spin_unlock(&h->mh_lock);
-		/* drop_move_data() skipped put_move_data() */
-		put_move_data(d); /* for p->execnode */
+		put_move_data(d); /* active */
 	} else
 		spin_unlock(&h->mh_lock);
-	put_task_struct(p); /* for d->m_taskp */
+
+	put_move_data(d); /* for p->execnode */
 
 	switch (state) {
 	case PM_NOTIFIED:
@@ -351,6 +366,7 @@
 	drop_move_data(d);
 }
 
+/* Might acquire mh_lock */
 void
 ssi_clear_task_execnode(struct task_struct *p)
 {
@@ -361,10 +377,11 @@
 	if (!(d = p->execnode))
 		return;
 	spin_lock(&movement_list_lock);
-	clear_task_execnode(p, get_move_data(d));
+	clear_task_execnode(p, __get_move_data(d));
 	put_move_data(d);
 }
 
+/* Might acquire mh_lock */
 static void
 move_data_clear_execnode(struct move_data *d)
 {
@@ -443,11 +460,15 @@
 	return d;
 }
 
-/* Might acquire movement_list_lock, mh_lock */
+/* Called under movement_list_lock */
+/* Returns with movement_list_lock unlocked */
+/* Might acquire mh_lock */
 static void
 free_move_data(struct move_data *d)
 {
 	d->m_magic = 0;
+	spin_unlock(&movement_list_lock);
+
 	if (d->m_taskp)
 		panic("%s:move_data %p freed with m_taskp %p set\n",
 		      __FUNCTION__, d, d->m_taskp);
@@ -467,8 +488,11 @@
 	struct move_header *h = d->m_mhp;
 
 	if (!list_empty(&d->m_list)) {
+		/* Remove from mh_datalist */
 		list_del_init(&d->m_list);
+
 		h->mh_total--;
+
 		if (d->m_state == PM_NOTIFIED) {
 			h->mh_wanted--;
 			if (h->mh_done == h->mh_wanted)
@@ -476,12 +500,12 @@
 							      PM_QUIESCED,
 							      NULL, 0);
 		}
-		return (!d->m_taskp);
+		return (!d->m_taskp); /* whether clear_task_execnode() ran */
 	}
 	return 0;
 }
 
-/* Might acquire movement_list_lock */
+/* Might acquire movement_list_lock, mh_lock */
 static void
 drop_move_data(struct move_data *d)
 {
@@ -491,21 +515,24 @@
 	if (d && !list_empty(&d->m_list)) {
 		h = d->m_mhp;
 		spin_lock(&h->mh_lock);
+
 		do_drop = __drop_move_data(d);
 		spin_unlock(&h->mh_lock);
+
 		if (do_drop)
-			put_move_data(d); /* for p->execnode */
+			put_move_data(d); /* active */
 	}
 }
 
+/* Called under mh_lock */
 static void
 __set_state_datalist(struct move_header *h, enum move_state state)
 {
 	struct move_data *d;
 
-	set_mb(h->mh_state, state);
+	h->mh_state = state;
 	list_for_each_entry(d, &h->mh_datalist, m_list) {
-		set_mb(d->m_state, state);
+		d->m_state = state;
 	}
 }
 
@@ -515,6 +542,7 @@
 {
 	struct move_data *d;
 
+	smp_mb(); /* ensure all CPU's see new state */
 	while (!list_empty(&h->mh_datalist)) {
 		d = list_entry(h->mh_datalist.next, struct move_data, m_list);
 		get_move_data(d);
@@ -588,20 +616,22 @@
 	return h;
 }
 
+/* Acquires mh_lock */
 static int
 cancel_move_out(struct move_header *h, struct move_data *d, int error)
 {
 	enum move_state state;
 
 	spin_lock(&h->mh_lock);
+
 	if (d) {
 		if (d->m_state == PM_MIGRATE_OUT_START)
 			(void)set_move_both_states(d, PM_MIGRATE_OUT,
 						   PM_MIGRATE_OUT_START,
 						   PM_MIGRATE_OUT_DONE);
 	}
+
 	state = h->mh_state;
-	/* spin_unlock(&h->mh_lock); */
 	switch (state) {
 	case PM_NOTIFIED:
 	case PM_QUIESCED:
@@ -614,7 +644,9 @@
 		       __FUNCTION__, state);
 		/*FALLTHROUGH*/
 	case PM_MIGRATE_OUT:
-		(void)move_header_wait_for_state_change(h, state);
+		spin_unlock(&h->mh_lock);
+		(void) move_header_wait_for_state_change(h, state);
+		spin_lock(&h->mh_lock);
 		break;
 	default:
 		printk(KERN_WARNING
@@ -622,17 +654,22 @@
 		       __FUNCTION__, state);
 		break;
 	}
-	/* spin_lock(&h->mh_lock); */
+
 	if (h->mh_aborting)
 		goto out;
+
 	h->mh_aborting = 1;
+
 	if (!h->mh_error || (h->mh_error > 0 && error < 0))
 		h->mh_error = error;
+
 	__set_state_datalist(h, PM_ABORT);
 	__free_move_datalist(h);
 out:
 	error = h->mh_error;
 	spin_unlock(&h->mh_lock);
+
+	smp_mb(); /* ensure all CPU's see new state */
 	wake_up_all(&h->mh_wqh);
 
 	return error;
@@ -650,26 +687,27 @@
 	enum move_state state;
 
 	spin_lock(&movement_list_lock);
-	d = get_move_data(p->execnode);
+	d = __get_move_data(p->execnode);
 	spin_unlock(&movement_list_lock);
 	if (!d)
 		return -EINVAL;
 
 	h = d->m_mhp;
 
-	smp_mb(); /* barrier for mh_state */
+	spin_lock(&h->mh_lock);
+
 	if (check_move_header_state(h, h->mh_state, PM_NOTIFIED)) {
+		spin_unlock(&h->mh_lock);
 		error = -EINVAL;
 		goto out;
 	}
 
-	spin_lock(&h->mh_lock);
 	error = set_move_data_state(d, PM_NOTIFIED, PM_QUIESCED, 1);
 	if (error > 0) {
-		spin_unlock(&h->mh_lock);
-
 		node = h->mh_dstnode;
 		if (node == CLUSTERNODE_BEST) {
+			spin_unlock(&h->mh_lock);
+
 			(void)VPOP_SELECT_NODE(p->p_vproc, NSC_COMM(p), &node);
 			select_node = 1;
 			if (node == this_node || node == CLUSTERNODE_INVAL) {
@@ -680,13 +718,12 @@
 				put_move_data(d);
 				return error;
 			}
+
+			spin_lock(&h->mh_lock);
 			h->mh_dstnode = node;
 		}
 
-		spin_lock(&h->mh_lock);
 		error = set_move_header_state(h, PM_NOTIFIED, PM_QUIESCED);
-		spin_unlock(&h->mh_lock);
-
 	} else if (d->m_state == PM_CONTINUE) {
 		spin_unlock(&h->mh_lock);
 
@@ -695,6 +732,7 @@
 		return 0;
 	}
 
+	spin_unlock(&h->mh_lock);
 	if (error < 0)
 		goto out;
 
@@ -747,6 +785,7 @@
 		error = set_move_both_states(d, PM_DESTROY, PM_DESTROY,
 					     PM_DESTROY_DONE);
 		spin_unlock(&h->mh_lock);
+
 		put_move_data(d);
 		p->group_leader = p;	/* prevent report state */
 		pproc_cleanup_process();
@@ -836,6 +875,7 @@
 		leader = p->tgid;
 	else
 		leader = -p->pid;
+
 	read_lock(&tasklist_lock);
 #ifdef VPROC_MIGRATE_THREAD_GROUP_FIX
 	t = p;
@@ -850,6 +890,7 @@
 	}
 #endif
 	read_unlock(&tasklist_lock);
+
 	for (;;) {
 		if (!count)
 			break;
@@ -857,6 +898,7 @@
 		if (!pidp)
 			return -ENOMEM;
 		i = 0;
+
 		read_lock(&tasklist_lock);
 #ifdef VPROC_MIGRATE_THREAD_GROUP_FIX
 		t = p;
@@ -917,10 +959,12 @@
 			i++;
 		}
 		read_unlock(&tasklist_lock);
+
 		if (i <= count) {
 			count = i;
 			break;
 		}
+
 		kfree(pidp);
 		count = i;
 		yield();
@@ -936,8 +980,11 @@
 			retval += tmpret;
 	}
 	kfree(pidp);
-	smp_mb(); /* barrier for mh_state */
+
+	spin_lock(&h->mh_lock);
 	if (h->mh_state == PM_QUIESCED && retval == 0) {
+		spin_unlock(&h->mh_lock);
+
 		count++;
 #ifndef VPROC_MIGRATE_THREAD_GROUP_FIX
 		if (atomic_read(&p->mm->mm_users) != count ||
@@ -956,9 +1003,11 @@
 		if (leader > 0) {
 			tcount = 1;
 			t = p;
+
 			read_lock(&tasklist_lock);
 			while_each_thread(p, t) tcount++;
 			read_unlock(&tasklist_lock);
+
 			if (tcount != count) {
 				printk(KERN_DEBUG
 				       "%s: group(%d)/share imbalance %d/%d\n",
@@ -980,11 +1029,15 @@
 			}
 #endif
 		}
-	}
+	} else
+		spin_unlock(&h->mh_lock);
 
 	return retval;
 }
 
+/* Might acquire movement_list_lock, mh_lock */
+/* Might acquire task_lock */
+/* Might acquire read tasklist_lock */
 static int
 setup_pid_move(struct move_header *h, pid_t pid, pid_t leader)
 {
@@ -1056,18 +1109,20 @@
 		return -EAGAIN;
 	}
 	p->execnode = get_move_data(d);
-	get_task_struct(p); /* for m_taskp */
 
 	spin_lock(&h->mh_lock);
 
+	get_task_struct(p);
 	d->m_taskp = p;
+
+	get_move_data(d);
 	list_add_tail(&d->m_list, &h->mh_datalist);
+
 	h->mh_wanted = ++(h->mh_total);
-	smp_mb();
 	if (h->mh_state == PM_QUIESCED)
-		set_mb(h->mh_state, PM_NOTIFIED);
-
+		h->mh_state = PM_NOTIFIED;
 	spin_unlock(&h->mh_lock);
+
 	spin_unlock(&movement_list_lock);
 
 	if ((h->mh_type & MOV_SIGMIG) || p != current) {
@@ -1075,9 +1130,11 @@
 		spin_lock_irqsave(&p->sighand->siglock, flags);
 		set_tsk_thread_flag(p, TIF_MIGPENDING);
 		/* Does the task have all signals blocked? */
-		if (has_pending_signals(&fillset, &p->blocked))
+		if (has_pending_signals(&fillset, &p->blocked)) {
 			/* No: wake it up. */
+			smp_mb(); /* ensure all CPU's see new state */
 			signal_wake_up(p, 0);
+		}
 		spin_unlock_irqrestore(&p->sighand->siglock, flags);
 	}
  already_done:
@@ -1168,15 +1225,16 @@
 {
 	struct move_header *h = (void *)arg;
 
-	h->mh_timeout = 1;
+	set_mb(h->mh_timeout, 1);
 	wake_up_all(&h->mh_wqh);
 }
 
+/* Acquires mh_lock */
+/* Might acquire movement_list_lock */
 static int
 check_move_list(struct move_header *h)
 {
-	int retval;
-	int do_drop;
+	int retval, do_drop;
 
 	struct move_data *d, *next;
 	LIST_HEAD(unseen_list);
@@ -1193,25 +1251,30 @@
 		retval = setup_pid_move(h, h->mh_id, 0);
 
 	spin_lock(&h->mh_lock);
+
 	list_for_each_entry_safe(d, next, &h->mh_datalist, m_list) {
-		if (!d->m_seen)
-			list_move(&d->m_list, &unseen_list);
+		if (d->m_seen)
+			continue;
+		list_move(&d->m_list, &unseen_list);
 	}
 	while (!list_empty(&unseen_list)) {
 		d = list_entry(unseen_list.next, struct move_data, m_list);
+		get_move_data(d); /* temp */
 		do_drop = __drop_move_data(d);
 		set_mb(d->m_state, PM_CONTINUE);
 		spin_unlock(&h->mh_lock);
 
 		wake_up_all(&d->m_wqh);
 		if (do_drop)
-			put_move_data(d);
+			put_move_data(d); /* active */
+		put_move_data(d); /* temp */
 		spin_lock(&h->mh_lock);
 	}
-	smp_mb();
+
 	if (!retval && h->mh_state == PM_NOTIFIED &&
 	    h->mh_done == h->mh_wanted)
 		retval = set_move_header_state(h, PM_NOTIFIED, PM_QUIESCED);
+
 	spin_unlock(&h->mh_lock);
 
 	return retval;
@@ -1221,9 +1284,17 @@
 move_header_wait_for_state_change(struct move_header *h,
 				  enum move_state expected_state)
 {
-	struct task_struct *p = current;
 	enum move_state state;
 	sigset_t saved_blocked;
+
+	might_sleep();
+
+	ssi_block_signals(current, &saved_blocked);
+	wait_event_interruptible(h->mh_wqh,
+			(state = h->mh_state) != expected_state || h->mh_timeout);
+	ssi_unblock_signals(current, &saved_blocked);
+#if 0
+	struct task_struct *p = current;
 	DECLARE_WAITQUEUE(wq, p);
 
 	ssi_block_signals(p, &saved_blocked);
@@ -1238,7 +1309,7 @@
 	set_task_state(p, TASK_RUNNING);
 	remove_wait_queue(&h->mh_wqh, &wq);
 	ssi_unblock_signals(p, &saved_blocked);
-
+#endif
 	return state;
 }
 
@@ -1247,8 +1318,16 @@
 				enum move_state expected_state)
 {
 	enum move_state state;
-	struct task_struct *p = current;
 	sigset_t saved_blocked;
+
+	might_sleep();
+
+	ssi_block_signals(current, &saved_blocked);
+	wait_event_interruptible_exclusive(d->m_wqh,
+				(state = d->m_state) != expected_state);
+	ssi_unblock_signals(current, &saved_blocked);
+#if 0
+	struct task_struct *p = current;
 	DECLARE_WAITQUEUE(wq, p);
 
 	ssi_block_signals(p, &saved_blocked);
@@ -1263,7 +1342,7 @@
 	set_task_state(p, TASK_RUNNING);
 	remove_wait_queue(&d->m_wqh, &wq);
 	ssi_unblock_signals(p, &saved_blocked);
-
+#endif
 	return state;
 }
 
@@ -1293,6 +1372,7 @@
 	h->mh_wanted = i;
 	spin_unlock(&h->mh_lock);
 
+	smp_mb(); /* ensure all CPU's see new state */
 	for (i = i - 1; i >= 0; i--)
 		wake_up_all(&data_list[i]->m_wqh);
 
@@ -1360,19 +1440,21 @@
 			break;
 	}
 
+	spin_lock(&h->mh_lock);
 	total = h->mh_total;
+	spin_unlock(&h->mh_lock);
 	if (total == 0)
 		goto out;
 
 	/* XXX objects */
 
-	proc_list = kmalloc(sizeof(*proc_list) * total, GFP_USER);
+	proc_list = kzmalloc(sizeof(*proc_list) * total, GFP_KERNEL);
 	if (!proc_list) {
 		error = -ENOMEM;
 		goto out;
 	}
 
-	data_list = kmalloc(sizeof(*data_list) * total, GFP_USER);
+	data_list = kzmalloc(sizeof(*data_list) * total, GFP_KERNEL);
 	if (!data_list) {
 		kfree(proc_list);
 		error = -ENOMEM;
@@ -1382,6 +1464,7 @@
 	i = 0;
 	leaders = 0;
 	j = total;
+
 	spin_lock(&h->mh_lock);
 	list_for_each_entry(d, &h->mh_datalist, m_list) {
 		proc_list[i++] = d->m_pid;
@@ -1393,6 +1476,7 @@
 	spin_unlock(&h->mh_lock);
 
 	SSI_ASSERT(i == total);
+	BUG_ON(i > total);
 
 	ret = RVP_MOVE_IN_SETUP(h->mh_dstnode, &error, h->mh_type, h->mh_id,
 				proc_list, total, this_node);
@@ -1594,6 +1678,7 @@
 	}
 
 	spin_lock(&h->mh_lock);
+
 	state = h->mh_state;
 	if (state == PM_QUIESCED) {
 		h->mh_done = 0;
@@ -1609,25 +1694,26 @@
 			       state);
 		goto out;
 	}
+
 	d = __find_move_data(h, args->childpid);
 	if (d) {
 		retval = set_move_data_state(d, PM_QUIESCED,
 					     PM_MIGRATE_IN_START, 0);
 		if (retval >= 0) {
 			h->mh_wanted++;
-			set_mb(h->mh_state, PM_MIGRATE_IN);
+			h->mh_state = PM_MIGRATE_IN;
 		}
-		spin_unlock(&h->mh_lock);
 	} else {
-		spin_unlock(&h->mh_lock);
 		printk(KERN_WARNING
 		       "%s:Cannot find movement data for id %d pid %d\n",
 		       __FUNCTION__, move_id, args->childpid);
 	}
+
+	spin_unlock(&h->mh_lock);
 	if (retval < 0)
 		goto out;
 
-	args->migrate_args.data = d;
+	args->migrate_args.data = get_move_data(d);
 	args->migrate_args.optype = RVP_MIGRATE;
 	if (!leader || leader == args->childpid) {
 		retval = rproc_create_proc(migrate_server_setup, args, 0, 0);
@@ -1648,11 +1734,14 @@
 #endif
 	else
 		leader = -leader;
-	l = find_move_data(h, leader);
-	if (!l)
-		goto out;
 
 	spin_lock(&h->mh_lock);
+	l = __find_move_data(h, leader);
+	if (!l) {
+		spin_unlock(&h->mh_lock);
+		goto out;
+	}
+
 	state = l->m_state;
 	if (state != PM_MIGRATE_IN_DONE && state != PM_MIGRATE_IN_THREAD) {
 		spin_unlock(&h->mh_lock);
@@ -1665,8 +1754,11 @@
 			       state);
 		goto out;
 	}
-	set_mb(l->m_state, PM_MIGRATE_IN_THREAD);
+	l->m_state = PM_MIGRATE_IN_THREAD;
+
+	get_move_data(d);
 	list_add_tail(&d->m_threadlist, &l->m_threadlist);
+
 	d->m_migargs  = args;
 	spin_unlock(&h->mh_lock);
 
@@ -1680,6 +1772,7 @@
 		retval = PTR_ERR(d->m_migargs);
 	} else {
 		list_del_init(&d->m_threadlist);
+		put_move_data(d);
 		retval = -EINVAL;
 	}
 	spin_unlock(&h->mh_lock);
@@ -1693,10 +1786,11 @@
 							   PM_MIGRATE_IN_START,
 							   PM_MIGRATE_IN_DONE);
 			spin_unlock(&h->mh_lock);
-			put_move_data(d);
+			put_move_data(d); /* migrate_args.data */
 		}
 	}
 	put_move_data(l);
+	put_move_data(d);
 	put_move_header(h);
 
 	return retval;
@@ -1712,6 +1806,7 @@
 	spin_lock(&movement_list_lock);
 	spin_lock(&h->mh_lock);
 	if (!p->execnode) {
+		get_move_data(d);
 		p->execnode = d;
 		get_task_struct(p);
 		d->m_taskp = p;
@@ -1722,11 +1817,14 @@
 					    PM_MIGRATE_IN, 0);
 	spin_unlock(&h->mh_lock);
 	spin_unlock(&movement_list_lock);
+
+	smp_mb(); /* ensure all CPU's see new state */
 	wake_up_all(&d->m_wqh);
 
 	return error;
 }
 
+/* Returns with move_data reference dropped */
 int
 move_update_state(struct move_data *d, int retval)
 {
@@ -1759,25 +1857,30 @@
 		if (!retval)
 			retval = ret;
 	}
+
 	for (;;) {
 		state = move_data_wait_for_state_change(d, PM_MIGRATE_IN_DONE);
 		if (state != PM_MIGRATE_IN_THREAD)
 			break;
 
 		spin_lock(&h->mh_lock);
+
 		while (d->m_state == PM_MIGRATE_IN_THREAD) {
 			if (list_empty(&d->m_threadlist)) {
 				set_mb(d->m_state, PM_MIGRATE_IN_DONE);
 				break;
 			}
+
 			t = list_entry(d->m_threadlist.next,
 				       struct move_data, m_threadlist);
-			(void) get_move_data(t);
+			/* get_move_data(t); */
 
 			list_del_init(&t->m_threadlist);
+
 			args = t->m_migargs;
 			t->m_migargs = NULL;
 			spin_unlock(&h->mh_lock);
+
 			ret = rproc_create_proc(migrate_server_setup, args,
 						args->migrate_args.clone_flags,
 						0);
@@ -1785,17 +1888,21 @@
 				free_ics_remotedata(args);
 
 				spin_lock(&h->mh_lock);
+
 				if (h->mh_error >= 0)
 					h->mh_error = ret;
 				t->m_migargs = ERR_PTR(ret);
+
 				(void)set_move_both_states(t, PM_MIGRATE_IN,
 							   PM_MIGRATE_IN_START,
 							   PM_MIGRATE_IN_DONE);
 				spin_unlock(&h->mh_lock);
 
+				smp_mb(); /* ensure all CPU's see new state */
 				wake_up_all(&t->m_wqh);
 			}
-			put_move_data(t);
+
+			put_move_data(t); /* m_threadlist */
 			spin_lock(&h->mh_lock);
 		}
 		spin_unlock(&h->mh_lock);


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.