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 static struct buffer_head * start_buffer = (struct buffer_head *) &end;
31 static 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 struct buffer_head * bh;
113
114 if (MAJOR(dev) != 2)
115 return;
116 if (!(bh = getblk(dev,0)))
117 return;
118 i = floppy_change(bh);
119 brelse(bh);
120 if (!i)
121 return;
122 for (i=0 ; i<NR_SUPER ; i++)
123 if (super_block[i].s_dev == dev)
124 put_super(super_block[i].s_dev);
125 invalidate_inodes(dev);
126 invalidate_buffers(dev);
127 }
128
129 #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
130 #define hash(dev,block) hash_table[_hashfn(dev,block)]
131
132 static inline void remove_from_hash_queue(struct buffer_head * bh)
133 {
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;
138 if (hash(bh->b_dev,bh->b_blocknr) == bh)
139 hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
140 bh->b_next = bh->b_prev = NULL;
141 }
142
143 static inline void remove_from_free_list(struct buffer_head * bh)
144 {
145 if (!(bh->b_prev_free) || !(bh->b_next_free))
146 panic("Free block list corrupted");
147 bh->b_prev_free->b_next_free = bh->b_next_free;
148 bh->b_next_free->b_prev_free = bh->b_prev_free;
149 if (free_list == bh)
150 free_list = bh->b_next_free;
151 bh->b_next_free = bh->b_prev_free = NULL;
152 }
153
154 static inline void remove_from_queues(struct buffer_head * bh)
155 {
156 remove_from_hash_queue(bh);
157 remove_from_free_list(bh);
158 }
159
160 static inline void put_first_free(struct buffer_head * bh)
161 {
162 if (!bh || (bh == free_list))
163 return;
164 remove_from_free_list(bh);
165
166 bh->b_next_free = free_list;
167 bh->b_prev_free = free_list->b_prev_free;
168 free_list->b_prev_free->b_next_free = bh;
169 free_list->b_prev_free = bh;
170 free_list = bh;
171 }
172
173 static inline void put_last_free(struct buffer_head * bh)
174 {
175 if (!bh)
176 return;
177 if (bh == free_list) {
178 free_list = bh->b_next_free;
179 return;
180 }
181 remove_from_free_list(bh);
182
183 bh->b_next_free = free_list;
184 bh->b_prev_free = free_list->b_prev_free;
185 free_list->b_prev_free->b_next_free = bh;
186 free_list->b_prev_free = bh;
187 }
188
189 static inline void insert_into_queues(struct buffer_head * bh)
190 {
191
192 bh->b_next_free = free_list;
193 bh->b_prev_free = free_list->b_prev_free;
194 free_list->b_prev_free->b_next_free = bh;
195 free_list->b_prev_free = bh;
196
197 bh->b_prev = NULL;
198 bh->b_next = NULL;
199 if (!bh->b_dev)
200 return;
201 bh->b_next = hash(bh->b_dev,bh->b_blocknr);
202 hash(bh->b_dev,bh->b_blocknr) = bh;
203 bh->b_next->b_prev = bh;
204 }
205
206 static struct buffer_head * find_buffer(int dev, int block)
207 {
208 struct buffer_head * tmp;
209
210 for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
211 if (tmp->b_dev==dev && tmp->b_blocknr==block)
212 return tmp;
213 return NULL;
214 }
215
216
217
218
219
220
221
222
223 struct buffer_head * get_hash_table(int dev, int block)
224 {
225 struct buffer_head * bh;
226
227 for (;;) {
228 if (!(bh=find_buffer(dev,block)))
229 return NULL;
230 bh->b_count++;
231 wait_on_buffer(bh);
232 if (bh->b_dev == dev && bh->b_blocknr == block) {
233 put_last_free(bh);
234 return bh;
235 }
236 bh->b_count--;
237 }
238 }
239
240
241
242
243
244
245
246
247
248
249
250 #define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
251 struct buffer_head * getblk(int dev,int block)
252 {
253 struct buffer_head * bh, * tmp;
254 int buffers;
255
256 repeat:
257 if (bh = get_hash_table(dev,block))
258 return bh;
259 buffers = NR_BUFFERS;
260 tmp = free_list;
261 do {
262 tmp = tmp->b_next_free;
263 if (tmp->b_count)
264 continue;
265 if (!bh || BADNESS(tmp)<BADNESS(bh)) {
266 bh = tmp;
267 if (!BADNESS(tmp))
268 break;
269 }
270 if (tmp->b_dirt)
271 ll_rw_block(WRITEA,tmp);
272
273 } while (buffers--);
274 if (!bh) {
275 sleep_on(&buffer_wait);
276 goto repeat;
277 }
278 wait_on_buffer(bh);
279 if (bh->b_count)
280 goto repeat;
281 while (bh->b_dirt) {
282 sync_dev(bh->b_dev);
283 wait_on_buffer(bh);
284 if (bh->b_count)
285 goto repeat;
286 }
287
288
289 if (find_buffer(dev,block))
290 goto repeat;
291
292
293 bh->b_count=1;
294 bh->b_dirt=0;
295 bh->b_uptodate=0;
296 remove_from_queues(bh);
297 bh->b_dev=dev;
298 bh->b_blocknr=block;
299 insert_into_queues(bh);
300 return bh;
301 }
302
303 void brelse(struct buffer_head * buf)
304 {
305 if (!buf)
306 return;
307 wait_on_buffer(buf);
308 if (!(buf->b_count--))
309 panic("Trying to free free buffer");
310 wake_up(&buffer_wait);
311 }
312
313
314
315
316
317 struct buffer_head * bread(int dev,int block)
318 {
319 struct buffer_head * bh;
320
321 if (!(bh=getblk(dev,block)))
322 panic("bread: getblk returned NULL\n");
323 if (bh->b_uptodate)
324 return bh;
325 ll_rw_block(READ,bh);
326 wait_on_buffer(bh);
327 if (bh->b_uptodate)
328 return bh;
329 brelse(bh);
330 return NULL;
331 }
332
333 #define COPYBLK(from,to) \
334 __asm__("cld\n\t" \
335 "rep\n\t" \
336 "movsl\n\t" \
337 ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
338 :"cx","di","si")
339
340
341
342
343
344
345
346 void bread_page(unsigned long address,int dev,int b[4])
347 {
348 struct buffer_head * bh[4];
349 int i;
350
351 for (i=0 ; i<4 ; i++)
352 if (b[i]) {
353 if (bh[i] = getblk(dev,b[i]))
354 if (!bh[i]->b_uptodate)
355 ll_rw_block(READ,bh[i]);
356 } else
357 bh[i] = NULL;
358 for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
359 if (bh[i]) {
360 wait_on_buffer(bh[i]);
361 if (bh[i]->b_uptodate)
362 COPYBLK((unsigned long) bh[i]->b_data,address);
363 brelse(bh[i]);
364 }
365 }
366
367
368
369
370
371
372 struct buffer_head * breada(int dev,int first, ...)
373 {
374 va_list args;
375 struct buffer_head * bh, *tmp;
376
377 va_start(args,first);
378 if (!(bh=getblk(dev,first)))
379 panic("bread: getblk returned NULL\n");
380 if (!bh->b_uptodate)
381 ll_rw_block(READ,bh);
382 while ((first=va_arg(args,int))>=0) {
383 tmp=getblk(dev,first);
384 if (tmp) {
385 if (!tmp->b_uptodate)
386 ll_rw_block(READA,bh);
387 tmp->b_count--;
388 }
389 }
390 va_end(args);
391 wait_on_buffer(bh);
392 if (bh->b_uptodate)
393 return bh;
394 brelse(bh);
395 return (NULL);
396 }
397
398 void buffer_init(long buffer_end)
399 {
400 struct buffer_head * h = start_buffer;
401 void * b;
402 int i;
403
404 if (buffer_end == 1<<20)
405 b = (void *) (640*1024);
406 else
407 b = (void *) buffer_end;
408 while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
409 if (((unsigned long) (h+1)) > 0xA0000) {
410 printk("buffer-list doesn't fit in low meg - contact Linus\n");
411 break;
412 }
413 h->b_dev = 0;
414 h->b_dirt = 0;
415 h->b_count = 0;
416 h->b_lock = 0;
417 h->b_uptodate = 0;
418 h->b_wait = NULL;
419 h->b_next = NULL;
420 h->b_prev = NULL;
421 h->b_data = (char *) b;
422 h->b_prev_free = h-1;
423 h->b_next_free = h+1;
424 h++;
425 NR_BUFFERS++;
426 if (b == (void *) 0x100000)
427 b = (void *) 0xA0000;
428 }
429 h--;
430 free_list = start_buffer;
431 free_list->b_prev_free = h;
432 h->b_next_free = free_list;
433 for (i=0;i<NR_HASH;i++)
434 hash_table[i] = NULL;
435 }