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