[S390] appldata: avoid deadlock with appldata_mem

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>
This commit is contained in:
Gerald Schaefer 2009-04-23 13:58:07 +02:00 committed by Martin Schwidefsky
parent 3bd5f3ef29
commit b1ad171efa
2 changed files with 17 additions and 17 deletions

View file

@ -98,7 +98,7 @@ static DECLARE_WORK(appldata_work, appldata_work_fn);
/* /*
* Ops list * Ops list
*/ */
static DEFINE_SPINLOCK(appldata_ops_lock); static DEFINE_MUTEX(appldata_ops_mutex);
static LIST_HEAD(appldata_ops_list); static LIST_HEAD(appldata_ops_list);
@ -129,14 +129,14 @@ static void appldata_work_fn(struct work_struct *work)
i = 0; i = 0;
get_online_cpus(); get_online_cpus();
spin_lock(&appldata_ops_lock); mutex_lock(&appldata_ops_mutex);
list_for_each(lh, &appldata_ops_list) { list_for_each(lh, &appldata_ops_list) {
ops = list_entry(lh, struct appldata_ops, list); ops = list_entry(lh, struct appldata_ops, list);
if (ops->active == 1) { if (ops->active == 1) {
ops->callback(ops->data); ops->callback(ops->data);
} }
} }
spin_unlock(&appldata_ops_lock); mutex_unlock(&appldata_ops_mutex);
put_online_cpus(); put_online_cpus();
} }
@ -338,7 +338,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
struct list_head *lh; struct list_head *lh;
found = 0; found = 0;
spin_lock(&appldata_ops_lock); mutex_lock(&appldata_ops_mutex);
list_for_each(lh, &appldata_ops_list) { list_for_each(lh, &appldata_ops_list) {
tmp_ops = list_entry(lh, struct appldata_ops, list); tmp_ops = list_entry(lh, struct appldata_ops, list);
if (&tmp_ops->ctl_table[2] == ctl) { if (&tmp_ops->ctl_table[2] == ctl) {
@ -346,15 +346,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
} }
} }
if (!found) { if (!found) {
spin_unlock(&appldata_ops_lock); mutex_unlock(&appldata_ops_mutex);
return -ENODEV; return -ENODEV;
} }
ops = ctl->data; ops = ctl->data;
if (!try_module_get(ops->owner)) { // protect this function if (!try_module_get(ops->owner)) { // protect this function
spin_unlock(&appldata_ops_lock); mutex_unlock(&appldata_ops_mutex);
return -ENODEV; return -ENODEV;
} }
spin_unlock(&appldata_ops_lock); mutex_unlock(&appldata_ops_mutex);
if (!*lenp || *ppos) { if (!*lenp || *ppos) {
*lenp = 0; *lenp = 0;
@ -378,11 +378,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
return -EFAULT; return -EFAULT;
} }
spin_lock(&appldata_ops_lock); mutex_lock(&appldata_ops_mutex);
if ((buf[0] == '1') && (ops->active == 0)) { if ((buf[0] == '1') && (ops->active == 0)) {
// protect work queue callback // protect work queue callback
if (!try_module_get(ops->owner)) { if (!try_module_get(ops->owner)) {
spin_unlock(&appldata_ops_lock); mutex_unlock(&appldata_ops_mutex);
module_put(ops->owner); module_put(ops->owner);
return -ENODEV; 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); "failed with rc=%d\n", ops->name, rc);
module_put(ops->owner); module_put(ops->owner);
} }
spin_unlock(&appldata_ops_lock); mutex_unlock(&appldata_ops_mutex);
out: out:
*lenp = len; *lenp = len;
*ppos += len; *ppos += len;
@ -433,9 +433,9 @@ int appldata_register_ops(struct appldata_ops *ops)
if (!ops->ctl_table) if (!ops->ctl_table)
return -ENOMEM; return -ENOMEM;
spin_lock(&appldata_ops_lock); mutex_lock(&appldata_ops_mutex);
list_add(&ops->list, &appldata_ops_list); 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].procname = appldata_proc_name;
ops->ctl_table[0].maxlen = 0; ops->ctl_table[0].maxlen = 0;
@ -452,9 +452,9 @@ int appldata_register_ops(struct appldata_ops *ops)
goto out; goto out;
return 0; return 0;
out: out:
spin_lock(&appldata_ops_lock); mutex_lock(&appldata_ops_mutex);
list_del(&ops->list); list_del(&ops->list);
spin_unlock(&appldata_ops_lock); mutex_unlock(&appldata_ops_mutex);
kfree(ops->ctl_table); kfree(ops->ctl_table);
return -ENOMEM; return -ENOMEM;
} }
@ -466,9 +466,9 @@ int appldata_register_ops(struct appldata_ops *ops)
*/ */
void appldata_unregister_ops(struct appldata_ops *ops) void appldata_unregister_ops(struct appldata_ops *ops)
{ {
spin_lock(&appldata_ops_lock); mutex_lock(&appldata_ops_mutex);
list_del(&ops->list); list_del(&ops->list);
spin_unlock(&appldata_ops_lock); mutex_unlock(&appldata_ops_mutex);
unregister_sysctl_table(ops->sysctl_header); unregister_sysctl_table(ops->sysctl_header);
kfree(ops->ctl_table); kfree(ops->ctl_table);
} }

View file

@ -78,7 +78,7 @@ static void appldata_get_mem_data(void *data)
{ {
/* /*
* don't put large structures on the stack, we are * 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; static struct sysinfo val;
unsigned long ev[NR_VM_EVENT_ITEMS]; unsigned long ev[NR_VM_EVENT_ITEMS];