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 my_work->fn = NULL;
96 my_work->who = current;
97 INIT_LIST_HEAD(&my_work->list);
98
99 spin_lock_irq(&pdflush_lock);
100 nr_pdflush_threads++;
101 for ( ; ; ) {
102 struct pdflush_work *pdf;
103
104 set_current_state(TASK_INTERRUPTIBLE);
105 list_move(&my_work->list, &pdflush_list);
106 my_work->when_i_went_to_sleep = jiffies;
107 spin_unlock_irq(&pdflush_lock);
108 schedule();
109 try_to_freeze();
110 spin_lock_irq(&pdflush_lock);
111 if (!list_empty(&my_work->list)) {
112
113
114
115
116
117 my_work->fn = NULL;
118 continue;
119 }
120 if (my_work->fn == NULL) {
121 printk("pdflush: bogus wakeup\n");
122 continue;
123 }
124 spin_unlock_irq(&pdflush_lock);
125
126 (*my_work->fn)(my_work->arg0);
127
128
129
130
131
132 if (jiffies - last_empty_jifs > 1 * HZ) {
133
134 if (list_empty(&pdflush_list)) {
135
136 if (nr_pdflush_threads < MAX_PDFLUSH_THREADS)
137 start_one_pdflush_thread();
138 }
139 }
140
141 spin_lock_irq(&pdflush_lock);
142 my_work->fn = NULL;
143
144
145
146
147
148 if (list_empty(&pdflush_list))
149 continue;
150 if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS)
151 continue;
152 pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);
153 if (jiffies - pdf->when_i_went_to_sleep > 1 * HZ) {
154
155 pdf->when_i_went_to_sleep = jiffies;
156 break;
157 }
158 }
159 nr_pdflush_threads--;
160 spin_unlock_irq(&pdflush_lock);
161 return 0;
162}
163
164
165
166
167
168
169
170
171static int pdflush(void *dummy)
172{
173 struct pdflush_work my_work;
174 cpumask_t cpus_allowed;
175
176
177
178
179
180 set_user_nice(current, 0);
181
182
183
184
185
186
187
188
189 cpus_allowed = cpuset_cpus_allowed(current);
190 set_cpus_allowed(current, cpus_allowed);
191
192 return __pdflush(&my_work);
193}
194
195
196
197
198
199
200int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
201{
202 unsigned long flags;
203 int ret = 0;
204
205 BUG_ON(fn == NULL);
206
207 spin_lock_irqsave(&pdflush_lock, flags);
208 if (list_empty(&pdflush_list)) {
209 spin_unlock_irqrestore(&pdflush_lock, flags);
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 spin_unlock_irqrestore(&pdflush_lock, flags);
222 }
223 return ret;
224}
225
226static void start_one_pdflush_thread(void)
227{
228 kthread_run(pdflush, NULL, "pdflush");
229}
230
231static int __init pdflush_init(void)
232{
233 int i;
234
235 for (i = 0; i < MIN_PDFLUSH_THREADS; i++)
236 start_one_pdflush_thread();
237 return 0;
238}
239
240module_init(pdflush_init);
241