[S390] appldata: avoid deadlock with appldata_mem
authorGerald Schaefer <gerald.schaefer@de.ibm.com>
Thu, 23 Apr 2009 11:58:07 +0000 (13:58 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 23 Apr 2009 11:58:17 +0000 (13:58 +0200)
The appldata_ops callbacks are called with a spin_lock held. But the
appldata_mem callback then calls all_vm_events(), which calls
get_online_cpus(), which might sleep. This possible deadlock is fixed
by using a mutex instead of a spin_lock.

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/appldata/appldata_base.c
arch/s390/appldata/appldata_mem.c

index aeb3cff95f63a42a638195ab4db7da74b894661c..1dfc7100c7ee358cb0a0e131b43d36145f64a6fd 100644 (file)
@@ -98,7 +98,7 @@ static DECLARE_WORK(appldata_work, appldata_work_fn);
 /*
  * Ops list
  */
-static DEFINE_SPINLOCK(appldata_ops_lock);
+static DEFINE_MUTEX(appldata_ops_mutex);
 static LIST_HEAD(appldata_ops_list);
 
 
@@ -129,14 +129,14 @@ static void appldata_work_fn(struct work_struct *work)
 
        i = 0;
        get_online_cpus();
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        list_for_each(lh, &appldata_ops_list) {
                ops = list_entry(lh, struct appldata_ops, list);
                if (ops->active == 1) {
                        ops->callback(ops->data);
                }
        }
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
        put_online_cpus();
 }
 
@@ -338,7 +338,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
        struct list_head *lh;
 
        found = 0;
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        list_for_each(lh, &appldata_ops_list) {
                tmp_ops = list_entry(lh, struct appldata_ops, list);
                if (&tmp_ops->ctl_table[2] == ctl) {
@@ -346,15 +346,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                }
        }
        if (!found) {
-               spin_unlock(&appldata_ops_lock);
+               mutex_unlock(&appldata_ops_mutex);
                return -ENODEV;
        }
        ops = ctl->data;
        if (!try_module_get(ops->owner)) {      // protect this function
-               spin_unlock(&appldata_ops_lock);
+               mutex_unlock(&appldata_ops_mutex);
                return -ENODEV;
        }
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
 
        if (!*lenp || *ppos) {
                *lenp = 0;
@@ -378,11 +378,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                return -EFAULT;
        }
 
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        if ((buf[0] == '1') && (ops->active == 0)) {
                // protect work queue callback
                if (!try_module_get(ops->owner)) {
-                       spin_unlock(&appldata_ops_lock);
+                       mutex_unlock(&appldata_ops_mutex);
                        module_put(ops->owner);
                        return -ENODEV;
                }
@@ -407,7 +407,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                               "failed with rc=%d\n", ops->name, rc);
                module_put(ops->owner);
        }
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
 out:
        *lenp = len;
        *ppos += len;
@@ -433,9 +433,9 @@ int appldata_register_ops(struct appldata_ops *ops)
        if (!ops->ctl_table)
                return -ENOMEM;
 
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        list_add(&ops->list, &appldata_ops_list);
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
 
        ops->ctl_table[0].procname = appldata_proc_name;
        ops->ctl_table[0].maxlen   = 0;
@@ -452,9 +452,9 @@ int appldata_register_ops(struct appldata_ops *ops)
                goto out;
        return 0;
 out:
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        list_del(&ops->list);
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
        kfree(ops->ctl_table);
        return -ENOMEM;
 }
@@ -466,9 +466,9 @@ out:
  */
 void appldata_unregister_ops(struct appldata_ops *ops)
 {
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        list_del(&ops->list);
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
        unregister_sysctl_table(ops->sysctl_header);
        kfree(ops->ctl_table);
 }
index 3ed56b7d1b2f3d1cf8b68eb274e9fab40b012080..4188cbe63a54a954e232a0d5d0dd5f9d4441dc32 100644 (file)
@@ -78,7 +78,7 @@ static void appldata_get_mem_data(void *data)
 {
        /*
         * don't put large structures on the stack, we are
-        * serialized through the appldata_ops_lock and can use static
+        * serialized through the appldata_ops_mutex and can use static
         */
        static struct sysinfo val;
        unsigned long ev[NR_VM_EVENT_ITEMS];