1 /*
2 * linux/fs/buffer.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7 /*
8 * 'buffer.c' implements the buffer-cache functions. Race-conditions have
9 * been avoided by NEVER letting a interrupt change a buffer (except for the
10 * data, of course), but instead letting the caller do it. NOTE! As interrupts
11 * can wake up a caller, some cli-sti sequences are needed to check for
12 * sleep-on-calls. These should be extremely quick, though (I hope).
13 */
/*
* 'buffer.c'����ʵ�ֻ��������ٻ��湦�ܡ�ͨ�������жϴ������̸ı仺�����������õ�
* ������ִ�У������˾�����������Ȼ���ı��������⣩��ע�⣡�����жϿ��Ի���һ����
* ���ߣ���˾���Ҫ�����ж�ָ�cli-sti��������������ڵ��ö�˯�ߡ�����Ҫ�dz��ؿ�
* ����ϣ������������
*/
14
15 /*
16 * NOTE! There is one discordant note here: checking floppies for
17 * disk change. This is where it fits best, I think, as it should
18 * invalidate changed floppy-disk-caches.
19 */
/*
* ע�⣡��һ������Ӧ�����������������Ƿ�����������������Ƿ���
* �ó�����õĵط��ˣ���Ϊ����Ҫʹ�Ѹ������̻���ʧЧ��
*/
20
21 #include <stdarg.h> // ������ͷ�ļ����Ժ����ʽ������������б�����Ҫ˵����-��
// ����(va_list)��������(va_start, va_arg��va_end)������
// vsprintf��vprintf��vfprintf������
22
23 #include <linux/config.h> // �ں�����ͷ�ļ�������������Ժ�Ӳ�����ͣ�HD_TYPE����ѡ�
24 #include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0�����ݣ�
// ����һЩ�й��������������úͻ�ȡ��Ƕ��ʽ��ຯ������䡣
25 #include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣
26 #include <asm/system.h> // ϵͳͷ�ļ������������û���������/�ж��ŵȵ�Ƕ����ꡣ
27 #include <asm/io.h> // ioͷ�ļ�������Ӳ���˿�����/���������䡣
28
// ����end���ɱ���ʱ�����ӳ���ld���ɣ����ڱ����ں˴����ĩ�ˣ���ָ���ں�ģ��ĩ��
// λ�ã��μ�����!δ�ҵ�����Դ����Ҳ���Դӱ����ں�ʱ���ɵ� System.map�ļ��в����������������
// �����ٻ�������ʼ���ں˴���ĩ��λ�á�
// ��33���ϵ�buffer_wait�����ǵȴ����л�����˯�ߵ��������ͷָ�롣���뻺���ͷ
// ���ṹ��b_waitָ������ò�ͬ������������һ����������������ϵͳȱ�����ÿ��л�
// ���ʱ����ǰ����ͻᱻ���ӵ�buffer_wait˯�ߵȴ������С���b_wait����ר�Ź��ȴ�
// ָ������飨��b_wait��Ӧ�Ļ���飩������ʹ�õĵȴ�����ͷָ�롣
29 extern int end;
30 struct buffer_head * start_buffer = (struct buffer_head *) &end;
31 struct buffer_head * hash_table[NR_HASH]; // NR_HASH = 307�
32 static struct buffer_head * free_list; // ���л��������ͷָ�롣
33 static struct task_struct * buffer_wait = NULL; // �ȴ����л�����˯�ߵ�������С�
// ���涨��ϵͳ�������к��еĻ������������NR_BUFFERS��һ��������linux/fs.hͷ
// �ļ���48�еĺ꣬��ֵ���DZ�����nr_buffers��������fs.h�ļ���172������Ϊȫ�ֱ�����
// ��д����ͨ������һ�������ƣ�Linus������д������Ϊ�����������д�����������ر�ʾ
// nr_buffers��һ�����ں˳�ʼ��֮���ٸı�ġ��������������ڳ�ʼ������buffer_init()
// �б����ã���371�У���
34 int NR_BUFFERS = 0; // ϵͳ���л���������
35
//// �ȴ�ָ������������
// ���ָ���Ļ����bh�Ѿ��������ý��̲����жϵ�˯���ڸû����ĵȴ�����b_wait�С�
// �ڻ�������ʱ����ȴ������ϵ����н��̽������ѡ���Ȼ���ڹر��жϣ�cli��֮��ȥ˯
// �ߵģ���������������Ӱ����������������������Ӧ�жϡ���Ϊÿ�����̶����Լ���TSS��
// �б����˱�־�Ĵ���EFLAGS��ֵ�������ڽ����л�ʱCPU�е�ǰEFLAGS��ֵҲ��֮�ı䡣
// ʹ��sleep_on()����˯��״̬�Ľ�����Ҫ��wake_up()��ȷ�ػ��ѡ�
36 static inline void wait_on_buffer(struct buffer_head * bh)
37 {
38 cli(); // ���жϡ�
39 while (bh->b_lock) // ����ѱ���������̽���˯�ߣ��ȴ��������
40 sleep_on(&bh->b_wait);
41 sti(); // ���жϡ�
42 }
43
//// �豸����ͬ����
// ͬ���豸���ڴ���ٻ��������ݡ����У�sync_inodes()������inode.c��59�С�
44 int sys_sync(void)
45 {
46 int i;
47 struct buffer_head * bh;
48
// ���ȵ���i�ڵ�ͬ�����������ڴ�i�ڵ���������Ĺ���i�ڵ�д����ٻ����С�Ȼ��
// ɨ�����и��ٻ����������ѱ��ĵĻ�������д����������������д�����У�����
// ���ٻ����е��������豸�е�ͬ����
49 sync_inodes(); /* write out inodes into buffers */
50 bh = start_buffer; // bhָ������ʼ����
51 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
52 wait_on_buffer(bh); // �ȴ�����������������������Ļ�����
53 if (bh->b_dirt)
54 ll_rw_block(WRITE,bh); // ����д�豸������
55 }
56 return 0;
57 }
58
//// ��ָ���豸���и��ٻ����������豸�����ݵ�ͬ��������
// �ú��������������ٻ����������л���顣����ָ���豸dev�Ļ���飬���������ѱ���
// ����д�����У�ͬ����������Ȼ����ڴ���i�ڵ������д����ٻ����С�֮���ٶ�ָ����
// ��devִ��һ����������ͬ��д�̲�����
59 int sync_dev(int dev)
60 {
61 int i;
62 struct buffer_head * bh;
63
// ���ȶԲ���ָ�����豸ִ������ͬ�����������豸�ϵ���������ٻ������е�����ͬ����
// ������ɨ����ٻ����������л���飬��ָ���豸dev�Ļ���飬�ȼ�����Ƿ��ѱ�������
// ���ѱ�������˯�ߵȴ��������Ȼ�����ж�һ�θû�����Ƿ���ָ���豸�Ļ���鲢��
// ���Ĺ���b_dirt��־��λ�������ǾͶ���ִ��д�̲�������Ϊ������˯���ڼ�û����
// �п����ѱ��ͷŻ��߱�Ų�����ã������ڼ���ִ��ǰ��Ҫ�ٴ��ж�һ�¸û�����Ƿ���
// ָ���豸�Ļ���飬
64 bh = start_buffer; // bhָ������ʼ����
65 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
66 if (bh->b_dev != dev) // �����豸dev�Ļ�����������
67 continue;
68 wait_on_buffer(bh); // �ȴ�����������������������Ļ�����
69 if (bh->b_dev == dev && bh->b_dirt)
70 ll_rw_block(WRITE,bh);
71 }
// �ٽ�i�ڵ�����д����ٻ��塣��i�ڵ��inode_table�е�inode�뻺���е���Ϣͬ����
72 sync_inodes();
// Ȼ���ڸ��ٻ����е����ݸ���֮���ٰ��������豸�е�����ͬ���������������ͬ������
// ��Ϊ������ں�ִ��Ч�ʡ���һ�黺����ͬ�������������ں������ࡰ��顱��ɾ���ʹ��
// i�ڵ��ͬ�������ܹ���Чִ�С����λ�����ͬ�����������Щ����i�ڵ�ͬ���������ֱ�
// ��Ļ�������豸������ͬ����
73 bh = start_buffer;
74 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
75 if (bh->b_dev != dev)
76 continue;
77 wait_on_buffer(bh);
78 if (bh->b_dev == dev && bh->b_dirt)
79 ll_rw_block(WRITE,bh);
80 }
81 return 0;
82 }
83
//// ʹָ���豸�ڸ��ٻ������е�������Ч��
// ɨ����ٻ����������л���顣��ָ���豸�Ļ���鸴λ����Ч(����)��־�����ı�־��
84 void inline invalidate_buffers(int dev)
85 {
86 int i;
87 struct buffer_head * bh;
88
89 bh = start_buffer;
90 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
91 if (bh->b_dev != dev) // �������ָ���豸�Ļ���飬��
92 continue; // ����ɨ����һ�顣
93 wait_on_buffer(bh); // �ȴ��û���������������ѱ���������
// ���ڽ���ִ�й�˯�ߵȴ���������Ҫ���ж�һ�»������Ƿ���ָ���豸�ġ�
94 if (bh->b_dev == dev)
95 bh->b_uptodate = bh->b_dirt = 0;
96 }
97 }
98
99 /*
100 * This routine checks whether a floppy has been changed, and
101 * invalidates all buffer-cache-entries in that case. This
102 * is a relatively slow routine, so we have to try to minimize using
103 * it. Thus it is called only upon a 'mount' or 'open'. This
104 * is the best way of combining speed and utility, I think.
105 * People changing diskettes in the middle of an operation deserve
106 * to loose :-)
107 *
108 * NOTE! Although currently this is only for floppies, the idea is
109 * that any additional removable block-device will use this routine,
110 * and that mount/open needn't know that floppies/whatever are
111 * special.
112 */
/*
* ���ӳ�����һ�������Ƿ��ѱ�����������Ѿ�������ʹ���ٻ������������
* ��Ӧ�����л�������Ч�����ӳ��������˵��������������Ҫ������ʹ������
* ���Խ���ִ��'mount'��'open'ʱ�ŵ��������������ǽ��ٶȺ�ʵ�������ϵ�
* ��÷��������ڲ��������и������̣��ͻᵼ�����ݵĶ�ʧ�����Ǿ�����ȡJ��
*
* ע�⣡����Ŀǰ���ӳ�����������̣��Ժ��κο��ƶ����ʵĿ��豸����ʹ�ø�
* ����mount/open��������Ҫ֪�������̻�������ʲô������ʡ�
*/
//// �������Ƿ����������Ѹ�����ʹ��Ӧ���ٻ�������Ч��
113 void check_disk_change(int dev)
114 {
115 int i;
116
// ���ȼ��һ���Dz��������豸����Ϊ���ڽ�֧�����̿��ƶ����ʡ�����������˳���Ȼ��
// ���������Ƿ��Ѹ��������û�����˳���floppy_change()��blk_drv/floppy.c��139�С�
117 if (MAJOR(dev) != 2)
118 return;
119 if (!floppy_change(dev & 0x03))
120 return;
// �����Ѿ������������ͷŶ�Ӧ�豸��i�ڵ�λͼ������λͼ��ռ�ĸ��ٻ���������ʹ��
// �豸��i�ڵ�����ݿ���Ϣ��ռ��ĸ��ٻ������Ч��
121 for (i=0 ; i<NR_SUPER ; i++)
122 if (super_block[i].s_dev == dev)
123 put_super(super_block[i].s_dev);
124 invalidate_inodes(dev);
125 invalidate_buffers(dev);
126 }
127
// �������д�����hash��ɢ�У����������hash����ļ���ꡣ
// hash������Ҫ�����Ǽ��ٲ��ұȽ�Ԫ�������ѵ�ʱ�䡣ͨ����Ԫ�صĴ洢λ����ؼ���֮��
// ����һ����Ӧ��ϵ��hash�����������ǾͿ���ֱ��ͨ�������������̲�ѯ��ָ����Ԫ�ء���
// ��hash������ָ��������Ҫ�Ǿ���ȷ��ɢ�е��κ�������ĸ��ʻ�����ȡ����������ķ���
// �ж��֣�����Linux 0.12��Ҫ�����˹ؼ��ֳ�������������Ϊ����Ѱ�ҵĻ����������������
// ���豸��dev�ͻ�����block�������Ƶ�hash�����϶���Ҫ�����������ؼ�ֵ����������
// �ؼ��ֵ�������ֻ�Ǽ���ؼ�ֵ��һ�ַ������ٶԹؼ�ֵ����MOD����Ϳ��Ա�֤��������
// ��õ���ֵ�����ں��������Χ�ڡ�
128 #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
129 #define hash(dev,block) hash_table[_hashfn(dev,block)]
130
//// ��hash���кͿ��л��������������顣
// hash������˫�������ṹ�����л���������˫��ѭ�������ṹ��
131 static inline void remove_from_queues(struct buffer_head * bh)
132 {
133 /* remove from hash-queue */
/* ��hash�������Ƴ������ */
134 if (bh->b_next)
135 bh->b_next->b_prev = bh->b_prev;
136 if (bh->b_prev)
137 bh->b_prev->b_next = bh->b_next;
// ����û������Ǹö��е�ͷһ���飬����hash���Ķ�Ӧ��ָ�����е���һ����������
138 if (hash(bh->b_dev,bh->b_blocknr) == bh)
139 hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
140 /* remove from free list */
/* �ӿ��л��������Ƴ������ */
141 if (!(bh->b_prev_free) || !(bh->b_next_free))
142 panic("Free block list corrupted");
143 bh->b_prev_free->b_next_free = bh->b_next_free;
144 bh->b_next_free->b_prev_free = bh->b_prev_free;
// �����������ͷָ��������������ָ����һ��������
145 if (free_list == bh)
146 free_list = bh->b_next_free;
147 }
148
//// �����������������β����ͬʱ����hash�����С�
149 static inline void insert_into_queues(struct buffer_head * bh)
150 {
151 /* put at end of free list */
/* ���ڿ�������ĩβ�� */
152 bh->b_next_free = free_list;
153 bh->b_prev_free = free_list->b_prev_free;
154 free_list->b_prev_free->b_next_free = bh;
155 free_list->b_prev_free = bh;
156 /* put the buffer in new hash-queue if it has a device */
/* ����û�����Ӧһ���豸�����������hash������ */
// ��ע�hash��ij���1�β�����ʱ��hash()����ֵ�϶�ΪNULL����˴�ʱ��161����
// �õ���bh->b_next�϶���NULL�����Ե�163����Ӧ����bh->b_next��ΪNULLʱ���ܸ�
// b_prev��bhֵ������163��ǰӦ�������жϡ�if (bh->b_next)�����ô���0.96���
// �ű�������
157 bh->b_prev = NULL;
158 bh->b_next = NULL;
159 if (!bh->b_dev)
160 return;
161 bh->b_next = hash(bh->b_dev,bh->b_blocknr);
162 hash(bh->b_dev,bh->b_blocknr) = bh;
163 bh->b_next->b_prev = bh; // �˾�ǰӦ���ӡ�if (bh->b_next)���жϡ�
164 }
165
//// ����hash���ڸ��ٻ�����Ѱ�Ҹ����豸��ָ����ŵĻ������顣
// ����ҵ��ػ��������ָ�룬����NULL��
166 static struct buffer_head * find_buffer(int dev, int block)
167 {
168 struct buffer_head * tmp;
169
// ����hash����Ѱ��ָ���豸�źͿ�ŵĻ���顣
170 for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
171 if (tmp->b_dev==dev && tmp->b_blocknr==block)
172 return tmp;
173 return NULL;
174 }
175
176 /*
177 * Why like this, I hear you say... The reason is race-conditions.
178 * As we don't lock buffers (unless we are readint them, that is),
179 * something might happen to it while we sleep (ie a read-error
180 * will force it bad). This shouldn't really happen currently, but
181 * the code is ready.
182 */
/*
* ����Ϊʲô���������ӵģ�����������... ԭ���Ǿ�����������������û�ж�
* ����������������������ڶ�ȡ�����е����ݣ�����ô�����ǣ����̣�˯��ʱ
* �������ܻᷢ��һЩ���⣨����һ���������¸û�����������Ŀǰ
* �������ʵ�����Dz��ᷢ���ģ��������Ĵ����Ѿ������ˡ�
*/
//// ����hash���ڸ��ٻ�������Ѱ��ָ���Ļ���顣���ҵ���Ըû�������������ؿ�ͷָ�롣
183 struct buffer_head * get_hash_table(int dev, int block)
184 {
185 struct buffer_head * bh;
186
187 for (;;) {
// �ڸ��ٻ�����Ѱ�Ҹ����豸��ָ����Ļ������飬���û���ҵ���NULL���˳���
188 if (!(bh=find_buffer(dev,block)))
189 return NULL;
// �Ըû�����������ü��������ȴ��û�������������ѱ������������ھ�����˯��״̬��
// ����б�Ҫ����֤�û�������ȷ�ԣ������ػ����ͷָ�롣
190 bh->b_count++;
191 wait_on_buffer(bh);
192 if (bh->b_dev == dev && bh->b_blocknr == block)
193 return bh;
// �����˯��ʱ�û�����������豸�Ż��ŷ����˸ı䣬�������������ü���������Ѱ�ҡ�
194 bh->b_count--;
195 }
196 }
197
198 /*
199 * Ok, this is getblk, and it isn't very clear, again to hinder
200 * race-conditions. Most of the code is seldom used, (ie repeating),
201 * so it should be much more efficient than it looks.
202 *
203 * The algoritm is changed: hopefully better, and an elusive bug removed.
204 */
/*
* OK��������getblk�������ú������������Ǻ�������ͬ��Ҳ����ΪҪ����
* �����������⡣���дִ�������õ���(�����ظ��������)�������Ӧ��
* �ȿ���ȥ��������Ч�öࡣ
*
* �㷨�Ѿ����˸ı䣺ϣ���ܸ��ã�����һ��������ĥ�Ĵ����Ѿ�ȥ����
*/
// ���������ͬʱ�жϻ��������ı�־��������־�����Ҷ����ı�־��Ȩ��Ҫ��������־
// ��
205 #define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
//// ȡ���ٻ�����ָ���Ļ���顣
// ���ָ�����豸�źͿ�ţ��Ļ������Ƿ��Ѿ��ڸ��ٻ����С����ָ�����Ѿ��ڸ��ٻ����У�
// �ض�Ӧ������ͷָ���˳���������ڣ�����Ҫ�ڸ��ٻ���������һ����Ӧ�豸�źͿ�ŵ�
// ���������Ӧ������ͷָ�롣
206 struct buffer_head * getblk(int dev,int block)
207 {
208 struct buffer_head * tmp, * bh;
209
210 repeat:
// ����hash�������ָ�����Ѿ��ڸ��ٻ����У��ض�Ӧ������ͷָ�룬�˳���
211 if (bh = get_hash_table(dev,block))
212 return bh;
// ɨ��������ݿ�������Ѱ�ҿ��л�������
// ������tmpָ����������ĵ�һ�����л�����ͷ��
213 tmp = free_list;
214 do {
// ����û���������ʹ�ã����ü���������0���������ɨ����һ�����b_count=0�Ŀ飬
// �����ٻ����е�ǰû�����õĿ鲻һ�����Ǹɾ��ģ�b_dirt=0����û�������ģ�b_lock=0����
// ��ˣ����ǻ�����Ҫ����������жϺ�ѡ�����統һ�������д��һ�����ݺ���ͷ��ˣ�
// ���Ǹÿ�b_count = 0����b_lock������0����һ������ִ�� breada()Ԥ��������ʱ��ֻҪ
// ll_rw_block()����������ͻ�ݼ�b_count������ʱʵ����Ӳ�̷��ʲ������ܻ��ڽ��У�
// ��˴�ʱb_lock=1����b_count=0��
215 if (tmp->b_count)
216 continue;
// �������ͷָ��bhΪ�գ�����tmp��ָ����ͷ�ı�־(�ġ�����)Ȩ��С��bhͷ��־��Ȩ
// �أ�����bhָ��tmp�����ͷ�� �����tmp�����ͷ����������û����Ҳû��������
// ־��λ����˵����Ϊָ���豸�ϵĿ�ȡ�ö�Ӧ�ĸ��ٻ���飬���˳�ѭ�����������Ǿͼ���
// ִ�б�ѭ���������ܷ��ҵ�һ��BADNESS()��С�Ļ���졣
217 if (!bh || BADNESS(tmp)<BADNESS(bh)) {
218 bh = tmp;
219 if (!BADNESS(tmp))
220 break;
221 }
222 /* and repeat until we find something good */ /* �ظ�����ֱ���ҵ��ʺϵĻ���� */
223 } while ((tmp = tmp->b_next_free) != free_list);
// ���ѭ����鷢�����л���鶼���ڱ�ʹ�ã����л�����ͷ�����ü�����>0���У���˯��
// �ȴ��п��л������á����п��л�������ʱ�����̻ᱻ��ȷ�ػ��ѡ�Ȼ�����Ǿ���ת��
// ������ʼ�����²��ҿ��л���顣
224 if (!bh) {
225 sleep_on(&buffer_wait);
226 goto repeat; // ��ת��210�С�
227 }
// ִ�е����˵�������Ѿ��ҵ���һ���Ƚ��ʺϵĿ��л�����ˡ������ȵȴ��û���������
//������ѱ������Ļ��������������˯�߽θû������ֱ���������ʹ�õĻ���ֻ���ظ�����
// Ѱ�ҹ��̡�
228 wait_on_buffer(bh);
229 if (bh->b_count) // �ֱ�ռ�ã���
230 goto repeat;
// ����û������ѱ��ģ�������д�̣����ٴεȴ�������������ͬ���أ����û������ֱ�
// ��������ʹ�õĻ���ֻ�����ظ�����Ѱ�ҹ��̡�
231 while (bh->b_dirt) {
232 sync_dev(bh->b_dev);
233 wait_on_buffer(bh);
234 if (bh->b_count) // �ֱ�ռ�ã���
235 goto repeat;
236 }
237 /* NOTE!! While we slept waiting for this block, somebody else might */
238 /* already have added "this" block to the cache. check it */
/* ע�⣡��������Ϊ�˵ȴ��û�����˯��ʱ���������̿����Ѿ����û���� */
* ��������ٻ����У���������ҲҪ�Դ˽��м�顣*/
// �ڸ��ٻ���hash���м��ָ���豸�Ϳ�Ļ�����Ƿ������˯��֮���Ѿ��������ȥ�����
// �ǵĻ������ٴ��ظ�����Ѱ�ҹ��̡�
239 if (find_buffer(dev,block))
240 goto repeat;
241 /* OK, FINALLY we know that this buffer is the only one of it's kind, */
242 /* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
/* OK����������֪���û������ָ��������Ψһһ�飬����Ŀǰ��û�б�ռ�� */
/* (b_count=0)��Ҳδ������(b_lock=0)�������Ǹɾ��ģ�δ���ĵģ�*/
// ����������ռ�ô˻���顣�����ü���Ϊ1����λ�ı�־����Ч(����)��־��
243 bh->b_count=1;
244 bh->b_dirt=0;
245 bh->b_uptodate=0;
// ��hash���кͿ��п��������Ƴ��û�����ͷ���øû���������ָ���豸�����ϵ�ָ���顣
// Ȼ����ݴ��µ��豸�źͿ�����²������������hash������λ�ô��������շ��ػ���
// ͷָ�롣
246 remove_from_queues(bh);
247 bh->b_dev=dev;
248 bh->b_blocknr=block;
249 insert_into_queues(bh);
250 return bh;
251 }
252
//// �ͷ�ָ������顣
// �ȴ��û���������Ȼ�����ü����ݼ�1������ȷ�ػ��ѵȴ����л����Ľ��̡�
253 void brelse(struct buffer_head * buf)
254 {
255 if (!buf) // �������ͷָ����Ч�ء�
256 return;
257 wait_on_buffer(buf);
258 if (!(buf->b_count--))
259 panic("Trying to free free buffer");
260 wake_up(&buffer_wait);
261 }
262
263 /*
264 * bread() reads a specified block and returns the buffer that contains
265 * it. It returns NULL if the block was unreadable.
266 */
/*
* ���豸�϶�ȡָ�������ݿ鲢���غ������ݵĻ����������ָ���Ŀ鲻����
* ��NULL��
*/
//// ���豸�϶�ȡ���ݿ顣
// �ú�������ָ�����豸��dev�����ݿ��block�������ڸ��ٻ�����������һ�黺��顣
// ����û�������Ѿ���������Ч�����ݾ�ֱ�ӷ��ظû����ָ�룬����ʹ��豸�ж�ȡ
// ָ�������ݿ鵽�û�����в����ػ����ָ�롣
267 struct buffer_head * bread(int dev,int block)
268 {
269 struct buffer_head * bh;
270
// �ڸ��ٻ�����������һ�黺��顣�������ֵ��NULL�����ʾ�ں˳�����ͣ����Ȼ������
// �ж������Ƿ����п������ݡ� ����û��������������Ч�ģ��Ѹ��µģ�����ֱ��ʹ�ã�
// �ء�
271 if (!(bh=getblk(dev,block)))
272 panic("bread: getblk returned NULL\n");
273 if (bh->b_uptodate)
274 return bh;
// �������Ǿ͵��õײ���豸��дll_rw_block()�������������豸������Ȼ��ȴ�ָ��
// ���ݿ鱻���룬���ȴ���������������˯������֮������û������Ѹ��£��ػ���
// ��ͷָ�룬�˳�������������豸����ʧ�ܣ������ͷŸû�����������NULL���˳���
275 ll_rw_block(READ,bh);
276 wait_on_buffer(bh);
277 if (bh->b_uptodate)
278 return bh;
279 brelse(bh);
280 return NULL;
281 }
282
//// �����ڴ�顣
// ��from��ַ����һ�飨1024�ֽڣ����ݵ�toλ�á�
283 #define COPYBLK(from,to) \
284 __asm__("cld\n\t" \
285 "rep\n\t" \
286 "movsl\n\t" \
287 ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
288 :"cx","di","si")
289
290 /*
291 * bread_page reads four buffers into memory at the desired address. It's
292 * a function of its own, as there is some speed to be got by reading them
293 * all at the same time, not waiting for one to be read, and then another
294 * etc.
295 */
/*
* bread_pageһ�ζ��ĸ���������ݶ����ڴ�ָ���ĵ�ַ��������һ�������ĺ�����
* ��Ϊͬʱ��ȡ�Ŀ���Ի���ٶ��ϵĺô������õ��Ŷ�һ�飬�ٶ�һ���ˡ�
*/
//// ���豸��һ��ҳ�棨4������飩�����ݵ�ָ���ڴ��ַ����
// ����address�DZ���ҳ�����ݵĵ�ַ��dev��ָ�����豸�ţ�b[4]�Ǻ���4���豸���ݿ��
// �����顣�ú���������mm/memory.c�ļ���do_no_page()�����У���386�У���
296 void bread_page(unsigned long address,int dev,int b[4])
297 {
298 struct buffer_head * bh[4];
299 int i;
300
// �ú���ѭ��ִ��4�Σ����ݷ�������b[]�е�4����Ŵ��豸dev�ж�ȡһҳ���ݷŵ�ָ��
// �ڴ�λ�� address���� ���ڲ���b[i]��������Ч��ţ��������ȴӸ��ٻ�����ȡָ���豸
// �Ϳ�ŵĻ���顣����������������Ч��δ���£���������豸������豸�϶�ȡ��Ӧ��
// �ݿ顣����b[i]��Ч�Ŀ������ȥ�����ˡ���˱�������ʵ���Ը���ָ����b[]�еĿ��
// �����ȡ1��4�����ݿ顣
301 for (i=0 ; i<4 ; i++)
302 if (b[i]) { // ���������
303 if (bh[i] = getblk(dev,b[i]))
304 if (!bh[i]->b_uptodate)
305 ll_rw_block(READ,bh[i]);
306 } else
307 bh[i] = NULL;
// ���4��������ϵ�����˳���Ƶ�ָ����ַ�����ڽ��и��ƣ�ʹ�ã������֮ǰ����
// ��Ҫ˯�ߵȴ��������������������Ļ��������⣬��Ϊ����˯�߹��ˣ��������ǻ���Ҫ
// �ڸ���֮ǰ�ټ��һ�»�����е������Ƿ�����Ч�ġ�����������ǻ���Ҫ�ͷŻ���顣
308 for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
309 if (bh[i]) {
310 wait_on_buffer(bh[i]); // �ȴ���������(���������Ļ�)��
311 if (bh[i]->b_uptodate) // ���������������Ч�Ļ����ơ�
312 COPYBLK((unsigned long) bh[i]->b_data,address);
313 brelse(bh[i]); // �ͷŸû�������
314 }
315 }
316
317 /*
318 * Ok, breada can be used as bread, but additionally to mark other
319 * blocks for reading as well. End the argument list with a negative
320 * number.
321 */
/*
* OK��breada������breadһ��ʹ�ã���������Ԥ��һЩ�顣�ú��������б�
* ��Ҫʹ��һ�����������������б��Ľ�����
*/
//// ��ָ���豸��ȡָ����һЩ�顣
// �������������ɱ䣬��һϵ��ָ���Ŀ�š��ɹ�ʱ���ص�1��Ļ����ͷָ�룬����
// NULL��
322 struct buffer_head * breada(int dev,int first, ...)
323 {
324 va_list args;
325 struct buffer_head * bh, *tmp;
326
// ����ȡ�ɱ�������е�1����������ţ������ŴӸ��ٻ�������ȡָ���豸�Ϳ�ŵĻ���
// �顣����û����������Ч�����±�־δ��λ���������豸���ݿ�����
327 va_start(args,first);
328 if (!(bh=getblk(dev,first)))
329 panic("bread: getblk returned NULL\n");
330 if (!bh->b_uptodate)
331 ll_rw_block(READ,bh);
// Ȼ��˳��ȡ�ɱ������������Ԥ����ţ�����������ͬ���������������á�ע�⣬336����
// ��һ��bug�����е�bhӦ����tmp�����bugֱ����0.96����ں˴����вű�����������
// ���⣬��Ϊ������Ԥ���������ݿ飬ֻ��������ٻ��������������Ͼ�ʹ�ã����Ե�337
// �������Ҫ�������ü����ݼ��ͷŵ��ÿ飨��Ϊgetblk()���������ӻ�������ü���ֵ����
332 while ((first=va_arg(args,int))>=0) {
333 tmp=getblk(dev,first);
334 if (tmp) {
335 if (!tmp->b_uptodate)
336 ll_rw_block(READA,bh); // bh Ӧ����tmp��
337 tmp->b_count--; // ��ʱ�ͷŵ���Ԥ���顣
338 }
339 }
// ��ʱ�ɱ�����������в���������ϡ����ǵȴ���1������������������ѱ����������ڵ�
// ���˳�֮�������������������Ȼ��Ч���ػ�����ͷָ���˳��������ͷŸû���������
// NULL���˳���
340 va_end(args);
341 wait_on_buffer(bh);
342 if (bh->b_uptodate)
343 return bh;
344 brelse(bh);
345 return (NULL);
346 }
347
//// ��������ʼ��������
// ����buffer_end�ǻ������ڴ�ĩ�ˡ����ھ���16MB�ڴ��ϵͳ��������ĩ�˱�����Ϊ4MB��
// ������8MB�ڴ��ϵͳ��������ĩ�˱�����Ϊ2MB���ú����ӻ�������ʼλ��start_buffer
// ���ͻ�����ĩ��buffer_end���ֱ�ͬʱ���ã���ʼ���������ͷ�ṹ�Ͷ�Ӧ�����ݿ顣ֱ��
// �������������ڴ汻������ϡ��μ������б�ǰ���ʾ��ͼ��
348 void buffer_init(long buffer_end)
349 {
350 struct buffer_head * h = start_buffer;
351 void * b;
352 int i;
353
// ���ȸ��ݲ����ṩ�Ļ������߶�λ��ȷ��ʵ�ʻ������߶�λ��b������������߶˵���1Mb��
// ����Ϊ��640KB - 1MB����ʾ�ڴ�� BIOSռ�ã�����ʵ�ʿ��û������ڴ�߶�λ��Ӧ����
// 640KB���������ڴ�߶�һ������1MB��
354 if (buffer_end == 1<<20)
355 b = (void *) (640*1024);
356 else
357 b = (void *) buffer_end;
// ��δ������ڳ�ʼ�����������������л����ѭ������������ȡϵͳ�л������Ŀ��������
// �����Ǵӻ������߶˿�ʼ����1KB��С�Ļ���飬���ͬʱ�ڻ������Ͷ˽��������û����
// �Ľṹbuffer_head��������Щbuffer_head���˫��������
// h��ָ��ͷ�ṹ��ָ�룬��h+1��ָ���ڴ��ַ��������һ������ͷ��ַ��Ҳ����˵��
// ָ��h����ͷ��ĩ���⡣Ϊ�˱�֤���㹻���ȵ��ڴ����洢һ������ͷ�ṹ����Ҫb��ָ��
// ���ڴ���ַ >= h����ͷ��ĩ�ˣ���Ҫ�� >= h+1��
358 while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
359 h->b_dev = 0; // ʹ�øû������豸�š�
360 h->b_dirt = 0; // ���־����������ı�־��
361 h->b_count = 0; // ��������ü�����
362 h->b_lock = 0; // �����������־��
363 h->b_uptodate = 0; // �������±�־�����������Ч��־����
364 h->b_wait = NULL; // ָ��ȴ��û��������Ľ��̡�
365 h->b_next = NULL; // ָ�������ͬhashֵ����һ������ͷ��
366 h->b_prev = NULL; // ָ�������ͬhashֵ��ǰһ������ͷ��
367 h->b_data = (char *) b; // ָ���Ӧ��������ݿ飨1024�ֽڣ���
368 h->b_prev_free = h-1; // ָ��������ǰһ�
369 h->b_next_free = h+1; // ָ����������һ�
370 h++; // hָ����һ�»���ͷλ�á�
371 NR_BUFFERS++; // �����������ۼӡ�
372 if (b == (void *) 0x100000) // ��b�ݼ�������1MB��������384KB��
373 b = (void *) 0xA0000; // ��bָ���ַ0xA0000(640KB)����
374 }
375 h--; // ��hָ�����һ����Ч�����ͷ��
376 free_list = start_buffer; // �ÿ�������ͷָ��ͷһ������顣
377 free_list->b_prev_free = h; // ����ͷ��b_prev_freeָ��ǰһ������һ���
378 h->b_next_free = free_list; // h����һ��ָ��ָ���һ��γ�һ��������
// ����ʼ��hash������ϣ����ɢ�б������ñ�������ָ��ΪNULL��
379 for (i=0;i<NR_HASH;i++)
380 hash_table[i]=NULL;
381 }
382