This source file includes following definitions.
- wait_on_buffer
- sync_buffers
- sys_sync
- sync_dev
- invalidate_buffers
- check_disk_change
- remove_from_hash_queue
- remove_from_free_list
- remove_from_queues
- put_first_free
- put_last_free
- insert_into_queues
- find_buffer
- get_hash_table
- getblk
- brelse
- bread
- bread_page
- breada
- buffer_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <stdarg.h>
22
23 #include <linux/config.h>
24 #include <linux/sched.h>
25 #include <linux/kernel.h>
26 #include <asm/system.h>
27 #include <asm/io.h>
28
29 extern int end;
30 struct buffer_head * start_buffer = (struct buffer_head *) &end;
31 struct buffer_head * hash_table[NR_HASH];
32 static struct buffer_head * free_list;
33 static struct task_struct * buffer_wait = NULL;
34 int NR_BUFFERS = 0;
35
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
44 static void sync_buffers(int dev)
45 {
46 int i;
47 struct buffer_head * bh;
48
49 bh = free_list;
50 for (i=0 ; i<NR_BUFFERS ; i++,bh = bh->b_next_free) {
51 #if 0
52 if (dev && (bh->b_dev != dev))
53 continue;
54 #endif
55 wait_on_buffer(bh);
56 #if 0
57 if (dev && (bh->b_dev != dev))
58 continue;
59 #endif
60 if (bh->b_dirt)
61 ll_rw_block(WRITE,bh);
62 }
63 }
64
65 int sys_sync(void)
66 {
67 sync_inodes();
68 sync_buffers(0);
69 return 0;
70 }
71
72 int sync_dev(int dev)
73 {
74 sync_buffers(dev);
75 sync_inodes();
76 sync_buffers(dev);
77 return 0;
78 }
79
80 void inline invalidate_buffers(int dev)
81 {
82 int i;
83 struct buffer_head * bh;
84
85 bh = start_buffer;
86 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
87 if (bh->b_dev != dev)
88 continue;
89 wait_on_buffer(bh);
90 if (bh->b_dev == dev)
91 bh->b_uptodate = bh->b_dirt = 0;
92 }
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 void check_disk_change(int dev)
110 {
111 int i;
112
113 if (MAJOR(dev) != 2)
114 return;
115 if (!floppy_change(dev & 0x03))
116 return;
117 for (i=0 ; i<NR_SUPER ; i++)
118 if (super_block[i].s_dev == dev)
119 put_super(super_block[i].s_dev);
120 invalidate_inodes(dev);
121 invalidate_buffers(dev);
122 }
123
124 #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
125 #define hash(dev,block) hash_table[_hashfn(dev,block)]
126
127 static inline void remove_from_hash_queue(struct buffer_head * bh)
128 {
129 if (bh->b_next)
130 bh->b_next->b_prev = bh->b_prev;
131 if (bh->b_prev)
132 bh->b_prev->b_next = bh->b_next;
133 if (hash(bh->b_dev,bh->b_blocknr) == bh)
134 hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
135 bh->b_next = bh->b_prev = NULL;
136 }
137
138 static inline void remove_from_free_list(struct buffer_head * bh)
139 {
140 if (!(bh->b_prev_free) || !(bh->b_next_free))
141 panic("Free block list corrupted");
142 bh->b_prev_free->b_next_free = bh->b_next_free;
143 bh->b_next_free->b_prev_free = bh->b_prev_free;
144 if (free_list == bh)
145 free_list = bh->b_next_free;
146 bh->b_next_free = bh->b_prev_free = NULL;
147 }
148
149 static inline void remove_from_queues(struct buffer_head * bh)
150 {
151 remove_from_hash_queue(bh);
152 remove_from_free_list(bh);
153 }
154
155 static inline void put_first_free(struct buffer_head * bh)
156 {
157 if (!bh || (bh == free_list))
158 return;
159 remove_from_free_list(bh);
160
161 bh->b_next_free = free_list;
162 bh->b_prev_free = free_list->b_prev_free;
163 free_list->b_prev_free->b_next_free = bh;
164 free_list->b_prev_free = bh;
165 free_list = bh;
166 }
167
168 static inline void put_last_free(struct buffer_head * bh)
169 {
170 if (!bh)
171 return;
172 if (bh == free_list) {
173 free_list = bh->b_next_free;
174 return;
175 }
176 remove_from_free_list(bh);
177
178 bh->b_next_free = free_list;
179 bh->b_prev_free = free_list->b_prev_free;
180 free_list->b_prev_free->b_next_free = bh;
181 free_list->b_prev_free = bh;
182 }
183
184 static inline void insert_into_queues(struct buffer_head * bh)
185 {
186
187 bh->b_next_free = free_list;
188 bh->b_prev_free = free_list->b_prev_free;
189 free_list->b_prev_free->b_next_free = bh;
190 free_list->b_prev_free = bh;
191
192 bh->b_prev = NULL;
193 bh->b_next = NULL;
194 if (!bh->b_dev)
195 return;
196 bh->b_next = hash(bh->b_dev,bh->b_blocknr);
197 hash(bh->b_dev,bh->b_blocknr) = bh;
198 bh->b_next->b_prev = bh;
199 }
200
201 static struct buffer_head * find_buffer(int dev, int block)
202 {
203 struct buffer_head * tmp;
204
205 for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
206 if (tmp->b_dev==dev && tmp->b_blocknr==block)
207 return tmp;
208 return NULL;
209 }
210
211
212
213
214
215
216
217
218 struct buffer_head * get_hash_table(int dev, int block)
219 {
220 struct buffer_head * bh;
221
222 for (;;) {
223 if (!(bh=find_buffer(dev,block)))
224 return NULL;
225 bh->b_count++;
226 wait_on_buffer(bh);
227 if (bh->b_dev == dev && bh->b_blocknr == block) {
228 put_last_free(bh);
229 return bh;
230 }
231 bh->b_count--;
232 }
233 }
234
235
236
237
238
239
240
241
242
243
244
245 #define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
246 struct buffer_head * getblk(int dev,int block)
247 {
248 struct buffer_head * bh, * tmp;
249 int buffers;
250
251 repeat:
252 if (bh = get_hash_table(dev,block))
253 return bh;
254 buffers = NR_BUFFERS;
255 tmp = free_list;
256 do {
257 tmp = tmp->b_next_free;
258 if (tmp->b_count)
259 continue;
260 if (!bh || BADNESS(tmp)<BADNESS(bh)) {
261 bh = tmp;
262 if (!BADNESS(tmp))
263 break;
264 }
265 if (tmp->b_dirt)
266 ll_rw_block(WRITEA,tmp);
267
268 } while (buffers--);
269 if (!bh) {
270 sleep_on(&buffer_wait);
271 goto repeat;
272 }
273 wait_on_buffer(bh);
274 if (bh->b_count)
275 goto repeat;
276 while (bh->b_dirt) {
277 sync_dev(bh->b_dev);
278 wait_on_buffer(bh);
279 if (bh->b_count)
280 goto repeat;
281 }
282
283
284 if (find_buffer(dev,block))
285 goto repeat;
286
287
288 bh->b_count=1;
289 bh->b_dirt=0;
290 bh->b_uptodate=0;
291 remove_from_queues(bh);
292 bh->b_dev=dev;
293 bh->b_blocknr=block;
294 insert_into_queues(bh);
295 return bh;
296 }
297
298 void brelse(struct buffer_head * buf)
299 {
300 if (!buf)
301 return;
302 wait_on_buffer(buf);
303 if (!(buf->b_count--))
304 panic("Trying to free free buffer");
305 wake_up(&buffer_wait);
306 }
307
308
309
310
311
312 struct buffer_head * bread(int dev,int block)
313 {
314 struct buffer_head * bh;
315
316 if (!(bh=getblk(dev,block)))
317 panic("bread: getblk returned NULL\n");
318 if (bh->b_uptodate)
319 return bh;
320 ll_rw_block(READ,bh);
321 wait_on_buffer(bh);
322 if (bh->b_uptodate)
323 return bh;
324 brelse(bh);
325 return NULL;
326 }
327
328 #define COPYBLK(from,to) \
329 __asm__("cld\n\t" \
330 "rep\n\t" \
331 "movsl\n\t" \
332 ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
333 :"cx","di","si")
334
335
336
337
338
339
340
341 void bread_page(unsigned long address,int dev,int b[4])
342 {
343 struct buffer_head * bh[4];
344 int i;
345
346 for (i=0 ; i<4 ; i++)
347 if (b[i]) {
348 if (bh[i] = getblk(dev,b[i]))
349 if (!bh[i]->b_uptodate)
350 ll_rw_block(READ,bh[i]);
351 } else
352 bh[i] = NULL;
353 for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
354 if (bh[i]) {
355 wait_on_buffer(bh[i]);
356 if (bh[i]->b_uptodate)
357 COPYBLK((unsigned long) bh[i]->b_data,address);
358 brelse(bh[i]);
359 }
360 }
361
362
363
364
365
366
367 struct buffer_head * breada(int dev,int first, ...)
368 {
369 va_list args;
370 struct buffer_head * bh, *tmp;
371
372 va_start(args,first);
373 if (!(bh=getblk(dev,first)))
374 panic("bread: getblk returned NULL\n");
375 if (!bh->b_uptodate)
376 ll_rw_block(READ,bh);
377 while ((first=va_arg(args,int))>=0) {
378 tmp=getblk(dev,first);
379 if (tmp) {
380 if (!tmp->b_uptodate)
381 ll_rw_block(READA,bh);
382 tmp->b_count--;
383 }
384 }
385 va_end(args);
386 wait_on_buffer(bh);
387 if (bh->b_uptodate)
388 return bh;
389 brelse(bh);
390 return (NULL);
391 }
392
393 void buffer_init(long buffer_end)
394 {
395 struct buffer_head * h = start_buffer;
396 void * b;
397 int i;
398
399 if (buffer_end == 1<<20)
400 b = (void *) (640*1024);
401 else
402 b = (void *) buffer_end;
403 while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
404 h->b_dev = 0;
405 h->b_dirt = 0;
406 h->b_count = 0;
407 h->b_lock = 0;
408 h->b_uptodate = 0;
409 h->b_wait = NULL;
410 h->b_next = NULL;
411 h->b_prev = NULL;
412 h->b_data = (char *) b;
413 h->b_prev_free = h-1;
414 h->b_next_free = h+1;
415 h++;
416 NR_BUFFERS++;
417 if (b == (void *) 0x100000)
418 b = (void *) 0xA0000;
419 }
420 h--;
421 free_list = start_buffer;
422 free_list->b_prev_free = h;
423 h->b_next_free = free_list;
424 for (i=0;i<NR_HASH;i++)
425 hash_table[i] = NULL;
426 }