This source file includes following definitions.
- rw_swap_page
- get_swap_page
- swap_free
- swap_in
- try_to_swap_out
- swap_out
- get_free_page
- sys_swapon
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/mm.h>
13 #include <linux/sched.h>
14 #include <linux/head.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/stat.h>
19
20 static int lowest_bit = 0;
21 static int highest_bit = 0;
22
23
24
25
26 #define NR_LAST_FREE_PAGES 32
27 static unsigned long last_free_pages[NR_LAST_FREE_PAGES] = {0,};
28
29 #define SWAP_BITS (4096<<3)
30
31 #define bitop(name,op) \
32 static inline int name(char * addr,unsigned int nr) \
33 { \
34 int __res; \
35 __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
36 :"=g" (__res) \
37 :"r" (nr),"m" (*(addr)),"0" (0)); \
38 return __res; \
39 }
40
41 bitop(bit,"")
42 bitop(setbit,"s")
43 bitop(clrbit,"r")
44
45 static char * swap_bitmap = NULL;
46 static char * swap_lockmap = NULL;
47 unsigned int swap_device = 0;
48 struct inode * swap_file = NULL;
49
50 void rw_swap_page(int rw, unsigned int nr, char * buf)
51 {
52 static struct wait_queue * lock_queue = NULL;
53
54 if (!swap_lockmap) {
55 printk("No swap lock-map\n");
56 return;
57 }
58 while (setbit(swap_lockmap,nr))
59 sleep_on(&lock_queue);
60 if (swap_device) {
61 ll_rw_page(rw,swap_device,nr,buf);
62 } else if (swap_file) {
63 unsigned int zones[4];
64 unsigned int block = nr << 2;
65 int i;
66
67 for (i = 0; i < 4; i++)
68 if (!(zones[i] = bmap(swap_file,block++))) {
69 printk("rw_swap_page: bad swap file\n");
70 return;
71 }
72 ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf);
73 } else
74 printk("re_swap_page: no swap file or device\n");
75 if (!clrbit(swap_lockmap,nr))
76 printk("rw_swap_page: lock already cleared\n");
77 wake_up(&lock_queue);
78 }
79
80 static unsigned int get_swap_page(void)
81 {
82 unsigned int nr;
83
84 if (!swap_bitmap)
85 return 0;
86 for (nr = lowest_bit; nr <= highest_bit ; nr++)
87 if (clrbit(swap_bitmap,nr)) {
88 if (nr == highest_bit)
89 highest_bit--;
90 return lowest_bit = nr;
91 }
92 return 0;
93 }
94
95 void swap_free(unsigned int swap_nr)
96 {
97 if (!swap_nr)
98 return;
99 if (swap_bitmap && swap_nr < SWAP_BITS) {
100 if (swap_nr < lowest_bit)
101 lowest_bit = swap_nr;
102 if (swap_nr > highest_bit)
103 highest_bit = swap_nr;
104 if (!setbit(swap_bitmap,swap_nr))
105 return;
106 }
107 printk("swap_free: swap-space bitmap bad (bit %d)\n",swap_nr);
108 return;
109 }
110
111 void swap_in(unsigned long *table_ptr)
112 {
113 unsigned long swap_nr;
114 unsigned long page;
115
116 swap_nr = *table_ptr;
117 if (1 & swap_nr) {
118 printk("trying to swap in present page\n\r");
119 return;
120 }
121 if (!swap_nr) {
122 printk("No swap page in swap_in\n\r");
123 return;
124 }
125 if (!swap_bitmap) {
126 printk("Trying to swap in without swap bit-map");
127 *table_ptr = BAD_PAGE;
128 return;
129 }
130 page = get_free_page(GFP_KERNEL);
131 if (!page) {
132 oom(current);
133 page = BAD_PAGE;
134 } else
135 read_swap_page(swap_nr>>1, (char *) page);
136 if (*table_ptr != swap_nr) {
137 free_page(page);
138 return;
139 }
140 swap_free(swap_nr>>1);
141 *table_ptr = page | (PAGE_DIRTY | 7);
142 }
143
144 int try_to_swap_out(unsigned long * table_ptr)
145 {
146 int i;
147 unsigned long page;
148 unsigned long swap_nr;
149
150 page = *table_ptr;
151 if (!(PAGE_PRESENT & page))
152 return 0;
153 if (page < low_memory || page >= high_memory)
154 return 0;
155 for (i = 0; i < NR_LAST_FREE_PAGES; i++)
156 if (last_free_pages[i] == (page & 0xfffff000))
157 return 0;
158 if (PAGE_DIRTY & page) {
159 page &= 0xfffff000;
160 if (mem_map[MAP_NR(page)] != 1)
161 return 0;
162 if (!(swap_nr = get_swap_page()))
163 return 0;
164 *table_ptr = swap_nr<<1;
165 invalidate();
166 write_swap_page(swap_nr, (char *) page);
167 free_page(page);
168 return 1;
169 }
170 page &= 0xfffff000;
171 *table_ptr = 0;
172 invalidate();
173 free_page(page);
174 return 1;
175 }
176
177
178
179
180
181 #define FIRST_VM_PAGE (TASK_SIZE>>12)
182 #define LAST_VM_PAGE (1024*1024)
183 #define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
184
185
186
187
188
189
190
191
192
193 int swap_out(void)
194 {
195 static int dir_entry = 1024;
196 static int page_entry = -1;
197 int counter = VM_PAGES;
198 int pg_table;
199 struct task_struct * p;
200
201 check_dir:
202 if (counter < 0)
203 goto no_swap;
204 if (dir_entry >= 1024)
205 dir_entry = FIRST_VM_PAGE>>10;
206 if (!(p = task[dir_entry >> 4])) {
207 counter -= 1024;
208 dir_entry++;
209 goto check_dir;
210 }
211 if (!(1 & (pg_table = pg_dir[dir_entry]))) {
212 if (pg_table) {
213 printk("bad page-table at pg_dir[%d]: %08x\n\r",
214 dir_entry,pg_table);
215 pg_dir[dir_entry] = 0;
216 }
217 counter -= 1024;
218 dir_entry++;
219 goto check_dir;
220 }
221 pg_table &= 0xfffff000;
222 check_table:
223 if (counter < 0)
224 goto no_swap;
225 counter--;
226 page_entry++;
227 if (page_entry >= 1024) {
228 page_entry = -1;
229 dir_entry++;
230 goto check_dir;
231 }
232 if (p->swappable && try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
233 p->rss--;
234 dir_entry++;
235 return 1;
236 }
237 goto check_table;
238 no_swap:
239 printk("Out of swap-memory\n\r");
240 return 0;
241 }
242
243
244
245
246
247 unsigned long get_free_page(int priority)
248 {
249 unsigned long result;
250 static unsigned long index = 0;
251
252 repeat:
253 __asm__("std ; repne ; scasb\n\t"
254 "jne 1f\n\t"
255 "movb $1,1(%%edi)\n\t"
256 "sall $12,%%ecx\n\t"
257 "addl %2,%%ecx\n\t"
258 "movl %%ecx,%%edx\n\t"
259 "movl $1024,%%ecx\n\t"
260 "leal 4092(%%edx),%%edi\n\t"
261 "rep ; stosl\n\t"
262 "movl %%edx,%%eax\n"
263 "1:\tcld"
264 :"=a" (result)
265 :"0" (0),"b" (low_memory),"c" (paging_pages),
266 "D" (mem_map+paging_pages-1)
267 :"di","cx","dx");
268 if (result >= high_memory)
269 goto repeat;
270 if ((result && result < low_memory) || (result & 0xfff)) {
271 printk("weird result: %08x\n",result);
272 result = 0;
273 }
274 if (result) {
275 --nr_free_pages;
276 if (index >= NR_LAST_FREE_PAGES)
277 index = 0;
278 last_free_pages[index] = result;
279 index++;
280 return result;
281 }
282 if (nr_free_pages) {
283 printk("Damn. mm_free_page count is off by %d\r\n",
284 nr_free_pages);
285 nr_free_pages = 0;
286 }
287 if (priority <= GFP_BUFFER)
288 return 0;
289 if (shrink_buffers()) {
290 schedule();
291 goto repeat;
292 }
293 if (swap_out()) {
294 schedule();
295 goto repeat;
296 }
297 return 0;
298 }
299
300
301
302
303
304
305 int sys_swapon(const char * specialfile)
306 {
307 struct inode * swap_inode;
308 char * tmp;
309 int i,j;
310
311 if (!suser())
312 return -EPERM;
313 if (!(swap_inode = namei(specialfile)))
314 return -ENOENT;
315 if (swap_file || swap_device || swap_bitmap || swap_lockmap) {
316 iput(swap_inode);
317 return -EBUSY;
318 }
319 if (S_ISBLK(swap_inode->i_mode)) {
320 swap_device = swap_inode->i_rdev;
321 iput(swap_inode);
322 } else if (S_ISREG(swap_inode->i_mode))
323 swap_file = swap_inode;
324 else {
325 iput(swap_inode);
326 return -EINVAL;
327 }
328 tmp = (char *) get_free_page(GFP_USER);
329 swap_lockmap = (char *) get_free_page(GFP_USER);
330 if (!tmp || !swap_lockmap) {
331 printk("Unable to start swapping: out of memory :-)\n");
332 free_page((long) tmp);
333 free_page((long) swap_lockmap);
334 iput(swap_file);
335 swap_device = 0;
336 swap_file = NULL;
337 swap_bitmap = NULL;
338 swap_lockmap = NULL;
339 return -ENOMEM;
340 }
341 read_swap_page(0,tmp);
342 if (strncmp("SWAP-SPACE",tmp+4086,10)) {
343 printk("Unable to find swap-space signature\n\r");
344 free_page((long) tmp);
345 free_page((long) swap_lockmap);
346 iput(swap_file);
347 swap_device = 0;
348 swap_file = NULL;
349 swap_bitmap = NULL;
350 swap_lockmap = NULL;
351 return -EINVAL;
352 }
353 memset(tmp+4086,0,10);
354 j = 0;
355 lowest_bit = 0;
356 highest_bit = 0;
357 for (i = 1 ; i < SWAP_BITS ; i++)
358 if (bit(tmp,i)) {
359 if (!lowest_bit)
360 lowest_bit = i;
361 highest_bit = i;
362 j++;
363 }
364 if (!j) {
365 printk("Empty swap-file\n");
366 free_page((long) tmp);
367 free_page((long) swap_lockmap);
368 iput(swap_file);
369 swap_device = 0;
370 swap_file = NULL;
371 swap_bitmap = NULL;
372 swap_lockmap = NULL;
373 return -EINVAL;
374 }
375 swap_bitmap = tmp;
376 printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
377 return 0;
378 }