|
|
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:
1.1.1.2 root 12: #include <errno.h>
1.1.1.5 ! root 13: #include <sys/stat.h>
1.1 root 14:
15: #include <linux/mm.h>
1.1.1.5 ! root 16: #include <linux/string.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.1.5 ! root 152: *
! 153: * Here it's easy to add a check for tasks that may not be swapped out:
! 154: * loadable device drivers or similar. Just add an entry to the task-struct
! 155: * and check it at the same time you check for the existence of the task.
! 156: * The code assumes tasks are page-table aligned, but so do other parts
! 157: * of the memory manager...
1.1 root 158: */
159: int swap_out(void)
160: {
1.1.1.2 root 161: static int dir_entry = 1024;
1.1 root 162: static int page_entry = -1;
163: int counter = VM_PAGES;
1.1.1.3 root 164: int pg_table;
1.1.1.5 ! root 165: struct task_struct * p;
1.1 root 166:
1.1.1.3 root 167: check_dir:
168: if (counter < 0)
169: goto no_swap;
170: if (dir_entry >= 1024)
171: dir_entry = FIRST_VM_PAGE>>10;
1.1.1.5 ! root 172: if (!(p = task[dir_entry >> 4])) {
! 173: counter -= 1024;
! 174: dir_entry++;
! 175: goto check_dir;
! 176: }
1.1.1.3 root 177: if (!(1 & (pg_table = pg_dir[dir_entry]))) {
178: if (pg_table) {
179: printk("bad page-table at pg_dir[%d]: %08x\n\r",
180: dir_entry,pg_table);
181: pg_dir[dir_entry] = 0;
182: }
1.1 root 183: counter -= 1024;
184: dir_entry++;
1.1.1.3 root 185: goto check_dir;
1.1 root 186: }
187: pg_table &= 0xfffff000;
1.1.1.3 root 188: check_table:
189: if (counter < 0)
190: goto no_swap;
191: counter--;
192: page_entry++;
193: if (page_entry >= 1024) {
194: page_entry = -1;
195: dir_entry++;
196: goto check_dir;
1.1 root 197: }
1.1.1.4 root 198: if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
1.1.1.5 ! root 199: p->rss--;
1.1.1.3 root 200: return 1;
1.1.1.4 root 201: }
1.1.1.3 root 202: goto check_table;
203: no_swap:
1.1 root 204: printk("Out of swap-memory\n\r");
205: return 0;
206: }
207:
208: /*
209: * Get physical address of first (actually last :-) free page, and mark it
210: * used. If no free pages left, return 0.
211: */
212: unsigned long get_free_page(void)
213: {
1.1.1.2 root 214: unsigned long result;
1.1 root 215:
216: repeat:
217: __asm__("std ; repne ; scasb\n\t"
218: "jne 1f\n\t"
219: "movb $1,1(%%edi)\n\t"
220: "sall $12,%%ecx\n\t"
221: "addl %2,%%ecx\n\t"
222: "movl %%ecx,%%edx\n\t"
223: "movl $1024,%%ecx\n\t"
224: "leal 4092(%%edx),%%edi\n\t"
225: "rep ; stosl\n\t"
226: "movl %%edx,%%eax\n"
1.1.1.2 root 227: "1:\tcld"
228: :"=a" (result)
1.1 root 229: :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
230: "D" (mem_map+PAGING_PAGES-1)
231: :"di","cx","dx");
1.1.1.2 root 232: if (result >= HIGH_MEMORY)
1.1 root 233: goto repeat;
1.1.1.2 root 234: if ((result && result < LOW_MEM) || (result & 0xfff)) {
235: printk("weird result: %08x\n",result);
236: result = 0;
237: }
238: if (!result && swap_out())
1.1 root 239: goto repeat;
1.1.1.2 root 240: return result;
1.1 root 241: }
242:
1.1.1.2 root 243: /*
244: * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
245: *
246: * The swapon system call
247: */
248: int sys_swapon(const char * specialfile)
1.1 root 249: {
1.1.1.2 root 250: struct inode * swap_inode;
1.1.1.5 ! root 251: char * tmp;
1.1.1.2 root 252: int i,j;
1.1 root 253:
1.1.1.2 root 254: if (!suser())
255: return -EPERM;
256: if (!(swap_inode = namei(specialfile)))
257: return -ENOENT;
258: if (swap_file || swap_device || swap_bitmap) {
259: iput(swap_inode);
260: return -EBUSY;
261: }
262: if (S_ISBLK(swap_inode->i_mode)) {
263: swap_device = swap_inode->i_rdev;
264: iput(swap_inode);
265: } else if (S_ISREG(swap_inode->i_mode))
266: swap_file = swap_inode;
267: else {
268: iput(swap_inode);
269: return -EINVAL;
1.1 root 270: }
1.1.1.5 ! root 271: tmp = (char *) get_free_page();
! 272: if (!tmp) {
1.1.1.2 root 273: iput(swap_file);
274: swap_device = 0;
275: swap_file = NULL;
276: printk("Unable to start swapping: out of memory :-)\n");
277: return -ENOMEM;
1.1 root 278: }
1.1.1.5 ! root 279: read_swap_page(0,tmp);
! 280: if (strncmp("SWAP-SPACE",tmp+4086,10)) {
1.1 root 281: printk("Unable to find swap-space signature\n\r");
1.1.1.5 ! root 282: free_page((long) tmp);
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.5 ! root 289: memset(tmp+4086,0,10);
1.1 root 290: j = 0;
1.1.1.2 root 291: for (i = 1 ; i < SWAP_BITS ; i++)
1.1.1.5 ! root 292: if (bit(tmp,i))
1.1 root 293: j++;
294: if (!j) {
1.1.1.2 root 295: printk("Empty swap-file\n");
1.1.1.5 ! root 296: free_page((long) tmp);
1.1.1.2 root 297: iput(swap_file);
298: swap_device = 0;
299: swap_file = NULL;
1.1 root 300: swap_bitmap = NULL;
1.1.1.2 root 301: return -EINVAL;
1.1 root 302: }
1.1.1.5 ! root 303: swap_bitmap = tmp;
1.1.1.2 root 304: printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
305: return 0;
1.1 root 306: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.