This source file includes following definitions.
- try_to_swap_out
- swap_out_pmd
- swap_out_pgd
- swap_out_vma
- swap_out_process
- swap_out
- try_to_free_page
- kswapd
- swap_tick
- init_swap_timer
1
2
3
4
5
6
7
8
9
10
11 #include <linux/mm.h>
12 #include <linux/sched.h>
13 #include <linux/head.h>
14 #include <linux/kernel.h>
15 #include <linux/kernel_stat.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/stat.h>
19 #include <linux/swap.h>
20 #include <linux/fs.h>
21 #include <linux/swapctl.h>
22 #include <linux/smp_lock.h>
23
24 #include <asm/dma.h>
25 #include <asm/system.h>
26 #include <asm/segment.h>
27 #include <asm/bitops.h>
28 #include <asm/pgtable.h>
29
30
31
32
33 static int next_swap_jiffies = 0;
34
35
36
37
38
39 int swapout_interval = HZ / 4;
40
41
42
43
44 static struct wait_queue * kswapd_wait = NULL;
45
46
47
48
49 static int kswapd_awake = 0;
50
51
52
53
54
55 kswapd_control_t kswapd_ctl = {4, -1, -1, -1, -1};
56
57 static void init_swap_timer(void);
58
59
60
61
62
63
64
65
66
67
68
69
70 static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
71 unsigned long address, pte_t * page_table, unsigned long limit)
72 {
73 pte_t pte;
74 unsigned long entry;
75 unsigned long page;
76 struct page * page_map;
77
78 pte = *page_table;
79 if (!pte_present(pte))
80 return 0;
81 page = pte_page(pte);
82 if (MAP_NR(page) >= MAP_NR(high_memory))
83 return 0;
84 if (page >= limit)
85 return 0;
86
87 page_map = mem_map + MAP_NR(page);
88 if (page_map->reserved)
89 return 0;
90
91
92
93 if ((pte_dirty(pte) && delete_from_swap_cache(page))
94 || pte_young(pte)) {
95 set_pte(page_table, pte_mkold(pte));
96 touch_page(page_map);
97 return 0;
98 }
99 age_page(page_map);
100 if (page_map->age)
101 return 0;
102 if (pte_dirty(pte)) {
103 if (vma->vm_ops && vma->vm_ops->swapout) {
104 pid_t pid = tsk->pid;
105 vma->vm_mm->rss--;
106 if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
107 kill_proc(pid, SIGBUS, 1);
108 } else {
109 if (page_map->count != 1)
110 return 0;
111 if (!(entry = get_swap_page()))
112 return 0;
113 vma->vm_mm->rss--;
114 set_pte(page_table, __pte(entry));
115 invalidate_page(vma, address);
116 tsk->nswap++;
117 write_swap_page(entry, (char *) page);
118 }
119 free_page(page);
120 return 1;
121 }
122 if ((entry = find_in_swap_cache(page))) {
123 if (page_map->count != 1) {
124 set_pte(page_table, pte_mkdirty(pte));
125 printk("Aiee.. duplicated cached swap-cache entry\n");
126 return 0;
127 }
128 vma->vm_mm->rss--;
129 set_pte(page_table, __pte(entry));
130 invalidate_page(vma, address);
131 free_page(page);
132 return 1;
133 }
134 vma->vm_mm->rss--;
135 pte_clear(page_table);
136 invalidate_page(vma, address);
137 entry = page_unuse(page);
138 free_page(page);
139 return entry;
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * vma,
157 pmd_t *dir, unsigned long address, unsigned long end, unsigned long limit)
158 {
159 pte_t * pte;
160 unsigned long pmd_end;
161
162 if (pmd_none(*dir))
163 return 0;
164 if (pmd_bad(*dir)) {
165 printk("swap_out_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
166 pmd_clear(dir);
167 return 0;
168 }
169
170 pte = pte_offset(dir, address);
171
172 pmd_end = (address + PMD_SIZE) & PMD_MASK;
173 if (end > pmd_end)
174 end = pmd_end;
175
176 do {
177 int result;
178 tsk->swap_address = address + PAGE_SIZE;
179 result = try_to_swap_out(tsk, vma, address, pte, limit);
180 if (result)
181 return result;
182 address += PAGE_SIZE;
183 pte++;
184 } while (address < end);
185 return 0;
186 }
187
188 static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * vma,
189 pgd_t *dir, unsigned long address, unsigned long end, unsigned long limit)
190 {
191 pmd_t * pmd;
192 unsigned long pgd_end;
193
194 if (pgd_none(*dir))
195 return 0;
196 if (pgd_bad(*dir)) {
197 printk("swap_out_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
198 pgd_clear(dir);
199 return 0;
200 }
201
202 pmd = pmd_offset(dir, address);
203
204 pgd_end = (address + PGDIR_SIZE) & PGDIR_MASK;
205 if (end > pgd_end)
206 end = pgd_end;
207
208 do {
209 int result = swap_out_pmd(tsk, vma, pmd, address, end, limit);
210 if (result)
211 return result;
212 address = (address + PMD_SIZE) & PMD_MASK;
213 pmd++;
214 } while (address < end);
215 return 0;
216 }
217
218 static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma,
219 pgd_t *pgdir, unsigned long start, unsigned long limit)
220 {
221 unsigned long end;
222
223
224
225 if (vma->vm_flags & (VM_SHM | VM_LOCKED))
226 return 0;
227
228 end = vma->vm_end;
229 while (start < end) {
230 int result = swap_out_pgd(tsk, vma, pgdir, start, end, limit);
231 if (result)
232 return result;
233 start = (start + PGDIR_SIZE) & PGDIR_MASK;
234 pgdir++;
235 }
236 return 0;
237 }
238
239 static int swap_out_process(struct task_struct * p, unsigned long limit)
240 {
241 unsigned long address;
242 struct vm_area_struct* vma;
243
244
245
246
247 address = p->swap_address;
248 p->swap_address = 0;
249
250
251
252
253 vma = find_vma(p, address);
254 if (!vma)
255 return 0;
256 if (address < vma->vm_start)
257 address = vma->vm_start;
258
259 for (;;) {
260 int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, limit);
261 if (result)
262 return result;
263 vma = vma->vm_next;
264 if (!vma)
265 break;
266 address = vma->vm_start;
267 }
268 p->swap_address = 0;
269 return 0;
270 }
271
272 static int swap_out(unsigned int priority, unsigned long limit)
273 {
274 static int swap_task;
275 int loop, counter;
276 struct task_struct *p;
277
278 counter = ((PAGEOUT_WEIGHT * nr_tasks) >> 10) >> priority;
279 for(; counter >= 0; counter--) {
280
281
282
283
284 loop = 0;
285 while(1) {
286 if (swap_task >= NR_TASKS) {
287 swap_task = 1;
288 if (loop)
289
290 return 0;
291 loop = 1;
292 }
293
294 p = task[swap_task];
295 if (p && p->swappable && p->mm->rss)
296 break;
297
298 swap_task++;
299 }
300
301
302
303
304 if (!p->swap_cnt) {
305
306
307 p->swap_cnt = AGE_CLUSTER_SIZE(p->mm->rss);
308 }
309 if (!--p->swap_cnt)
310 swap_task++;
311 switch (swap_out_process(p, limit)) {
312 case 0:
313 if (p->swap_cnt)
314 swap_task++;
315 break;
316 case 1:
317 return 1;
318 default:
319 break;
320 }
321 }
322 return 0;
323 }
324
325
326
327
328
329
330 int try_to_free_page(int priority, unsigned long limit)
331 {
332 static int state = 0;
333 int i=6;
334
335 switch (state) {
336 do {
337 case 0:
338 if (shrink_mmap(i, limit))
339 return 1;
340 state = 1;
341 case 1:
342 if (shm_swap(i, limit))
343 return 1;
344 state = 2;
345 default:
346 if (swap_out(i, limit))
347 return 1;
348 state = 0;
349 } while(i--);
350 }
351 return 0;
352 }
353
354
355
356
357
358
359 int kswapd(void *unused)
360 {
361 int i;
362 char *revision="$Revision: 1.3.2.3 $", *s, *e;
363
364 current->session = 1;
365 current->pgrp = 1;
366 sprintf(current->comm, "kswapd");
367 current->blocked = ~0UL;
368
369
370
371
372
373
374
375 #ifdef __SMP__
376 lock_kernel();
377 syscall_count++;
378 #endif
379
380
381 current->policy = SCHED_FIFO;
382 current->priority = 32;
383
384
385
386 init_swap_timer();
387
388 if ((s = strchr(revision, ':')) &&
389 (e = strchr(s, '$')))
390 s++, i = e - s;
391 else
392 s = revision, i = -1;
393 printk ("Started kswapd v%.*s\n", i, s);
394
395 while (1) {
396 kswapd_awake = 0;
397 current->signal = 0;
398 interruptible_sleep_on(&kswapd_wait);
399 kswapd_awake = 1;
400 swapstats.wakeups++;
401
402 for (i=0; i < kswapd_ctl.maxpages; i++)
403 try_to_free_page(GFP_KERNEL, ~0UL);
404 }
405 }
406
407
408
409
410
411 void swap_tick(void)
412 {
413 if (nr_free_pages < free_pages_low ||
414 (nr_free_pages < free_pages_high &&
415 jiffies >= next_swap_jiffies)) {
416 if (!kswapd_awake && kswapd_ctl.maxpages > 0) {
417 wake_up(&kswapd_wait);
418 need_resched = 1;
419 kswapd_awake = 1;
420 }
421 next_swap_jiffies = jiffies + swapout_interval;
422 }
423 timer_active |= (1<<SWAP_TIMER);
424 }
425
426
427
428
429
430
431 void init_swap_timer(void)
432 {
433 timer_table[SWAP_TIMER].expires = 0;
434 timer_table[SWAP_TIMER].fn = swap_tick;
435 timer_active |= (1<<SWAP_TIMER);
436 }