1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/sched.h>
14#include <linux/list.h>
15#include <linux/signal.h>
16#include <linux/spinlock.h>
17#include <linux/gfp.h>
18#include <linux/init.h>
19#include <linux/module.h>
20#include <linux/fs.h>
21#include <linux/writeback.h>
22#include <linux/kthread.h>
23#include <linux/cpuset.h>
24#include <linux/freezer.h>
25
26
27
28
29
30#define MIN_PDFLUSH_THREADS 2
31#define MAX_PDFLUSH_THREADS 8
32
33static void start_one_pdflush_thread(void);
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48static LIST_HEAD(pdflush_list);
49static DEFINE_SPINLOCK(pdflush_lock);
50
51
52
53
54
55
56
57
58int nr_pdflush_threads = 0;
59
60
61
62
63static unsigned long last_empty_jifs;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84struct pdflush_work {
85 struct task_struct *who;
86 void (*fn)(unsigned long);
87 unsigned long arg0;
88 struct list_head list;
89 unsigned long when_i_went_to_sleep;
90};
91
92static int __pdflush(struct pdflush_work *my_work)
93{
94 current->flags |= PF_FLUSHER | PF_SWAPWRITE;
95 set_freezable();
96 my_work->fn = NULL;
97 my_work->who = current;
98 INIT_LIST_HEAD(&my_work->list);
99
100 spin_lock_irq(&pdflush_lock);
101 nr_pdflush_threads++;
102 for ( ; ; ) {
103 struct pdflush_work *pdf;
104
105 set_current_state(TASK_INTERRUPTIBLE);
106 list_move(&my_work->list, &pdflush_list);
107 my_work->when_i_went_to_sleep = jiffies;
108 spin_unlock_irq(&pdflush_lock);
109 schedule();
110 try_to_freeze();
111 spin_lock_irq(&pdflush_lock);
112 if (!list_empty(&my_work->list)) {
113
114
115
116
117
118 my_work->fn = NULL;
119 continue;
120 }
121 if (my_work->fn == NULL) {
122 printk("pdflush: bogus wakeup\n");
123 continue;
124 }
125 spin_unlock_irq(&pdflush_lock);
126
127 (*my_work->fn)(my_work->arg0);
128
129
130
131
132
133 if (time_after(jiffies, last_empty_jifs + 1 * HZ)) {
134
135 if (list_empty(&pdflush_list)) {
136
137 if (nr_pdflush_threads < MAX_PDFLUSH_THREADS)
138 start_one_pdflush_thread();
139 }
140 }
141
142 spin_lock_irq(&pdflush_lock);
143 my_work->fn = NULL;
144
145
146
147
148
149 if (list_empty(&pdflush_list))
150 continue;
151 if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS)
152 continue;
153 pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);
154 if (time_after(jiffies, pdf->when_i_went_to_sleep + 1 * HZ)) {
155
156 pdf->when_i_went_to_sleep = jiffies;
157 break;
158 }
159 }
160 nr_pdflush_threads--;
161 spin_unlock_irq(&pdflush_lock);
162 return 0;
163}
164
165
166
167
168
169
170
171
172static int pdflush(void *dummy)
173{
174 struct pdflush_work my_work;
175 cpumask_t cpus_allowed;
176
177
178
179
180
181 set_user_nice(current, 0);
182
183
184
185
186
187
188
189
190 cpuset_cpus_allowed(current, &cpus_allowed);
191 set_cpus_allowed_ptr(current, &cpus_allowed);
192
193 return __pdflush(&my_work);
194}
195
196
197
198
199
200
201int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
202{
203 unsigned long flags;
204 int ret = 0;
205
206 BUG_ON(fn == NULL);
207
208 spin_lock_irqsave(&pdflush_lock, flags);
209 if (list_empty(&pdflush_list)) {
210 ret = -1;
211 } else {
212 struct pdflush_work *pdf;
213
214 pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
215 list_del_init(&pdf->list);
216 if (list_empty(&pdflush_list))
217 last_empty_jifs = jiffies;
218 pdf->fn = fn;
219 pdf->arg0 = arg0;
220 wake_up_process(pdf->who);
221 }
222 spin_unlock_irqrestore(&pdflush_lock, flags);
223
224 return ret;
225}
226
227static void start_one_pdflush_thread(void)
228{
229 kthread_run(pdflush, NULL, "pdflush");
230}
231
232static int __init pdflush_init(void)
233{
234 int i;
235
236 for (i = 0; i < MIN_PDFLUSH_THREADS; i++)
237 start_one_pdflush_thread();
238 return 0;
239}
240
241module_init(pdflush_init);
242