diff options
author | Gerald Schaefer <gerald.schaefer@de.ibm.com> | 2009-04-23 07:58:07 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-04-23 07:58:17 -0400 |
commit | b1ad171efa089ae26aba750d747d8149a4f860d5 (patch) | |
tree | aecfd29ad345e2bc288c6e4ea046f7d559c87270 /arch/s390 | |
parent | 3bd5f3ef290627efa3c219fa21a82eea90bc4cb0 (diff) |
[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>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/appldata/appldata_base.c | 32 | ||||
-rw-r--r-- | arch/s390/appldata/appldata_mem.c | 2 |
2 files changed, 17 insertions, 17 deletions
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index aeb3cff95f63..1dfc7100c7ee 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c | |||
@@ -98,7 +98,7 @@ static DECLARE_WORK(appldata_work, appldata_work_fn); | |||
98 | /* | 98 | /* |
99 | * Ops list | 99 | * Ops list |
100 | */ | 100 | */ |
101 | static DEFINE_SPINLOCK(appldata_ops_lock); | 101 | static DEFINE_MUTEX(appldata_ops_mutex); |
102 | static LIST_HEAD(appldata_ops_list); | 102 | static LIST_HEAD(appldata_ops_list); |
103 | 103 | ||
104 | 104 | ||
@@ -129,14 +129,14 @@ static void appldata_work_fn(struct work_struct *work) | |||
129 | 129 | ||
130 | i = 0; | 130 | i = 0; |
131 | get_online_cpus(); | 131 | get_online_cpus(); |
132 | spin_lock(&appldata_ops_lock); | 132 | mutex_lock(&appldata_ops_mutex); |
133 | list_for_each(lh, &appldata_ops_list) { | 133 | list_for_each(lh, &appldata_ops_list) { |
134 | ops = list_entry(lh, struct appldata_ops, list); | 134 | ops = list_entry(lh, struct appldata_ops, list); |
135 | if (ops->active == 1) { | 135 | if (ops->active == 1) { |
136 | ops->callback(ops->data); | 136 | ops->callback(ops->data); |
137 | } | 137 | } |
138 | } | 138 | } |
139 | spin_unlock(&appldata_ops_lock); | 139 | mutex_unlock(&appldata_ops_mutex); |
140 | put_online_cpus(); | 140 | put_online_cpus(); |
141 | } | 141 | } |
142 | 142 | ||
@@ -338,7 +338,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, | |||
338 | struct list_head *lh; | 338 | struct list_head *lh; |
339 | 339 | ||
340 | found = 0; | 340 | found = 0; |
341 | spin_lock(&appldata_ops_lock); | 341 | mutex_lock(&appldata_ops_mutex); |
342 | list_for_each(lh, &appldata_ops_list) { | 342 | list_for_each(lh, &appldata_ops_list) { |
343 | tmp_ops = list_entry(lh, struct appldata_ops, list); | 343 | tmp_ops = list_entry(lh, struct appldata_ops, list); |
344 | if (&tmp_ops->ctl_table[2] == ctl) { | 344 | if (&tmp_ops->ctl_table[2] == ctl) { |
@@ -346,15 +346,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, | |||
346 | } | 346 | } |
347 | } | 347 | } |
348 | if (!found) { | 348 | if (!found) { |
349 | spin_unlock(&appldata_ops_lock); | 349 | mutex_unlock(&appldata_ops_mutex); |
350 | return -ENODEV; | 350 | return -ENODEV; |
351 | } | 351 | } |
352 | ops = ctl->data; | 352 | ops = ctl->data; |
353 | if (!try_module_get(ops->owner)) { // protect this function | 353 | if (!try_module_get(ops->owner)) { // protect this function |
354 | spin_unlock(&appldata_ops_lock); | 354 | mutex_unlock(&appldata_ops_mutex); |
355 | return -ENODEV; | 355 | return -ENODEV; |
356 | } | 356 | } |
357 | spin_unlock(&appldata_ops_lock); | 357 | mutex_unlock(&appldata_ops_mutex); |
358 | 358 | ||
359 | if (!*lenp || *ppos) { | 359 | if (!*lenp || *ppos) { |
360 | *lenp = 0; | 360 | *lenp = 0; |
@@ -378,11 +378,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, | |||
378 | return -EFAULT; | 378 | return -EFAULT; |
379 | } | 379 | } |
380 | 380 | ||
381 | spin_lock(&appldata_ops_lock); | 381 | mutex_lock(&appldata_ops_mutex); |
382 | if ((buf[0] == '1') && (ops->active == 0)) { | 382 | if ((buf[0] == '1') && (ops->active == 0)) { |
383 | // protect work queue callback | 383 | // protect work queue callback |
384 | if (!try_module_get(ops->owner)) { | 384 | if (!try_module_get(ops->owner)) { |
385 | spin_unlock(&appldata_ops_lock); | 385 | mutex_unlock(&appldata_ops_mutex); |
386 | module_put(ops->owner); | 386 | module_put(ops->owner); |
387 | return -ENODEV; | 387 | return -ENODEV; |
388 | } | 388 | } |
@@ -407,7 +407,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, | |||
407 | "failed with rc=%d\n", ops->name, rc); | 407 | "failed with rc=%d\n", ops->name, rc); |
408 | module_put(ops->owner); | 408 | module_put(ops->owner); |
409 | } | 409 | } |
410 | spin_unlock(&appldata_ops_lock); | 410 | mutex_unlock(&appldata_ops_mutex); |
411 | out: | 411 | out: |
412 | *lenp = len; | 412 | *lenp = len; |
413 | *ppos += len; | 413 | *ppos += len; |
@@ -433,9 +433,9 @@ int appldata_register_ops(struct appldata_ops *ops) | |||
433 | if (!ops->ctl_table) | 433 | if (!ops->ctl_table) |
434 | return -ENOMEM; | 434 | return -ENOMEM; |
435 | 435 | ||
436 | spin_lock(&appldata_ops_lock); | 436 | mutex_lock(&appldata_ops_mutex); |
437 | list_add(&ops->list, &appldata_ops_list); | 437 | list_add(&ops->list, &appldata_ops_list); |
438 | spin_unlock(&appldata_ops_lock); | 438 | mutex_unlock(&appldata_ops_mutex); |
439 | 439 | ||
440 | ops->ctl_table[0].procname = appldata_proc_name; | 440 | ops->ctl_table[0].procname = appldata_proc_name; |
441 | ops->ctl_table[0].maxlen = 0; | 441 | ops->ctl_table[0].maxlen = 0; |
@@ -452,9 +452,9 @@ int appldata_register_ops(struct appldata_ops *ops) | |||
452 | goto out; | 452 | goto out; |
453 | return 0; | 453 | return 0; |
454 | out: | 454 | out: |
455 | spin_lock(&appldata_ops_lock); | 455 | mutex_lock(&appldata_ops_mutex); |
456 | list_del(&ops->list); | 456 | list_del(&ops->list); |
457 | spin_unlock(&appldata_ops_lock); | 457 | mutex_unlock(&appldata_ops_mutex); |
458 | kfree(ops->ctl_table); | 458 | kfree(ops->ctl_table); |
459 | return -ENOMEM; | 459 | return -ENOMEM; |
460 | } | 460 | } |
@@ -466,9 +466,9 @@ out: | |||
466 | */ | 466 | */ |
467 | void appldata_unregister_ops(struct appldata_ops *ops) | 467 | void appldata_unregister_ops(struct appldata_ops *ops) |
468 | { | 468 | { |
469 | spin_lock(&appldata_ops_lock); | 469 | mutex_lock(&appldata_ops_mutex); |
470 | list_del(&ops->list); | 470 | list_del(&ops->list); |
471 | spin_unlock(&appldata_ops_lock); | 471 | mutex_unlock(&appldata_ops_mutex); |
472 | unregister_sysctl_table(ops->sysctl_header); | 472 | unregister_sysctl_table(ops->sysctl_header); |
473 | kfree(ops->ctl_table); | 473 | kfree(ops->ctl_table); |
474 | } | 474 | } |
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index 3ed56b7d1b2f..4188cbe63a54 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c | |||
@@ -78,7 +78,7 @@ static void appldata_get_mem_data(void *data) | |||
78 | { | 78 | { |
79 | /* | 79 | /* |
80 | * don't put large structures on the stack, we are | 80 | * don't put large structures on the stack, we are |
81 | * serialized through the appldata_ops_lock and can use static | 81 | * serialized through the appldata_ops_mutex and can use static |
82 | */ | 82 | */ |
83 | static struct sysinfo val; | 83 | static struct sysinfo val; |
84 | unsigned long ev[NR_VM_EVENT_ITEMS]; | 84 | unsigned long ev[NR_VM_EVENT_ITEMS]; |