+++ /dev/null
-From: Russ Anderson <rja@sgi.com>
-Subject: ia64: cpe_migrate.ko causes deadlock.
-References: bnc#464676
-
-schedule_on_each_cpu() deadlocks when called from an event thread.
-Change cpe_migrate to use a kthread to avoid the problem.
-
-Signed-off-by: Russ Anderson <rja@sgi.com>
-Acked-by: Raymund Will <rw@suse.de>
-
----
- arch/ia64/kernel/cpe_migrate.c | 72 +++++++++++++++++++++++++++++++----------
- 1 file changed, 56 insertions(+), 16 deletions(-)
-
-Index: linux/arch/ia64/kernel/cpe_migrate.c
-===================================================================
---- linux.orig/arch/ia64/kernel/cpe_migrate.c 2009-01-09 11:37:47.130269369 -0600
-+++ linux/arch/ia64/kernel/cpe_migrate.c 2009-01-09 11:44:43.658280930 -0600
-@@ -22,6 +22,7 @@
- #include <linux/page-isolation.h>
- #include <linux/memcontrol.h>
- #include <linux/kobject.h>
-+#include <linux/kthread.h>
-
- #include <asm/page.h>
- #include <asm/system.h>
-@@ -40,12 +41,15 @@ static struct cpe_info cpe[CE_HISTORY_LE
- static int cpe_polling_enabled = 1;
- static int cpe_head;
- static int cpe_tail;
--static int work_scheduled;
- static int mstat_cannot_isolate;
- static int mstat_failed_to_discard;
- static int mstat_already_marked;
- static int mstat_already_on_list;
-
-+/* IRQ handler notifies this wait queue on receipt of an IRQ */
-+DECLARE_WAIT_QUEUE_HEAD(cpe_activate_IRQ_wq);
-+static DECLARE_COMPLETION(kthread_cpe_migrated_exited);
-+int cpe_active;
- DEFINE_SPINLOCK(cpe_migrate_lock);
-
- static void
-@@ -159,12 +163,12 @@ ia64_mca_cpe_move_page(u64 paddr, u32 no
- }
-
- /*
-- * ia64_mca_cpe_migrate
-- * The worker that does the actual migration. It pulls a
-- * physical address off the list and calls the migration code.
-+ * cpe_process_queue
-+ * Pulls the physical address off the list and calls the migration code.
-+ * Will process all the addresses on the list.
- */
--static void
--ia64_mca_cpe_migrate(struct work_struct *unused)
-+void
-+cpe_process_queue(void)
- {
- int ret;
- u64 paddr;
-@@ -192,10 +196,36 @@ ia64_mca_cpe_migrate(struct work_struct
- cpe_tail = 0;
-
- } while (cpe_tail != cpe_head);
-- work_scheduled = 0;
-+ return;
-+}
-+
-+inline int
-+cpe_list_empty(void)
-+{
-+ return (cpe_head == cpe_tail) && (!cpe[cpe_head].paddr);
-+}
-+
-+/*
-+ * kthread_cpe_migrate
-+ * kthread_cpe_migrate is created at module load time and lives
-+ * until the module is removed. When not active, it will sleep.
-+ */
-+static int
-+kthread_cpe_migrate(void *ignore)
-+{
-+ while (cpe_active) {
-+ /*
-+ * wait for work
-+ */
-+ (void)wait_event_interruptible(cpe_activate_IRQ_wq,
-+ (!cpe_list_empty() ||
-+ !cpe_active));
-+ cpe_process_queue(); /* process work */
-+ }
-+ complete(&kthread_cpe_migrated_exited);
-+ return 0;
- }
-
--static DECLARE_WORK(cpe_enable_work, ia64_mca_cpe_migrate);
- DEFINE_SPINLOCK(cpe_list_lock);
-
- /*
-@@ -227,10 +257,7 @@ cpe_setup_migrate(void *rec)
- if (ret < 0)
- return -EINVAL;
-
-- if ((cpe_head != cpe_tail) || (cpe[cpe_head].paddr != 0))
-- /*
-- * List not empty
-- */
-+ if (!cpe_list_empty())
- for (i = 0; i < CE_HISTORY_LENGTH; i++) {
- if (PAGE_ALIGN(cpe[i].paddr) == PAGE_ALIGN(paddr)) {
- mstat_already_on_list++;
-@@ -255,10 +282,7 @@ cpe_setup_migrate(void *rec)
- }
- spin_unlock(&cpe_list_lock);
-
-- if (!work_scheduled) {
-- work_scheduled = 1;
-- schedule_work(&cpe_enable_work);
-- }
-+ wake_up_interruptible(&cpe_activate_IRQ_wq);
-
- return 1;
- }
-@@ -395,12 +419,23 @@ static int __init
- cpe_migrate_external_handler_init(void)
- {
- int error;
-+ struct task_struct *kthread;
-
- error = sysfs_create_file(kernel_kobj, &badram_attr.attr);
- if (error)
- return -EINVAL;
-
- /*
-+ * set up the kthread
-+ */
-+ cpe_active = 1;
-+ kthread = kthread_run(kthread_cpe_migrate, NULL, "cpe_migrate");
-+ if (IS_ERR(kthread)) {
-+ complete(&kthread_cpe_migrated_exited);
-+ return -EFAULT;
-+ }
-+
-+ /*
- * register external ce handler
- */
- if (ia64_reg_CE_extension(cpe_setup_migrate)) {
-@@ -418,6 +453,11 @@ cpe_migrate_external_handler_exit(void)
- {
- /* unregister external mca handlers */
- ia64_unreg_CE_extension();
-+
-+ /* Stop kthread */
-+ cpe_active = 0; /* tell kthread_cpe_migrate to exit */
-+ wake_up_interruptible(&cpe_activate_IRQ_wq);
-+ wait_for_completion(&kthread_cpe_migrated_exited);
-
- sysfs_remove_file(kernel_kobj, &badram_attr.attr);
- }
-