����13-3 linux/mm/swap.c
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 */
/*
* ������Ӧ�ð�������ִ���ڴ潻���Ĵ��루���ڴ浽���̻�֮����
* ��91��12��18�տ�ʼ���ơ�
*/
11
12 #include <string.h> // �ַ���ͷ�ļ���������һЩ�й��ڴ���ַ���������Ƕ�뺯����
13
14 #include <linux/mm.h> // �ڴ����ͷ�ļ�������ҳ�泤�ȣ���һЩ�ڴ��������ԭ�͡�
15 #include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0�����ݣ�
// ����һЩ�й��������������úͻ�ȡ��Ƕ��ʽ��ຯ������䡣
16 #include <linux/head.h> // headͷ�ļ��������˶��������ļṹ���ͼ���ѡ���������
17 #include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�Ͷ��塣
18
// ÿ���ֽ�8λ�����1ҳ��4096�ֽڣ�����32768������λ����1������λ��Ӧ1ҳ�ڴ棬
// �����ɹ���32768��ҳ�棬��Ӧ128MB�ڴ�������
19 #define SWAP_BITS (4096<<3)
20
// ����λ�����ꡣͨ��������ͬ��"op"���ɶ����ָ������λ���в��ԡ����û�������ֲ�����
// ����addr��ָ�����Ե�ַ��nr��ָ����ַ����ʼ�ı���λƫ��λ���ú�Ѹ�����ַaddr��
// ��nr������λ��ֵ�����λ��־�����û�λ�ñ���λ�����ؽ�λ��־ֵ����ԭ����λֵ����
// ��25���ϵ�һ��ָ����"op"�ַ��IJ�ͬ������γɲ�ͬ��ָ�
// ��"op"= ""ʱ������ָ��bt �C ��Bit Test�����Բ���ԭֵ���ý�λλ��
// ��"op"="s"ʱ������ָ��bts - ��Bit Test and Set�����ñ���λֵ����ԭֵ���ý�λλ��
// ��"op"="r"ʱ������ָ��btr - ��Bit Test and Reset����λ����λֵ��ԭֵ���ý�λλ��
// ���룺%0 �C ������ֵ)��%1 -λƫ��(nr)��%2 �C��ַ(addr)��%3 �C �Ӳ����Ĵ�����ֵ(0)��
// ��Ƕ������ѻ���ַ��%2���ͱ���ƫ��ֵ��%1����ָ���ı���λֵ�ȱ��浽��λ��־CF�У�
// Ȼ�����ã���λ���ñ���λ��ָ��adcl�Ǵ���λλ�ӣ����ڸ��ݽ�λλCF���ò�������%0����
// ���CF = 1 �ؼĴ���ֵ = 1�����ؼĴ���ֵ = 0 ��
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
// ������ݲ�ͬ��op�ַ�����3����Ƕ������
31 bitop(bit,"") // ������Ƕ���� bit(char * addr, unsigned int nr)��
32 bitop(setbit,"s") // ������Ƕ���� setbit(char * addr, unsigned int nr)��
33 bitop(clrbit,"r") // ������Ƕ���� clrbit(char * addr, unsigned int nr)��
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 */
/*
* ���ǴӲ���������0��task[0]����ҳ�� �C ���������ں�ҳ�档
* ����ֻ������ҳ����н���������
*/
// ��1�������ڴ�ҳ�档��������0ĩ�ˣ�64MB������ʼ�������ڴ�ҳ�档
42 #define FIRST_VM_PAGE (TASK_SIZE>>12) // = 64MB/4KB = 16384��
43 #define LAST_VM_PAGE (1024*1024) // = 4GB/4KB = 1048576��
44 #define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE) // = 1032192����0��ʼ�ƣ���
45
// ����1ҳ����ҳ�档
// ɨ����������ӳ��λͼ������Ӧλͼ������λ0���⣩������ֵΪ1�ĵ�һ������λ�ţ�
// ��Ŀǰ���еĽ���ҳ��š��������ɹ��ؽ���ҳ��ţ�����0��
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
// �ͷŽ����豸��ָ���Ľ���ҳ�档
// �ڽ���λͼ������ָ��ҳ��Ŷ�Ӧ�ı���λ����1������ԭ���ñ���λ�͵���1�����ʾ
// �����豸��ԭ����ҳ���û�б�ռ�ã�����λͼ������������ʾ������Ϣ�����ء�
// ����ָ������ҳ��š�
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
// ���ȼ�齻��λͼ�Ͳ�����Ч�ԡ��������λͼ�����ڣ�����ָ��ҳ�����Ӧ��ҳ���Ѵ���
// ���ڴ��У����߽���ҳ���Ϊ 0������ʾ������Ϣ���˳��������ѷŵ������豸��ȥ���ڴ�
// ҳ�棬��Ӧҳ�����д�ŵ�Ӧ�ǽ���ҳ���*2����(swap_nr << 1)���μ�����Գ��Խ�����
// ��try_to_swap_out()�е�111�е�˵����
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 }
// Ȼ������һҳ�����ڴ沢�ӽ����豸�ж���ҳ���Ϊswap_nr��ҳ�档�ڰ�ҳ�潻������
// �Ͱѽ���λͼ�ж�Ӧ����λ��λ�������ԭ��������λ�ģ�˵���˴����ٴδӽ�����
// ���ж�����ͬ��ҳ�棬������ʾһ�¾�����Ϣ�������ҳ����ָ�������ҳ�棬������ҳ
// �����ġ��û��ɶ�д�ʹ��ڱ�־��Dirty��U/S��R/W��P����
87 if (!(page = get_free_page()))
88 oom();
89 read_swap_page(swap_nr, (char *) page); // ��include/linux/mm.h�ж��塣
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
// ����ҳ�潻����ȥ��
// ��ҳ��û�б��Ĺ����ñ����ڽ����豸�У���Ϊ��Ӧҳ�滹������ֱ�Ӵ���Ӧӳ���ļ�
// �ж��롣���ǿ���ֱ���ͷŵ���Ӧ����ҳ�����¡����������һ������ҳ��ţ�Ȼ���ҳ��
// ������ȥ����ʱ����ҳ���Ҫ�����ڶ�Ӧҳ�����У���������Ҫ����ҳ�������λP = 0��
// ������ҳ����ָ�롣ҳ�潻�����ͷųɹ�����1������0��
95 int try_to_swap_out(unsigned long * table_ptr)
96 {
97 unsigned long page;
98 unsigned long swap_nr;
99
// �����жϲ�������Ч�ԡ�����Ҫ������ȥ���ڴ�ҳ�沢�����ڣ������Ч�������˳���
// ��ҳ����ָ��������ҳ���ַ���ڷ�ҳ�������ڴ�߶�PAGING_MEMORY��15MB����Ҳ�˳���
100 page = *table_ptr;
101 if (!(PAGE_PRESENT & page))
102 return 0;
103 if (page - LOW_MEM > PAGING_MEMORY)
104 return 0;
// ���ڴ�ҳ���ѱ��Ĺ������Ǹ�ҳ���DZ������ģ���ôΪ���������Ч�ʣ�����ҳ�治��
// ��������ȥ������ֱ���˳�����������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;
// ����Ҫ�������豸�е�ҳ�棬��Ӧҳ�����н���ŵ���(swap_nr << 1)�� ��2������1λ��
// ��Ϊ�˿ճ�ԭ��ҳ����Ĵ���λ��P����ֻ�д���λP=0����ҳ�������ݲ�Ϊ0��ҳ��Ż�
// �ڽ����豸�С� Intel�ֲ�����ȷָ������һ������Ĵ���λ P = 0ʱ����Чҳ�����
// ��������λ��λ31��1���ɹ�����ʹ�á�����д����ҳ����write_swap_page(nr, buffer)
// ������Ϊll_rw_page(WRITE,SWAP_DEV,(nr),(buffer))���μ�linux/mm.h �ļ���12�С�
111 *table_ptr = swap_nr<<1;
112 invalidate(); // ˢ��CPUҳ�任���ٻ��塣
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 */
/*
* OK�������������һ���dz����ӵ��� �C ���ڲ������Ժò����ٶȿ��
* �����롣������Dz��Դ˲��ĵĻ�����ô������ܸ�����Щ��
*/
// ���ڴ�ҳ��ŵ������豸�С�
// �����Ե�ַ64MB��Ӧ��Ŀ¼�FIRST_VM_PAGE>>10����ʼ����������4GB���Կռ䣬����
// ЧҳĿ¼����ҳ����ҳ����ָ���������ڴ�ҳ��ִ�н����������豸��ȥ�ij��ԡ�һ���ɹ�
// �ػ���һ��ҳ�棬�ͷ���1������0���ú�������get_free_page()�б����á�
128 int swap_out(void)
129 {
130 static int dir_entry = FIRST_VM_PAGE>>10; // ������1�ĵ�1��Ŀ¼��������
131 static int page_entry = -1;
132 int counter = VM_PAGES;
133 int pg_table;
134
// ��������ҳĿ¼�������Ҷ���ҳ�����ڵ�ҳĿ¼��pg_table���ҵ����˳�ѭ�����������
// ҳĿ¼������Ӧʣ�����ҳ������counter��Ȼ����������һҳĿ¼� ��ȫ��������
// ��û���ҵ��ʺϵģ����ڵģ�ҳĿ¼������¼���������
135 while (counter>0) {
136 pg_table = pg_dir[dir_entry]; // ҳĿ¼�����ݡ�
137 if (pg_table & 1)
138 break;
139 counter -= 1024; // 1��ҳ����Ӧ1024��ҳ֡��
140 dir_entry++; // ��һĿ¼�
141 if (dir_entry >= 1024)
142 dir_entry = FIRST_VM_PAGE>>10;
143 }
// ��ȡ�õ�ǰĿ¼���ҳ��ָ�����Ը�ҳ���е����� 1024 ��ҳ�棬��һ���ý�������
// try_to_swap_out()���Խ�����ȥ��һ��ij��ҳ��ɹ������������豸�оͷ���1��������
// ��Ŀ¼�������ҳ�����ѳ���ʧ�ܣ�����ʾ�������ڴ����ꡱ�ľ��棬������0��
144 pg_table &= 0xfffff000; // ҳ��ָ�루��ַ����
145 while (counter-- > 0) {
146 page_entry++; // ҳ������������ʼΪ-1����
// ����Ѿ����Դ����굱ǰҳ�������û���ܹ��ɹ��ؽ�����һ��ҳ�棬����ʱҳ��������
// ���ڵ���1024������ͬǰ���135 �C 143��ִ����ͬ�Ĵ�����ѡ��һ������ҳ�����ڵ�ҳ
// Ŀ¼���ȡ����Ӧ����ҳ��ָ�롣
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 */
/*
* ��ȡ��(ʵ���������1��:-)����ҳ�棬�����Ϊ��ʹ�á����û�п���ҳ�棬
* �ͷ���0��
*/
//// �����ڴ���������1ҳ��������ҳ�档
// ����Ѿ�û�п��������ڴ�ҳ�棬�����ִ�н���������Ȼ���ٴ�����ҳ�档
// ���룺%1(ax=0) - 0��%2(LOW_MEM)�ڴ��ֽ�λͼ��������ʼλ�ã�%3(cx= PAGING_PAGES)��
// %4(edi=mem_map+PAGING_PAGES-1)��
// ���������%0��ax = ����ҳ����ʼ��ַ��������������ҳ���������ַ��
// ����%4�Ĵ���ʵ��ָ��mem_map[]�ڴ��ֽ�λͼ�����һ���ֽڡ���������λͼĩ�˿�ʼ��
// ǰɨ������ҳ���־��ҳ������ΪPAGING_PAGES��������ҳ����У��ڴ�λͼ�ֽ�Ϊ0����
// ����ҳ���ַ��ע�⣡������ֻ��ָ�������ڴ�����һҳ��������ҳ�棬����û��ӳ�䵽ij
// �����̵ĵ�ַ�ռ���ȥ������� put_page() ���������ڰ�ָ��ҳ��ӳ�䵽ij�����̵ĵ�ַ
// �ռ��С���Ȼ�����ں�ʹ�ñ�����������Ҫ��ʹ�� put_page() ����ӳ�䣬��Ϊ�ں˴����
// ���ݿռ䣨16MB���Ѿ��Եȵ�ӳ�䵽������ַ�ռ䡣
// ��65�ж�����һ���ֲ��Ĵ����������ñ������������� eax�Ĵ����У��Ա��ڸ�Ч���ʺ�
// ���������ֶ�������ķ�����Ҫ������Ƕ�������С���ϸ˵���μ�gcc�ֲᡰ��ָ���Ĵ�
// ���еı�������
172 unsigned long get_free_page(void)
173 {
174 register unsigned long __res asm("ax");
175
// �������ڴ�ӳ���ֽ�λͼ�в���ֵΪ0���ֽ��Ȼ��Ѷ�Ӧ�����ڴ�ҳ�����㡣����õ�
// ��ҳ���ַ����ʵ�������ڴ�����������Ѱ�ҡ����û���ҵ�����ҳ����ȥ����ִ�н�����
// ���������²��ҡ���ؿ�������ҳ���ַ��
176 repeat:
177 __asm__("std ; repne ; scasb\n\t" // �÷���λ��al(0)���Ӧÿ��ҳ���(di)���ݱȽϣ�
178 "jne 1f\n\t" // ���û�е���0���ֽڣ�����ת����������0����
179 "movb $1,1(%%edi)\n\t" // 1 =>[1+edi], ����Ӧҳ���ڴ�ӳ�����λ��1��
180 "sall $12,%%ecx\n\t" // ҳ����*4K = ���ҳ����ʼ��ַ��
181 "addl %2,%%ecx\n\t" // �ټ��ϵͶ��ڴ��ַ����ҳ��ʵ��������ʼ��ַ��
182 "movl %%ecx,%%edx\n\t" // ��ҳ��ʵ����ʼ��ַ��edx�Ĵ�����
183 "movl $1024,%%ecx\n\t" // �Ĵ���ecx�ü���ֵ1024��
184 "leal 4092(%%edx),%%edi\n\t" // ��4092+edx��λ����edi����ҳ���ĩ�ˣ���
185 "rep ; stosl\n\t" // ��edi��ָ�ڴ����㣨����������ҳ�����㣩��
186 "movl %%edx,%%eax\n" // ��ҳ����ʼ��ַ��eax������ֵ����
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 {
// blk_size[]ָ��ָ�����豸�ŵĿ��豸�������顣�ÿ�������ÿһ���Ӧһ�����豸����
// ӵ�е����ݿ�������1���С=1KB����
201 extern int *blk_size[]; // blk_drv/ll_rw_blk.c��49��
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 }
// ȡָ�������豸�ŵĽ��������ݿ�����swap_size����Ϊ0�أ����ܿ���С��100��
// ����ʾ��Ϣ�������豸��̫С����Ȼ���˳���
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 }
// �������ݿ�����ת���ɶ�Ӧ�ɽ���ҳ����������ֵ���ܴ���SWAP_BITS���ܱ�ʾ��ҳ������
// ������ҳ���������ô��� 32768�� Ȼ������һҳ�����ڴ�������Ž���ҳ��λӳ������
// swap_bitmap������ÿ1���ش���1ҳ����ҳ�档
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 }
// read_swap_page(nr, buffer)������Ϊll_rw_page(READ,SWAP_DEV,(nr),(buffer))��
// �μ�linux/mm.h�ļ���11�С�����ѽ����豸�ϵ�ҳ��0����swap_bitmapҳ���С�
// ��ҳ���ǽ���������ҳ�档���е�4086�ֽڿ�ʼ������10���ַ��Ľ����豸������
// ������SWAP-SPACE������û���ҵ��������ַ�������˵������һ����Ч�Ľ����豸��
// ������ʾ��Ϣ���ͷŸ����������ҳ�沢�˳����������������ַ����ֽ����㡣
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);
// Ȼ�������Ľ���λӳ��ͼ��Ӧ��32768������λȫΪ0����λͼ������λ�ı���λ0��
// ���ʾλͼ�����⣬������ʾ������Ϣ���ͷ�λͼռ�õ�ҳ�沢�˳�������Ϊ�˼ӿ���
// �ٶȣ��������Ƚ���ѡ�鿴λͼ��λ0�����һ������ҳ���Ӧ�ı���λ����swap_size
// ����ҳ���Ӧ�ı���λ���Լ����SWAP_BITS��32768������λ��
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 }
// Ȼ������ϸ�ؼ��λ1��λswap_size���б���λ�Ƿ�Ϊ0�����в���0�ı���λ���ڣ�
// ���ʾλͼ�����⣬�����ͷ�λͼռ�õ�ҳ�沢�˳�������������ʾ�����豸��������
// �Լ�����ҳ�����ͽ����ռ����ֽ�����
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 }
254