1 /*
2 * malloc.c --- a general purpose kernel memory allocator for Linux.
3 *
4 * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91
5 *
6 * This routine is written to be as fast as possible, so that it
7 * can be called from the interrupt level.
8 *
9 * Limitations: maximum size of memory we can allocate using this routine
10 * is 4k, the size of a page in Linux.
11 *
12 * The general game plan is that each page (called a bucket) will only hold
13 * objects of a given size. When all of the object on a page are released,
14 * the page can be returned to the general free pool. When malloc() is
15 * called, it looks for the smallest bucket size which will fulfill its
16 * request, and allocate a piece of memory from that bucket pool.
17 *
18 * Each bucket has as its control block a bucket descriptor which keeps
19 * track of how many objects are in use on that page, and the free list
20 * for that page. Like the buckets themselves, bucket descriptors are
21 * stored on pages requested from get_free_page(). However, unlike buckets,
22 * pages devoted to bucket descriptor pages are never released back to the
23 * system. Fortunately, a system should probably only need 1 or 2 bucket
24 * descriptor pages, since a page can hold 256 bucket descriptors (which
25 * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using
26 * that much allocated memory, it's probably doing something wrong. :-)
27 *
28 * Note: malloc() and free() both call get_free_page() and free_page()
29 * in sections of code where interrupts are turned off, to allow
30 * malloc() and free() to be safely called from an interrupt routine.
31 * (We will probably need this functionality when networking code,
32 * particularily things like NFS, is added to Linux.) However, this
33 * presumes that get_free_page() and free_page() are interrupt-level
34 * safe, which they may not be once paging is added. If this is the
35 * case, we will need to modify malloc() to keep a few unused pages
36 * "pre-allocated" so that it can safely draw upon those pages if
37 * it is called from an interrupt routine.
38 *
39 * Another concern is that get_free_page() should not sleep; if it
40 * does, the code is carefully ordered so as to avoid any race
41 * conditions. The catch is that if malloc() is called re-entrantly,
42 * there is a chance that unecessary pages will be grabbed from the
43 * system. Except for the pages for the bucket descriptor page, the
44 * extra pages will eventually get released back to the system, though,
45 * so it isn't all that bad.
46 */
47
/*
* malloc.c - Linux��ͨ���ں��ڴ���亯����
*
* ��Theodore Ts'o���� (tytso@mit.edu), 11/29/91
*
* �ú�������д�ɾ����ܵؿ죬�Ӷ����Դ��жϲ���ô˺�����
*
* ���ƣ�ʹ�øú���һ�����ܷ��������ڴ���4k��Ҳ��Linux���ڴ�ҳ��Ĵ�С��
*
* ��д�ú�������ѭ��һ�������ÿҳ(����Ϊһ���洢Ͱ)��������Ҫ���ɶ���Ĵ�С��
* ��һҳ�ϵ����ж����ͷź�ҳ�Ϳ��Է���ͨ�ÿ����ڴ�ء���malloc()������
* ʱ������Ѱ������Ҫ�����С�Ĵ洢Ͱ�����Ӹô洢Ͱ�з���һ���ڴ档
*
* ÿ���洢Ͱ����һ����Ϊ������õĴ洢Ͱ�����������м�¼��ҳ�����ж��ٶ�������
* ʹ���Լ���ҳ�Ͽ����ڴ���б�������洢Ͱ����һ�����洢Ͱ������Ҳ�Ǵ洢��ʹ��
* get_free_page()���뵽��ҳ���ϵģ�������洢Ͱ��ͬ���ǣ�Ͱ��������ռ�õ�ҳ��
* �����ٻ��ͷŸ�ϵͳ�����˵���һ��ϵͳ��Լֻ��Ҫ1��2ҳ��Ͱ������ҳ�棬��Ϊһ
* ��ҳ����Դ��256��Ͱ������(��Ӧ1MB�ڴ�Ĵ洢Ͱҳ��)�����ϵͳΪͰ��������
* ���������ڴ棬��ô�϶�ϵͳʲô�ط���������J��
*
* ע�⣡malloc()��free()���߹ر����жϵĴ��벿�ֶ�������get_free_page()��
* free_page()��������ʹmalloc()��free()����ȫ�ر����жϳ����е���
* (��������룬������NFS�ȱ����뵽Linux��ʱ�Ϳ�����Ҫ���ֹ���)����ǰ
* ���Ǽ���get_free_page()��free_page()�ǿ���ȫ�����жϼ�������ʹ�õģ�
* ����һ�������˷�ҳ����֮��Ϳ��ܲ��ǰ�ȫ�ġ�������������������ô����
* ����Ҫ��malloc()����Ԥ�ȷ��䡱��ҳ���õ��ڴ棬���malloc()��free()
* �����жϳ����е���ʱ�Ϳ���ȫ��ʹ����Щҳ�档
*
* ������Ҫ���ǵ�����get_free_page()��Ӧ��˯�ߣ������˯�ߵĻ�����Ϊ�˷�ֹ
* �κξ���������������Ҫ��ϸ�ذ���˳�� �ؼ��������malloc()�ǿ��������
* �����õĻ�����ô�ͻ���ڲ���Ҫ��ҳ�汻��ϵͳ��ȡ�ߵĻ��ᡣ��������Ͱ����
* ����ҳ�棬��Щ�����ҳ�����ջ��ͷŸ�ϵͳ�����Բ�������������������á�
*/
48 #include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣
49 #include <linux/mm.h> // �ڴ����ͷ�ļ�������ҳ���С�����һЩҳ���ͷź���ԭ�͡�
50 #include <asm/system.h> // ϵͳͷ�ļ������������û���������/�ж��ŵȵ�Ƕ��ʽ���ꡣ
51
// �洢Ͱ�������ṹ��
52 struct bucket_desc { /* 16 bytes */
53 void *page; // ��Ͱ��������Ӧ���ڴ�ҳ��ָ�롣
54 struct bucket_desc *next; // ��һ��������ָ�롣
55 void *freeptr; // ָ��Ͱ�п����ڴ�λ�õ�ָ�롣
56 unsigned short refcnt; // ���ü�����
57 unsigned short bucket_size; // ����������Ӧ�洢Ͱ�Ĵ�С��
58 };
59
// �洢Ͱ������Ŀ¼�ṹ��
60 struct _bucket_dir { /* 8 bytes */
61 int size; // �ô洢Ͱ�Ĵ�С(�ֽ���)��
62 struct bucket_desc *chain; // �ô洢ͰĿ¼���Ͱ����������ָ�롣
63 };
64
65 /*
66 * The following is the where we store a pointer to the first bucket
67 * descriptor for a given size.
68 *
69 * If it turns out that the Linux kernel allocates a lot of objects of a
70 * specific size, then we may want to add that specific size to this list,
71 * since that will allow the memory to be allocated more efficiently.
72 * However, since an entire page must be dedicated to each specific size
73 * on this list, some amount of temperance must be exercised here.
74 *
75 * Note that this list *must* be kept in order.
76 */
/*
* ���������Ǵ�ŵ�һ��������С�洢Ͱ������ָ��ĵط���
*
* ���Linux�ں˷���������ָ����С�Ķ�����ô���Ǿ�ϣ������ָ���Ĵ�С�ӵ�
* ���б�(����)�У���Ϊ��������ʹ�ڴ�ķ������Ч�����ǣ���Ϊһҳ�����ڴ�ҳ��
* ���������б���ָ����С�����ж���������Ҫ����������IJ��Բ�����
*/
// �洢ͰĿ¼�б�(����)��
77 struct _bucket_dir bucket_dir[] = {
78 { 16, (struct bucket_desc *) 0}, // 16�ֽڳ��ȵ��ڴ�顣
79 { 32, (struct bucket_desc *) 0}, // 32�ֽڳ��ȵ��ڴ�顣
80 { 64, (struct bucket_desc *) 0}, // 64�ֽڳ��ȵ��ڴ�顣
81 { 128, (struct bucket_desc *) 0}, // 128�ֽڳ��ȵ��ڴ�顣
82 { 256, (struct bucket_desc *) 0}, // 256�ֽڳ��ȵ��ڴ�顣
83 { 512, (struct bucket_desc *) 0}, // 512�ֽڳ��ȵ��ڴ�顣
84 { 1024, (struct bucket_desc *) 0}, // 1024�ֽڳ��ȵ��ڴ�顣
85 { 2048, (struct bucket_desc *) 0}, // 2048�ֽڳ��ȵ��ڴ�顣
86 { 4096, (struct bucket_desc *) 0}, // 4096�ֽ�(1ҳ)�ڴ档
87 { 0, (struct bucket_desc *) 0}}; /* End of list marker */
88
89 /*
90 * This contains a linked list of free bucket descriptor blocks
91 */
/*
* �����Ǻ��п���Ͱ�������ڴ���������
*/
92 struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0;
93
94 /*
95 * This routine initializes a bucket description page.
96 */
/*
* ������ӳ������ڳ�ʼ��һҳͰ������ҳ�档
*/
//// ��ʼ��Ͱ��������
// ��������Ͱ����������������free_bucket_descָ���һ������Ͱ��������
97 static inline void init_bucket_desc()
98 {
99 struct bucket_desc *bdesc, *first;
100 int i;
101
// ����һҳ�ڴ棬���ڴ��Ͱ�����������ʧ�ܣ�����ʾ��ʼ��Ͱ������ʱ�ڴ治��������Ϣ��������
102 first = bdesc = (struct bucket_desc *) get_free_page();
103 if (!bdesc)
104 panic("Out of memory in init_bucket_desc()");
// ���ȼ���һҳ�ڴ��пɴ�ŵ�Ͱ������������Ȼ����佨����������ָ�롣
105 for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) {
106 bdesc->next = bdesc+1;
107 bdesc++;
108 }
109 /*
110 * This is done last, to avoid race conditions in case
111 * get_free_page() sleeps and this routine gets called again....
112 */
/*
* ������������ģ�Ŀ����Ϊ�˱�����get_free_page()˯��ʱ���ӳ����ֱ�
* ���ö�����ľ���������
*/
// ������Ͱ������ָ��free_bucket_desc���������С�
113 bdesc->next = free_bucket_desc;
114 free_bucket_desc = first;
115 }
116
//// ���䶯̬�ڴ溯����
// ������len - ������ڴ�鳤�ȡ�
// ���أ�ָ�����ڴ��ָ�롣���ʧ����NULL��
117 void *malloc(unsigned int len)
118 {
119 struct _bucket_dir *bdir;
120 struct bucket_desc *bdesc;
121 void *retval;
122
123 /*
124 * First we search the bucket_dir to find the right bucket change
125 * for this request.
126 */
/*
* �������������洢ͰĿ¼bucket_dir��Ѱ���ʺ������Ͱ��С��
*/
// �����洢ͰĿ¼��Ѱ���ʺ������ڴ���С��Ͱ���������������Ŀ¼���Ͱ�ֽ�������������ֽ�
// �������ҵ��˶�Ӧ��ͰĿ¼�
127 for (bdir = bucket_dir; bdir->size; bdir++)
128 if (bdir->size >= len)
129 break;
// �������������Ŀ¼��û���ҵ����ʴ�С��Ŀ¼��������������ڴ���С̫�����˸�
// ����ķ�������(�Ϊ1��ҳ��)��������ʾ������Ϣ��������
130 if (!bdir->size) {
131 printk("malloc called with impossibly large argument (%d)\n",
132 len);
133 panic("malloc: bad arg");
134 }
135 /*
136 * Now we search for a bucket descriptor which has free space
137 */
/*
* �����������������п��пռ��Ͱ��������
*/
138 cli(); /* Avoid race conditions */ /* Ϊ�˱�����־������������ȹ��ж� */
// ������ӦͰĿ¼�������������������Ҿ��п��пռ��Ͱ�����������Ͱ�������Ŀ����ڴ�ָ��
// freeptr��Ϊ�գ����ʾ�ҵ�����Ӧ��Ͱ��������
139 for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next)
140 if (bdesc->freeptr)
141 break;
142 /*
143 * If we didn't find a bucket with free space, then we'll
144 * allocate a new one.
145 */
/*
* ���û���ҵ����п��пռ��Ͱ����������ô���Ǿ�Ҫ�½���һ����Ŀ¼�����������
*/
146 if (!bdesc) {
147 char *cp;
148 int i;
149
// ��free_bucket_desc��Ϊ��ʱ����ʾ��һ�ε��øó��������������п�Ͱ�������������ꡣ
// ��ʱ����Ҫ����һ��ҳ�沢�����Ͻ�������ʼ������������������free_bucket_desc��ָ���һ
// ������Ͱ��������
150 if (!free_bucket_desc)
151 init_bucket_desc();
// ȡfree_bucket_descָ��Ŀ���Ͱ������������free_bucket_descָ����һ������Ͱ��������
152 bdesc = free_bucket_desc;
153 free_bucket_desc = bdesc->next;
// ��ʼ�����µ�Ͱ������������������������0��Ͱ�Ĵ�С���ڶ�ӦͰĿ¼�Ĵ�С������һ�ڴ�ҳ�棬
// ����������ҳ��ָ��pageָ���ҳ�棻�����ڴ�ָ��Ҳָ���ҳ��ͷ����Ϊ��ʱȫΪ���С�
154 bdesc->refcnt = 0;
155 bdesc->bucket_size = bdir->size;
156 bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
// ��������ڴ�ҳ�����ʧ�ܣ�����ʾ������Ϣ��������
157 if (!cp)
158 panic("Out of memory in kernel malloc()");
159 /* Set up the chain of free objects */
/* �ڸ�ҳ�����ڴ��н������ж������� */
// �Ը�ͰĿ¼��ָ����Ͱ��СΪ���ȣ��Ը�ҳ�ڴ���л��֣���ʹÿ������Ŀ�ʼ4�ֽ�����
// ��ָ����һ�����ָ�롣
160 for (i=PAGE_SIZE/bdir->size; i > 1; i--) {
161 *((char **) cp) = cp + bdir->size;
162 cp += bdir->size;
163 }
// ���һ������ʼ����ָ������Ϊ0(NULL)��
// Ȼ���ø�Ͱ����������һ������ָ���ֶ�ָ���ӦͰĿ¼��ָ��chain��ָ������������ͰĿ¼��
// chainָ���Ͱ��������Ҳ���������������뵽����������ͷ����
164 *((char **) cp) = 0;
165 bdesc->next = bdir->chain; /* OK, link it in! */ /* OK���������룡*/
166 bdir->chain = bdesc;
167 }
// ����ָ�뼴���ڸ���������Ӧҳ��ĵ�ǰ����ָ�롣Ȼ������ÿ��пռ�ָ��ָ����һ�����ж���
// ��ʹ�������ж�Ӧҳ���ж������ü�����1��
168 retval = (void *) bdesc->freeptr;
169 bdesc->freeptr = *((void **) retval);
170 bdesc->refcnt++;
// ����жϣ�������ָ������ڴ�����ָ�롣
171 sti(); /* OK, we're safe again */ /* OK�����������ְ�ȫ��*/
172 return(retval);
173 }
174
175 /*
176 * Here is the free routine. If you know the size of the object that you
177 * are freeing, then free_s() will use that information to speed up the
178 * search for the bucket descriptor.
179 *
180 * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)"
181 */
/*
* �������ͷ��ӳ��������֪���ͷŶ���Ĵ�С����free_s()��ʹ�ø���Ϣ����
* ��Ѱ��ӦͰ���������ٶȡ�
*
* ���ǽ�����һ���꣬ʹ��"free(x)"��Ϊ"free_s(x, 0)"��
*/
//// �ͷŴ洢Ͱ����
// ������obj - ��Ӧ����ָ�룻size - ��С��
182 void free_s(void *obj, int size)
183 {
184 void *page;
185 struct _bucket_dir *bdir;
186 struct bucket_desc *bdesc, *prev;
187
188 /* Calculate what page this object lives in */
/* ����ö������ڵ�ҳ�� */
189 page = (void *) ((unsigned long) obj & 0xfffff000);
190 /* Now search the buckets looking for that page */
/* ���������洢ͰĿ¼�������ӵ�Ͱ��������Ѱ�Ҹ�ҳ�� */
//
191 for (bdir = bucket_dir; bdir->size; bdir++) {
192 prev = 0;
193 /* If size is zero then this conditional is always false */
/* �������size��0�������������϶���false */
194 if (bdir->size < size)
195 continue;
// ������ӦĿ¼�������ӵ����������������Ҷ�Ӧҳ�档���ij������ҳ��ָ�����page���ʾ�ҵ�
// ����Ӧ������������ת��found����������������ж�Ӧpage������������ָ��prevָ�����������
196 for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) {
197 if (bdesc->page == page)
198 goto found;
199 prev = bdesc;
200 }
201 }
// �������˶�ӦĿ¼���������������û���ҵ�ָ����ҳ�棬����ʾ������Ϣ��������
202 panic("Bad address passed to kernel free_s()");
203 found:
// �ҵ���Ӧ��Ͱ�����������ȹ��жϡ�Ȼ�ö����ڴ��������п���������У���ʹ��������
// �Ķ������ü�����1��
204 cli(); /* To avoid race conditions */ /* Ϊ�˱��⾺������ */
205 *((void **)obj) = bdesc->freeptr;
206 bdesc->freeptr = obj;
207 bdesc->refcnt--;
// ������ü����ѵ���0�������ǾͿ����ͷŶ�Ӧ���ڴ�ҳ���Ͱ��������
208 if (bdesc->refcnt == 0) {
209 /*
210 * We need to make sure that prev is still accurate. It
211 * may not be, if someone rudely interrupted us....
212 */
/*
* ������Ҫȷ��prev��Ȼ����ȷ�ģ���ij�����³���ж�������
* ���п��ܲ����ˡ�
*/
// ���prev�Ѿ���������������������ǰһ����������������������ǰ��������ǰһ����������
213 if ((prev && (prev->next != bdesc)) ||
214 (!prev && (bdir->chain != bdesc)))
215 for (prev = bdir->chain; prev; prev = prev->next)
216 if (prev->next == bdesc)
217 break;
// ����ҵ���ǰһ�����������������������ɾ����ǰ��������
218 if (prev)
219 prev->next = bdesc->next;
// ���prev==NULL����˵����ǰһ���������Ǹ�Ŀ¼������������Ҳ��Ŀ¼����chainӦ��ֱ��
// ָ��ǰ������bdesc�������ʾ���������⣬����ʾ������Ϣ����������ˣ�Ϊ�˽���ǰ������
// ��������ɾ����Ӧ����chainָ����һ����������
220 else {
221 if (bdir->chain != bdesc)
222 panic("malloc bucket chains corrupted");
223 bdir->chain = bdesc->next;
224 }
// �ͷŵ�ǰ���������������ڴ�ҳ�棬�������������������������������ʼ����
225 free_page((unsigned long) bdesc->page);
226 bdesc->next = free_bucket_desc;
227 free_bucket_desc = bdesc;
228 }
// ���жϣ����ء�
229 sti();
230 return;
231 }
232
233