|
|
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>
1.1.1.2 root 13: #include <errno.h>
1.1 root 14:
15: #include <linux/mm.h>
1.1.1.2 root 16: #include <sys/stat.h>
1.1 root 17: #include <linux/sched.h>
18: #include <linux/head.h>
19: #include <linux/kernel.h>
20:
21: #define SWAP_BITS (4096<<3)
22:
23: #define bitop(name,op) \
24: static inline int name(char * addr,unsigned int nr) \
25: { \
26: int __res; \
27: __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
28: :"=g" (__res) \
29: :"r" (nr),"m" (*(addr)),"0" (0)); \
30: return __res; \
31: }
32:
33: bitop(bit,"")
34: bitop(setbit,"s")
35: bitop(clrbit,"r")
36:
37: static char * swap_bitmap = NULL;
1.1.1.2 root 38: unsigned int swap_device = 0;
39: struct inode * swap_file = NULL;
40:
41: void rw_swap_page(int rw, unsigned int nr, char * buf)
42: {
43: unsigned int zones[4];
44: int i;
45:
46: if (swap_device) {
47: ll_rw_page(rw,swap_device,nr,buf);
48: return;
49: }
50: if (swap_file) {
51: nr <<= 2;
52: for (i = 0; i < 4; i++)
53: if (!(zones[i] = bmap(swap_file,nr++))) {
54: printk("rw_swap_page: bad swap file\n");
55: return;
56: }
57: ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf);
58: return;
59: }
60: printk("ll_swap_page: no swap file or device\n");
61: }
1.1 root 62:
63: /*
64: * We never page the pages in task[0] - kernel memory.
65: * We page all other pages.
66: */
67: #define FIRST_VM_PAGE (TASK_SIZE>>12)
68: #define LAST_VM_PAGE (1024*1024)
69: #define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
70:
71: static int get_swap_page(void)
72: {
73: int nr;
74:
75: if (!swap_bitmap)
76: return 0;
1.1.1.2 root 77: for (nr = 1; nr < SWAP_BITS ; nr++)
1.1 root 78: if (clrbit(swap_bitmap,nr))
79: return nr;
80: return 0;
81: }
82:
83: void swap_free(int swap_nr)
84: {
85: if (!swap_nr)
86: return;
87: if (swap_bitmap && swap_nr < SWAP_BITS)
88: if (!setbit(swap_bitmap,swap_nr))
89: return;
1.1.1.2 root 90: printk("swap_free: swap-space bitmap bad\n");
1.1 root 91: return;
92: }
93:
94: void swap_in(unsigned long *table_ptr)
95: {
96: int swap_nr;
97: unsigned long page;
98:
99: if (!swap_bitmap) {
100: printk("Trying to swap in without swap bit-map");
101: return;
102: }
103: if (1 & *table_ptr) {
104: printk("trying to swap in present page\n\r");
105: return;
106: }
107: swap_nr = *table_ptr >> 1;
108: if (!swap_nr) {
109: printk("No swap page in swap_in\n\r");
110: return;
111: }
112: if (!(page = get_free_page()))
113: oom();
114: read_swap_page(swap_nr, (char *) page);
115: if (setbit(swap_bitmap,swap_nr))
116: printk("swapping in multiply from same page\n\r");
117: *table_ptr = page | (PAGE_DIRTY | 7);
118: }
119:
120: int try_to_swap_out(unsigned long * table_ptr)
121: {
122: unsigned long page;
123: unsigned long swap_nr;
124:
125: page = *table_ptr;
126: if (!(PAGE_PRESENT & page))
127: return 0;
128: if (page - LOW_MEM > PAGING_MEMORY)
129: return 0;
130: if (PAGE_DIRTY & page) {
131: page &= 0xfffff000;
132: if (mem_map[MAP_NR(page)] != 1)
133: return 0;
134: if (!(swap_nr = get_swap_page()))
135: return 0;
136: *table_ptr = swap_nr<<1;
137: invalidate();
138: write_swap_page(swap_nr, (char *) page);
139: free_page(page);
140: return 1;
141: }
1.1.1.2 root 142: page &= 0xfffff000;
1.1 root 143: *table_ptr = 0;
144: invalidate();
145: free_page(page);
146: return 1;
147: }
148:
149: /*
1.1.1.2 root 150: * Go through the page tables, searching for a user page that
151: * we can swap out.
1.1 root 152: */
153: int swap_out(void)
154: {
1.1.1.2 root 155: static int dir_entry = 1024;
1.1 root 156: static int page_entry = -1;
157: int counter = VM_PAGES;
1.1.1.3 root 158: int pg_table;
1.1 root 159:
1.1.1.3 root 160: check_dir:
161: if (counter < 0)
162: goto no_swap;
163: if (dir_entry >= 1024)
164: dir_entry = FIRST_VM_PAGE>>10;
165: if (!(1 & (pg_table = pg_dir[dir_entry]))) {
166: if (pg_table) {
167: printk("bad page-table at pg_dir[%d]: %08x\n\r",
168: dir_entry,pg_table);
169: pg_dir[dir_entry] = 0;
170: }
1.1 root 171: counter -= 1024;
172: dir_entry++;
1.1.1.3 root 173: goto check_dir;
1.1 root 174: }
175: pg_table &= 0xfffff000;
1.1.1.3 root 176: check_table:
177: if (counter < 0)
178: goto no_swap;
179: counter--;
180: page_entry++;
181: if (page_entry >= 1024) {
182: page_entry = -1;
183: dir_entry++;
184: goto check_dir;
1.1 root 185: }
1.1.1.4 ! root 186: if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
! 187: if (! task[dir_entry >> 4])
! 188: printk("swapping out page from non-existent task\n\r");
! 189: else
! 190: task[dir_entry >> 4]->rss--;
1.1.1.3 root 191: return 1;
1.1.1.4 ! root 192: }
1.1.1.3 root 193: goto check_table;
194: no_swap:
1.1 root 195: printk("Out of swap-memory\n\r");
196: return 0;
197: }
198:
199: /*
200: * Get physical address of first (actually last :-) free page, and mark it
201: * used. If no free pages left, return 0.
202: */
203: unsigned long get_free_page(void)
204: {
1.1.1.2 root 205: unsigned long result;
1.1 root 206:
207: repeat:
208: __asm__("std ; repne ; scasb\n\t"
209: "jne 1f\n\t"
210: "movb $1,1(%%edi)\n\t"
211: "sall $12,%%ecx\n\t"
212: "addl %2,%%ecx\n\t"
213: "movl %%ecx,%%edx\n\t"
214: "movl $1024,%%ecx\n\t"
215: "leal 4092(%%edx),%%edi\n\t"
216: "rep ; stosl\n\t"
217: "movl %%edx,%%eax\n"
1.1.1.2 root 218: "1:\tcld"
219: :"=a" (result)
1.1 root 220: :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
221: "D" (mem_map+PAGING_PAGES-1)
222: :"di","cx","dx");
1.1.1.2 root 223: if (result >= HIGH_MEMORY)
1.1 root 224: goto repeat;
1.1.1.2 root 225: if ((result && result < LOW_MEM) || (result & 0xfff)) {
226: printk("weird result: %08x\n",result);
227: result = 0;
228: }
229: if (!result && swap_out())
1.1 root 230: goto repeat;
1.1.1.2 root 231: return result;
1.1 root 232: }
233:
1.1.1.2 root 234: /*
235: * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
236: *
237: * The swapon system call
238: */
239:
240: int sys_swapon(const char * specialfile)
1.1 root 241: {
1.1.1.2 root 242: struct inode * swap_inode;
243: int i,j;
1.1 root 244:
1.1.1.2 root 245: if (!suser())
246: return -EPERM;
247: if (!(swap_inode = namei(specialfile)))
248: return -ENOENT;
249: if (swap_file || swap_device || swap_bitmap) {
250: iput(swap_inode);
251: return -EBUSY;
252: }
253: if (S_ISBLK(swap_inode->i_mode)) {
254: swap_device = swap_inode->i_rdev;
255: iput(swap_inode);
256: } else if (S_ISREG(swap_inode->i_mode))
257: swap_file = swap_inode;
258: else {
259: iput(swap_inode);
260: return -EINVAL;
1.1 root 261: }
262: swap_bitmap = (char *) get_free_page();
263: if (!swap_bitmap) {
1.1.1.2 root 264: iput(swap_file);
265: swap_device = 0;
266: swap_file = NULL;
267: printk("Unable to start swapping: out of memory :-)\n");
268: return -ENOMEM;
1.1 root 269: }
270: read_swap_page(0,swap_bitmap);
271: if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) {
272: printk("Unable to find swap-space signature\n\r");
273: free_page((long) swap_bitmap);
1.1.1.2 root 274: iput(swap_file);
275: swap_device = 0;
276: swap_file = NULL;
1.1 root 277: swap_bitmap = NULL;
1.1.1.2 root 278: return -EINVAL;
1.1 root 279: }
280: memset(swap_bitmap+4086,0,10);
281: j = 0;
1.1.1.2 root 282: for (i = 1 ; i < SWAP_BITS ; i++)
1.1 root 283: if (bit(swap_bitmap,i))
284: j++;
285: if (!j) {
1.1.1.2 root 286: printk("Empty swap-file\n");
1.1 root 287: free_page((long) swap_bitmap);
1.1.1.2 root 288: iput(swap_file);
289: swap_device = 0;
290: swap_file = NULL;
1.1 root 291: swap_bitmap = NULL;
1.1.1.2 root 292: return -EINVAL;
1.1 root 293: }
1.1.1.2 root 294: printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
295: return 0;
1.1 root 296: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.