|
|
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.3 ! root 186: if (try_to_swap_out(page_entry + (unsigned long *) pg_table))
! 187: return 1;
! 188: goto check_table;
! 189: no_swap:
1.1 root 190: printk("Out of swap-memory\n\r");
191: return 0;
192: }
193:
194: /*
195: * Get physical address of first (actually last :-) free page, and mark it
196: * used. If no free pages left, return 0.
197: */
198: unsigned long get_free_page(void)
199: {
1.1.1.2 root 200: unsigned long result;
1.1 root 201:
202: repeat:
203: __asm__("std ; repne ; scasb\n\t"
204: "jne 1f\n\t"
205: "movb $1,1(%%edi)\n\t"
206: "sall $12,%%ecx\n\t"
207: "addl %2,%%ecx\n\t"
208: "movl %%ecx,%%edx\n\t"
209: "movl $1024,%%ecx\n\t"
210: "leal 4092(%%edx),%%edi\n\t"
211: "rep ; stosl\n\t"
212: "movl %%edx,%%eax\n"
1.1.1.2 root 213: "1:\tcld"
214: :"=a" (result)
1.1 root 215: :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
216: "D" (mem_map+PAGING_PAGES-1)
217: :"di","cx","dx");
1.1.1.2 root 218: if (result >= HIGH_MEMORY)
1.1 root 219: goto repeat;
1.1.1.2 root 220: if ((result && result < LOW_MEM) || (result & 0xfff)) {
221: printk("weird result: %08x\n",result);
222: result = 0;
223: }
224: if (!result && swap_out())
1.1 root 225: goto repeat;
1.1.1.2 root 226: return result;
1.1 root 227: }
228:
1.1.1.2 root 229: /*
230: * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
231: *
232: * The swapon system call
233: */
234:
235: int sys_swapon(const char * specialfile)
1.1 root 236: {
1.1.1.2 root 237: struct inode * swap_inode;
238: int i,j;
1.1 root 239:
1.1.1.2 root 240: if (!suser())
241: return -EPERM;
242: if (!(swap_inode = namei(specialfile)))
243: return -ENOENT;
244: if (swap_file || swap_device || swap_bitmap) {
245: iput(swap_inode);
246: return -EBUSY;
247: }
248: if (S_ISBLK(swap_inode->i_mode)) {
249: swap_device = swap_inode->i_rdev;
250: iput(swap_inode);
251: } else if (S_ISREG(swap_inode->i_mode))
252: swap_file = swap_inode;
253: else {
254: iput(swap_inode);
255: return -EINVAL;
1.1 root 256: }
257: swap_bitmap = (char *) get_free_page();
258: if (!swap_bitmap) {
1.1.1.2 root 259: iput(swap_file);
260: swap_device = 0;
261: swap_file = NULL;
262: printk("Unable to start swapping: out of memory :-)\n");
263: return -ENOMEM;
1.1 root 264: }
265: read_swap_page(0,swap_bitmap);
266: if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) {
267: printk("Unable to find swap-space signature\n\r");
268: free_page((long) swap_bitmap);
1.1.1.2 root 269: iput(swap_file);
270: swap_device = 0;
271: swap_file = NULL;
1.1 root 272: swap_bitmap = NULL;
1.1.1.2 root 273: return -EINVAL;
1.1 root 274: }
275: memset(swap_bitmap+4086,0,10);
276: j = 0;
1.1.1.2 root 277: for (i = 1 ; i < SWAP_BITS ; i++)
1.1 root 278: if (bit(swap_bitmap,i))
279: j++;
280: if (!j) {
1.1.1.2 root 281: printk("Empty swap-file\n");
1.1 root 282: free_page((long) swap_bitmap);
1.1.1.2 root 283: iput(swap_file);
284: swap_device = 0;
285: swap_file = NULL;
1.1 root 286: swap_bitmap = NULL;
1.1.1.2 root 287: return -EINVAL;
1.1 root 288: }
1.1.1.2 root 289: printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
290: return 0;
1.1 root 291: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.