This source file includes following definitions.
- wait_on_buffer
- sys_sync
- sync_dev
- invalidate_buffers
- check_disk_change
- remove_from_queues
- 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 int sys_sync(void)
45 {
46 int i;
47 struct buffer_head * bh;
48
49 sync_inodes();
50 bh = start_buffer;
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
59 int sync_dev(int dev)
60 {
61 int i;
62 struct buffer_head * bh;
63
64 bh = start_buffer;
65 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
66 if (bh->b_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 }
72 sync_inodes();
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
101
102
103
104
105
106
107
108
109
110
111
112
113 void check_disk_change(int dev)
114 {
115 int i;
116
117 if (MAJOR(dev) != 2)
118 return;
119 if (!floppy_change(dev & 0x03))
120 return;
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
128 #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
129 #define hash(dev,block) hash_table[_hashfn(dev,block)]
130
131 static inline void remove_from_queues(struct buffer_head * bh)
132 {
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
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
149 static inline void insert_into_queues(struct buffer_head * bh)
150 {
151
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
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;
164 }
165
166 static struct buffer_head * find_buffer(int dev, int block)
167 {
168 struct buffer_head * tmp;
169
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
178
179
180
181
182
183 struct buffer_head * get_hash_table(int dev, int block)
184 {
185 struct buffer_head * bh;
186
187 for (;;) {
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
200
201
202
203
204
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:
211 if (bh = get_hash_table(dev,block))
212 return bh;
213 tmp = free_list;
214 do {
215 if (tmp->b_count)
216 continue;
217 if (!bh || BADNESS(tmp)<BADNESS(bh)) {
218 bh = tmp;
219 if (!BADNESS(tmp))
220 break;
221 }
222
223 } while ((tmp = tmp->b_next_free) != free_list);
224 if (!bh) {
225 sleep_on(&buffer_wait);
226 goto repeat;
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
238
239 if (find_buffer(dev,block))
240 goto repeat;
241
242
243 bh->b_count=1;
244 bh->b_dirt=0;
245 bh->b_uptodate=0;
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
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
265
266
267 struct buffer_head * bread(int dev,int block)
268 {
269 struct buffer_head * bh;
270
271 if (!(bh=getblk(dev,block)))
272 panic("bread: getblk returned NULL\n");
273 if (bh->b_uptodate)
274 return bh;
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
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
292
293
294
295
296 void bread_page(unsigned long address,int dev,int b[4])
297 {
298 struct buffer_head * bh[4];
299 int i;
300
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;
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
319
320
321
322 struct buffer_head * breada(int dev,int first, ...)
323 {
324 va_list args;
325 struct buffer_head * bh, *tmp;
326
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);
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);
337 tmp->b_count--;
338 }
339 }
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
348 void buffer_init(long buffer_end)
349 {
350 struct buffer_head * h = start_buffer;
351 void * b;
352 int i;
353
354 if (buffer_end == 1<<20)
355 b = (void *) (640*1024);
356 else
357 b = (void *) buffer_end;
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;
366 h->b_prev = NULL;
367 h->b_data = (char *) b;
368 h->b_prev_free = h-1;
369 h->b_next_free = h+1;
370 h++;
371 NR_BUFFERS++;
372 if (b == (void *) 0x100000)
373 b = (void *) 0xA0000;
374 }
375 h--;
376 free_list = start_buffer;
377 free_list->b_prev_free = h;
378 h->b_next_free = free_list;
379 for (i=0;i<NR_HASH;i++)
380 hash_table[i]=NULL;
381 }