|
|
1.1 root 1: /*
2: * linux/mm/swap.c
3: *
4: * (C) 1991 Linus Torvalds
5: */
6:
7: /*
8: * This file should contain most things doing the swapping from/to disk.
9: * Started 18.12.91
10: */
11:
12: #include <string.h>
13:
14: #include <linux/mm.h>
15: #include <linux/sched.h>
16: #include <linux/head.h>
17: #include <linux/kernel.h>
18:
19: #define SWAP_BITS (4096<<3)
20:
21: #define bitop(name,op) \
22: static inline int name(char * addr,unsigned int nr) \
23: { \
24: int __res; \
25: __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
26: :"=g" (__res) \
27: :"r" (nr),"m" (*(addr)),"0" (0)); \
28: return __res; \
29: }
30:
31: bitop(bit,"")
32: bitop(setbit,"s")
33: bitop(clrbit,"r")
34:
35: static char * swap_bitmap = NULL;
36: int SWAP_DEV = 0;
37:
38: /*
39: * We never page the pages in task[0] - kernel memory.
40: * We page all other pages.
41: */
42: #define FIRST_VM_PAGE (TASK_SIZE>>12)
43: #define LAST_VM_PAGE (1024*1024)
44: #define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
45:
46: static int get_swap_page(void)
47: {
48: int nr;
49:
50: if (!swap_bitmap)
51: return 0;
52: for (nr = 1; nr < 32768 ; nr++)
53: if (clrbit(swap_bitmap,nr))
54: return nr;
55: return 0;
56: }
57:
58: void swap_free(int swap_nr)
59: {
60: if (!swap_nr)
61: return;
62: if (swap_bitmap && swap_nr < SWAP_BITS)
63: if (!setbit(swap_bitmap,swap_nr))
64: return;
65: printk("Swap-space bad (swap_free())\n\r");
66: return;
67: }
68:
69: void swap_in(unsigned long *table_ptr)
70: {
71: int swap_nr;
72: unsigned long page;
73:
74: if (!swap_bitmap) {
75: printk("Trying to swap in without swap bit-map");
76: return;
77: }
78: if (1 & *table_ptr) {
79: printk("trying to swap in present page\n\r");
80: return;
81: }
82: swap_nr = *table_ptr >> 1;
83: if (!swap_nr) {
84: printk("No swap page in swap_in\n\r");
85: return;
86: }
87: if (!(page = get_free_page()))
88: oom();
89: read_swap_page(swap_nr, (char *) page);
90: if (setbit(swap_bitmap,swap_nr))
91: printk("swapping in multiply from same page\n\r");
92: *table_ptr = page | (PAGE_DIRTY | 7);
93: }
94:
95: int try_to_swap_out(unsigned long * table_ptr)
96: {
97: unsigned long page;
98: unsigned long swap_nr;
99:
100: page = *table_ptr;
101: if (!(PAGE_PRESENT & page))
102: return 0;
103: if (page - LOW_MEM > PAGING_MEMORY)
104: return 0;
105: if (PAGE_DIRTY & page) {
106: page &= 0xfffff000;
107: if (mem_map[MAP_NR(page)] != 1)
108: return 0;
109: if (!(swap_nr = get_swap_page()))
110: return 0;
111: *table_ptr = swap_nr<<1;
112: invalidate();
113: write_swap_page(swap_nr, (char *) page);
114: free_page(page);
115: return 1;
116: }
117: *table_ptr = 0;
118: invalidate();
119: free_page(page);
120: return 1;
121: }
122:
123: /*
124: * Ok, this has a rather intricate logic - the idea is to make good
125: * and fast machine code. If we didn't worry about that, things would
126: * be easier.
127: */
128: int swap_out(void)
129: {
130: static int dir_entry = FIRST_VM_PAGE>>10;
131: static int page_entry = -1;
132: int counter = VM_PAGES;
133: int pg_table;
134:
135: while (counter>0) {
136: pg_table = pg_dir[dir_entry];
137: if (pg_table & 1)
138: break;
139: counter -= 1024;
140: dir_entry++;
141: if (dir_entry >= 1024)
142: dir_entry = FIRST_VM_PAGE>>10;
143: }
144: pg_table &= 0xfffff000;
145: while (counter-- > 0) {
146: page_entry++;
147: if (page_entry >= 1024) {
148: page_entry = 0;
149: repeat:
150: dir_entry++;
151: if (dir_entry >= 1024)
152: dir_entry = FIRST_VM_PAGE>>10;
153: pg_table = pg_dir[dir_entry];
154: if (!(pg_table&1))
155: if ((counter -= 1024) > 0)
156: goto repeat;
157: else
158: break;
159: pg_table &= 0xfffff000;
160: }
161: if (try_to_swap_out(page_entry + (unsigned long *) pg_table))
162: return 1;
163: }
164: printk("Out of swap-memory\n\r");
165: return 0;
166: }
167:
168: /*
169: * Get physical address of first (actually last :-) free page, and mark it
170: * used. If no free pages left, return 0.
171: */
172: unsigned long get_free_page(void)
173: {
174: register unsigned long __res asm("ax");
175:
176: repeat:
177: __asm__("std ; repne ; scasb\n\t"
178: "jne 1f\n\t"
179: "movb $1,1(%%edi)\n\t"
180: "sall $12,%%ecx\n\t"
181: "addl %2,%%ecx\n\t"
182: "movl %%ecx,%%edx\n\t"
183: "movl $1024,%%ecx\n\t"
184: "leal 4092(%%edx),%%edi\n\t"
185: "rep ; stosl\n\t"
186: "movl %%edx,%%eax\n"
187: "1:"
188: :"=a" (__res)
189: :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
190: "D" (mem_map+PAGING_PAGES-1)
191: :"di","cx","dx");
192: if (__res >= HIGH_MEMORY)
193: goto repeat;
194: if (!__res && swap_out())
195: goto repeat;
196: return __res;
197: }
198:
199: void init_swapping(void)
200: {
201: extern int *blk_size[];
202: int swap_size,i,j;
203:
204: if (!SWAP_DEV)
205: return;
206: if (!blk_size[MAJOR(SWAP_DEV)]) {
207: printk("Unable to get size of swap device\n\r");
208: return;
209: }
210: swap_size = blk_size[MAJOR(SWAP_DEV)][MINOR(SWAP_DEV)];
211: if (!swap_size)
212: return;
213: if (swap_size < 100) {
214: printk("Swap device too small (%d blocks)\n\r",swap_size);
215: return;
216: }
217: swap_size >>= 2;
218: if (swap_size > SWAP_BITS)
219: swap_size = SWAP_BITS;
220: swap_bitmap = (char *) get_free_page();
221: if (!swap_bitmap) {
222: printk("Unable to start swapping: out of memory :-)\n\r");
223: return;
224: }
225: read_swap_page(0,swap_bitmap);
226: if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) {
227: printk("Unable to find swap-space signature\n\r");
228: free_page((long) swap_bitmap);
229: swap_bitmap = NULL;
230: return;
231: }
232: memset(swap_bitmap+4086,0,10);
233: for (i = 0 ; i < SWAP_BITS ; i++) {
234: if (i == 1)
235: i = swap_size;
236: if (bit(swap_bitmap,i)) {
237: printk("Bad swap-space bit-map\n\r");
238: free_page((long) swap_bitmap);
239: swap_bitmap = NULL;
240: return;
241: }
242: }
243: j = 0;
244: for (i = 1 ; i < swap_size ; i++)
245: if (bit(swap_bitmap,i))
246: j++;
247: if (!j) {
248: free_page((long) swap_bitmap);
249: swap_bitmap = NULL;
250: return;
251: }
252: printk("Swap device ok: %d pages (%d bytes) swap-space\n\r",j,j*4096);
253: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.