]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | Subject: mm: fix pdflush thread creation upper bound. |
2 | From: Peter W. Morreale <pmorreale@novell.com> | |
3 | References: bnc#460284 | |
4 | Patch-upstream: not yet | |
5 | ||
6 | This patch fixes a race on creating pdflush threads. Without the patch, | |
7 | it is possible to create more than MAX_PDFLUSH_THREADS threads, and this | |
8 | has been observed in practice. | |
9 | ||
10 | The fix involves moving the lock around to protect the check against the | |
11 | thread count and correctly dealing with thread creation failure. | |
12 | ||
13 | Signed-Off-By: Peter W. Morreale <pmorreale@novell.com> | |
14 | Acked-by: Nick Piggin <npiggin@suse.de> | |
15 | --- | |
16 | --- | |
17 | mm/pdflush.c | 27 +++++++++++++++++++++------ | |
18 | 1 file changed, 21 insertions(+), 6 deletions(-) | |
19 | ||
20 | --- a/mm/pdflush.c | |
21 | +++ b/mm/pdflush.c | |
22 | @@ -98,7 +98,6 @@ static int __pdflush(struct pdflush_work | |
23 | INIT_LIST_HEAD(&my_work->list); | |
24 | ||
25 | spin_lock_irq(&pdflush_lock); | |
26 | - nr_pdflush_threads++; | |
27 | for ( ; ; ) { | |
28 | struct pdflush_work *pdf; | |
29 | ||
30 | @@ -126,20 +125,23 @@ static int __pdflush(struct pdflush_work | |
31 | ||
32 | (*my_work->fn)(my_work->arg0); | |
33 | ||
34 | + spin_lock_irq(&pdflush_lock); | |
35 | + | |
36 | /* | |
37 | * Thread creation: For how long have there been zero | |
38 | * available threads? | |
39 | */ | |
40 | if (time_after(jiffies, last_empty_jifs + 1 * HZ)) { | |
41 | - /* unlocked list_empty() test is OK here */ | |
42 | if (list_empty(&pdflush_list)) { | |
43 | - /* unlocked test is OK here */ | |
44 | - if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) | |
45 | + if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) { | |
46 | + nr_pdflush_threads++; | |
47 | + spin_unlock_irq(&pdflush_lock); | |
48 | start_one_pdflush_thread(); | |
49 | + spin_lock_irq(&pdflush_lock); | |
50 | + } | |
51 | } | |
52 | } | |
53 | ||
54 | - spin_lock_irq(&pdflush_lock); | |
55 | my_work->fn = NULL; | |
56 | ||
57 | /* | |
58 | @@ -226,13 +228,26 @@ int pdflush_operation(void (*fn)(unsigne | |
59 | ||
60 | static void start_one_pdflush_thread(void) | |
61 | { | |
62 | - kthread_run(pdflush, NULL, "pdflush"); | |
63 | + struct task_struct *k; | |
64 | + | |
65 | + k = kthread_run(pdflush, NULL, "pdflush"); | |
66 | + if (unlikely(IS_ERR(k))) { | |
67 | + spin_lock_irq(&pdflush_lock); | |
68 | + nr_pdflush_threads--; | |
69 | + spin_unlock_irq(&pdflush_lock); | |
70 | + } | |
71 | } | |
72 | ||
73 | static int __init pdflush_init(void) | |
74 | { | |
75 | int i; | |
76 | ||
77 | + /* | |
78 | + * Pre-set nr_pdflush_threads... If we fail to create, | |
79 | + * the count will be decremented. | |
80 | + */ | |
81 | + nr_pdflush_threads = MIN_PDFLUSH_THREADS; | |
82 | + | |
83 | for (i = 0; i < MIN_PDFLUSH_THREADS; i++) | |
84 | start_one_pdflush_thread(); | |
85 | return 0; |