|
|
1.1 root 1: /*
1.1.1.2 root 2: * linux/fs/buffer.c
3: *
4: * (C) 1991 Linus Torvalds
5: */
6:
7: /*
1.1 root 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: */
14:
1.1.1.2 root 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>
22:
1.1 root 23: #include <linux/config.h>
24: #include <linux/sched.h>
25: #include <linux/kernel.h>
26: #include <asm/system.h>
1.1.1.2 root 27: #include <asm/io.h>
1.1 root 28:
29: extern int end;
1.1.1.6 root 30: static struct buffer_head * start_buffer = (struct buffer_head *) &end;
31: static struct buffer_head * hash_table[NR_HASH];
1.1 root 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:
1.1.1.4 root 44: static void sync_buffers(int dev)
1.1 root 45: {
46: int i;
47: struct buffer_head * bh;
48:
1.1.1.4 root 49: bh = free_list;
1.1.1.7 root 50: for (i = NR_BUFFERS*2 ; i-- > 0 ; bh = bh->b_next_free) {
51: if (bh->b_lock)
1.1.1.4 root 52: continue;
1.1.1.7 root 53: if (!bh->b_dirt)
1.1.1.4 root 54: continue;
1.1.1.7 root 55: ll_rw_block(WRITE,bh);
1.1 root 56: }
1.1.1.4 root 57: }
58:
59: int sys_sync(void)
60: {
1.1.1.9 ! root 61: int i;
! 62:
! 63: for (i=0 ; i<NR_SUPER ; i++)
! 64: if (super_block[i].s_dev
! 65: && super_block[i].s_op
! 66: && super_block[i].s_op->write_super
! 67: && super_block[i].s_dirt)
! 68: super_block[i].s_op->write_super(&super_block[i]);
1.1.1.4 root 69: sync_inodes(); /* write out inodes into buffers */
70: sync_buffers(0);
1.1 root 71: return 0;
72: }
73:
1.1.1.2 root 74: int sync_dev(int dev)
1.1 root 75: {
1.1.1.9 ! root 76: struct super_block * sb;
! 77:
! 78: if (sb = get_super (dev))
! 79: if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
! 80: sb->s_op->write_super (sb);
1.1.1.4 root 81: sync_buffers(dev);
1.1.1.2 root 82: sync_inodes();
1.1.1.4 root 83: sync_buffers(dev);
1.1 root 84: return 0;
85: }
86:
1.1.1.3 root 87: void inline invalidate_buffers(int dev)
88: {
89: int i;
90: struct buffer_head * bh;
91:
92: bh = start_buffer;
93: for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
94: if (bh->b_dev != dev)
95: continue;
96: wait_on_buffer(bh);
97: if (bh->b_dev == dev)
98: bh->b_uptodate = bh->b_dirt = 0;
99: }
100: }
101:
1.1.1.2 root 102: /*
103: * This routine checks whether a floppy has been changed, and
104: * invalidates all buffer-cache-entries in that case. This
105: * is a relatively slow routine, so we have to try to minimize using
106: * it. Thus it is called only upon a 'mount' or 'open'. This
107: * is the best way of combining speed and utility, I think.
108: * People changing diskettes in the middle of an operation deserve
109: * to loose :-)
110: *
111: * NOTE! Although currently this is only for floppies, the idea is
112: * that any additional removable block-device will use this routine,
113: * and that mount/open needn't know that floppies/whatever are
114: * special.
115: */
116: void check_disk_change(int dev)
117: {
118: int i;
1.1.1.5 root 119: struct buffer_head * bh;
1.1.1.2 root 120:
121: if (MAJOR(dev) != 2)
122: return;
1.1.1.5 root 123: if (!(bh = getblk(dev,0)))
124: return;
125: i = floppy_change(bh);
126: brelse(bh);
127: if (!i)
1.1.1.2 root 128: return;
129: for (i=0 ; i<NR_SUPER ; i++)
1.1.1.3 root 130: if (super_block[i].s_dev == dev)
1.1.1.2 root 131: put_super(super_block[i].s_dev);
1.1.1.3 root 132: invalidate_inodes(dev);
133: invalidate_buffers(dev);
1.1.1.2 root 134: }
135:
1.1 root 136: #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
137: #define hash(dev,block) hash_table[_hashfn(dev,block)]
138:
1.1.1.4 root 139: static inline void remove_from_hash_queue(struct buffer_head * bh)
1.1 root 140: {
141: if (bh->b_next)
142: bh->b_next->b_prev = bh->b_prev;
143: if (bh->b_prev)
144: bh->b_prev->b_next = bh->b_next;
145: if (hash(bh->b_dev,bh->b_blocknr) == bh)
146: hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
1.1.1.4 root 147: bh->b_next = bh->b_prev = NULL;
148: }
149:
150: static inline void remove_from_free_list(struct buffer_head * bh)
151: {
1.1 root 152: if (!(bh->b_prev_free) || !(bh->b_next_free))
153: panic("Free block list corrupted");
154: bh->b_prev_free->b_next_free = bh->b_next_free;
155: bh->b_next_free->b_prev_free = bh->b_prev_free;
156: if (free_list == bh)
157: free_list = bh->b_next_free;
1.1.1.4 root 158: bh->b_next_free = bh->b_prev_free = NULL;
159: }
160:
161: static inline void remove_from_queues(struct buffer_head * bh)
162: {
163: remove_from_hash_queue(bh);
164: remove_from_free_list(bh);
165: }
166:
167: static inline void put_first_free(struct buffer_head * bh)
168: {
169: if (!bh || (bh == free_list))
170: return;
171: remove_from_free_list(bh);
172: /* add to front of free list */
173: bh->b_next_free = free_list;
174: bh->b_prev_free = free_list->b_prev_free;
175: free_list->b_prev_free->b_next_free = bh;
176: free_list->b_prev_free = bh;
177: free_list = bh;
178: }
179:
180: static inline void put_last_free(struct buffer_head * bh)
181: {
182: if (!bh)
183: return;
184: if (bh == free_list) {
185: free_list = bh->b_next_free;
186: return;
187: }
188: remove_from_free_list(bh);
189: /* add to back of free list */
190: bh->b_next_free = free_list;
191: bh->b_prev_free = free_list->b_prev_free;
192: free_list->b_prev_free->b_next_free = bh;
193: free_list->b_prev_free = bh;
1.1 root 194: }
195:
196: static inline void insert_into_queues(struct buffer_head * bh)
197: {
198: /* put at end of free list */
199: bh->b_next_free = free_list;
200: bh->b_prev_free = free_list->b_prev_free;
201: free_list->b_prev_free->b_next_free = bh;
202: free_list->b_prev_free = bh;
203: /* put the buffer in new hash-queue if it has a device */
204: bh->b_prev = NULL;
205: bh->b_next = NULL;
206: if (!bh->b_dev)
207: return;
208: bh->b_next = hash(bh->b_dev,bh->b_blocknr);
209: hash(bh->b_dev,bh->b_blocknr) = bh;
1.1.1.7 root 210: if (bh->b_next)
211: bh->b_next->b_prev = bh;
1.1 root 212: }
213:
214: static struct buffer_head * find_buffer(int dev, int block)
215: {
216: struct buffer_head * tmp;
217:
218: for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
219: if (tmp->b_dev==dev && tmp->b_blocknr==block)
220: return tmp;
221: return NULL;
222: }
223:
224: /*
225: * Why like this, I hear you say... The reason is race-conditions.
226: * As we don't lock buffers (unless we are readint them, that is),
227: * something might happen to it while we sleep (ie a read-error
228: * will force it bad). This shouldn't really happen currently, but
229: * the code is ready.
230: */
231: struct buffer_head * get_hash_table(int dev, int block)
232: {
233: struct buffer_head * bh;
234:
1.1.1.2 root 235: for (;;) {
236: if (!(bh=find_buffer(dev,block)))
237: return NULL;
238: bh->b_count++;
239: wait_on_buffer(bh);
1.1.1.4 root 240: if (bh->b_dev == dev && bh->b_blocknr == block) {
241: put_last_free(bh);
1.1.1.2 root 242: return bh;
1.1.1.4 root 243: }
1.1.1.2 root 244: bh->b_count--;
1.1 root 245: }
246: }
247:
248: /*
249: * Ok, this is getblk, and it isn't very clear, again to hinder
250: * race-conditions. Most of the code is seldom used, (ie repeating),
251: * so it should be much more efficient than it looks.
1.1.1.2 root 252: *
1.1.1.3 root 253: * The algoritm is changed: hopefully better, and an elusive bug removed.
1.1.1.4 root 254: *
255: * 14.02.92: changed it to sync dirty buffers a bit: better performance
256: * when the filesystem starts to get full of dirty blocks (I hope).
1.1 root 257: */
1.1.1.2 root 258: #define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
1.1 root 259: struct buffer_head * getblk(int dev,int block)
260: {
1.1.1.4 root 261: struct buffer_head * bh, * tmp;
262: int buffers;
1.1 root 263:
264: repeat:
1.1.1.2 root 265: if (bh = get_hash_table(dev,block))
266: return bh;
1.1.1.4 root 267: buffers = NR_BUFFERS;
1.1.1.7 root 268: for (tmp = free_list ; buffers-- > 0 ; tmp = tmp->b_next_free) {
1.1.1.2 root 269: if (tmp->b_count)
270: continue;
271: if (!bh || BADNESS(tmp)<BADNESS(bh)) {
272: bh = tmp;
273: if (!BADNESS(tmp))
1.1 root 274: break;
275: }
1.1.1.7 root 276: #if 0
1.1.1.4 root 277: if (tmp->b_dirt)
278: ll_rw_block(WRITEA,tmp);
1.1.1.7 root 279: #endif
280: }
1.1.1.3 root 281: /* and repeat until we find something good */
1.1.1.2 root 282: if (!bh) {
1.1 root 283: sleep_on(&buffer_wait);
284: goto repeat;
285: }
1.1.1.2 root 286: wait_on_buffer(bh);
287: if (bh->b_count)
1.1 root 288: goto repeat;
1.1.1.8 root 289: if (bh->b_dirt) {
1.1.1.7 root 290: sync_buffers(bh->b_dev);
1.1.1.8 root 291: goto repeat;
1.1 root 292: }
1.1.1.2 root 293: /* NOTE!! While we slept waiting for this block, somebody else might */
294: /* already have added "this" block to the cache. check it */
295: if (find_buffer(dev,block))
296: goto repeat;
297: /* OK, FINALLY we know that this buffer is the only one of it's kind, */
298: /* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
299: bh->b_count=1;
300: bh->b_dirt=0;
301: bh->b_uptodate=0;
302: remove_from_queues(bh);
303: bh->b_dev=dev;
304: bh->b_blocknr=block;
305: insert_into_queues(bh);
306: return bh;
1.1 root 307: }
308:
309: void brelse(struct buffer_head * buf)
310: {
311: if (!buf)
312: return;
313: wait_on_buffer(buf);
314: if (!(buf->b_count--))
315: panic("Trying to free free buffer");
316: wake_up(&buffer_wait);
317: }
318:
319: /*
320: * bread() reads a specified block and returns the buffer that contains
321: * it. It returns NULL if the block was unreadable.
322: */
323: struct buffer_head * bread(int dev,int block)
324: {
325: struct buffer_head * bh;
326:
327: if (!(bh=getblk(dev,block)))
328: panic("bread: getblk returned NULL\n");
329: if (bh->b_uptodate)
330: return bh;
331: ll_rw_block(READ,bh);
1.1.1.2 root 332: wait_on_buffer(bh);
333: if (bh->b_uptodate)
334: return bh;
335: brelse(bh);
336: return NULL;
337: }
338:
1.1.1.3 root 339: #define COPYBLK(from,to) \
340: __asm__("cld\n\t" \
341: "rep\n\t" \
342: "movsl\n\t" \
343: ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
344: :"cx","di","si")
345:
346: /*
347: * bread_page reads four buffers into memory at the desired address. It's
348: * a function of its own, as there is some speed to be got by reading them
349: * all at the same time, not waiting for one to be read, and then another
350: * etc.
351: */
352: void bread_page(unsigned long address,int dev,int b[4])
353: {
354: struct buffer_head * bh[4];
355: int i;
356:
357: for (i=0 ; i<4 ; i++)
358: if (b[i]) {
359: if (bh[i] = getblk(dev,b[i]))
360: if (!bh[i]->b_uptodate)
361: ll_rw_block(READ,bh[i]);
362: } else
363: bh[i] = NULL;
364: for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
365: if (bh[i]) {
366: wait_on_buffer(bh[i]);
367: if (bh[i]->b_uptodate)
368: COPYBLK((unsigned long) bh[i]->b_data,address);
369: brelse(bh[i]);
370: }
371: }
372:
1.1.1.2 root 373: /*
374: * Ok, breada can be used as bread, but additionally to mark other
375: * blocks for reading as well. End the argument list with a negative
376: * number.
377: */
378: struct buffer_head * breada(int dev,int first, ...)
379: {
380: va_list args;
381: struct buffer_head * bh, *tmp;
382:
383: va_start(args,first);
384: if (!(bh=getblk(dev,first)))
385: panic("bread: getblk returned NULL\n");
386: if (!bh->b_uptodate)
387: ll_rw_block(READ,bh);
388: while ((first=va_arg(args,int))>=0) {
389: tmp=getblk(dev,first);
390: if (tmp) {
391: if (!tmp->b_uptodate)
1.1.1.7 root 392: ll_rw_block(READA,tmp);
1.1.1.2 root 393: tmp->b_count--;
394: }
395: }
396: va_end(args);
397: wait_on_buffer(bh);
1.1 root 398: if (bh->b_uptodate)
399: return bh;
400: brelse(bh);
401: return (NULL);
402: }
403:
1.1.1.2 root 404: void buffer_init(long buffer_end)
1.1 root 405: {
406: struct buffer_head * h = start_buffer;
1.1.1.2 root 407: void * b;
1.1 root 408: int i;
409:
1.1.1.2 root 410: if (buffer_end == 1<<20)
411: b = (void *) (640*1024);
412: else
413: b = (void *) buffer_end;
1.1 root 414: while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
1.1.1.6 root 415: if (((unsigned long) (h+1)) > 0xA0000) {
416: printk("buffer-list doesn't fit in low meg - contact Linus\n");
417: break;
418: }
1.1 root 419: h->b_dev = 0;
420: h->b_dirt = 0;
421: h->b_count = 0;
422: h->b_lock = 0;
423: h->b_uptodate = 0;
424: h->b_wait = NULL;
425: h->b_next = NULL;
426: h->b_prev = NULL;
427: h->b_data = (char *) b;
1.1.1.7 root 428: h->b_reqnext = NULL;
1.1 root 429: h->b_prev_free = h-1;
430: h->b_next_free = h+1;
431: h++;
432: NR_BUFFERS++;
433: if (b == (void *) 0x100000)
434: b = (void *) 0xA0000;
435: }
436: h--;
437: free_list = start_buffer;
438: free_list->b_prev_free = h;
439: h->b_next_free = free_list;
440: for (i=0;i<NR_HASH;i++)
1.1.1.4 root 441: hash_table[i] = NULL;
1.1 root 442: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.