|
|
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;
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(); /* write out inodes into buffers */
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:
1.1.1.2 root 59: int sync_dev(int dev)
1.1 root 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);
1.1.1.2 root 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)
1.1 root 79: ll_rw_block(WRITE,bh);
80: }
81: return 0;
82: }
83:
1.1.1.3 ! root 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:
1.1.1.2 root 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: */
113: void check_disk_change(int dev)
114: {
115: int i;
116:
117: if (MAJOR(dev) != 2)
118: return;
1.1.1.3 ! root 119: if (!floppy_change(dev & 0x03))
1.1.1.2 root 120: return;
121: for (i=0 ; i<NR_SUPER ; i++)
1.1.1.3 ! root 122: if (super_block[i].s_dev == dev)
1.1.1.2 root 123: put_super(super_block[i].s_dev);
1.1.1.3 ! root 124: invalidate_inodes(dev);
! 125: invalidate_buffers(dev);
1.1.1.2 root 126: }
127:
1.1 root 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: /* remove from hash-queue */
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: /* 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:
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 */
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: * 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: */
183: struct buffer_head * get_hash_table(int dev, int block)
184: {
185: struct buffer_head * bh;
186:
1.1.1.2 root 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--;
1.1 root 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.
1.1.1.2 root 202: *
1.1.1.3 ! root 203: * The algoritm is changed: hopefully better, and an elusive bug removed.
1.1 root 204: */
1.1.1.2 root 205: #define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
1.1 root 206: struct buffer_head * getblk(int dev,int block)
207: {
1.1.1.2 root 208: struct buffer_head * tmp, * bh;
1.1 root 209:
210: repeat:
1.1.1.2 root 211: if (bh = get_hash_table(dev,block))
212: return bh;
1.1 root 213: tmp = free_list;
214: do {
1.1.1.2 root 215: if (tmp->b_count)
216: continue;
217: if (!bh || BADNESS(tmp)<BADNESS(bh)) {
218: bh = tmp;
219: if (!BADNESS(tmp))
1.1 root 220: break;
221: }
1.1.1.3 ! root 222: /* and repeat until we find something good */
1.1.1.2 root 223: } while ((tmp = tmp->b_next_free) != free_list);
224: if (!bh) {
1.1 root 225: sleep_on(&buffer_wait);
226: goto repeat;
227: }
1.1.1.2 root 228: wait_on_buffer(bh);
229: if (bh->b_count)
1.1 root 230: goto repeat;
1.1.1.2 root 231: while (bh->b_dirt) {
232: sync_dev(bh->b_dev);
233: wait_on_buffer(bh);
234: if (bh->b_count)
235: goto repeat;
1.1 root 236: }
1.1.1.2 root 237: /* NOTE!! While we slept waiting for this block, somebody else might */
238: /* already have added "this" block to the cache. check it */
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 */
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;
1.1 root 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: * bread() reads a specified block and returns the buffer that contains
265: * it. It returns NULL if the block was unreadable.
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);
1.1.1.2 root 276: wait_on_buffer(bh);
277: if (bh->b_uptodate)
278: return bh;
279: brelse(bh);
280: return NULL;
281: }
282:
1.1.1.3 ! root 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: */
! 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:
1.1.1.2 root 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: */
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);
1.1 root 342: if (bh->b_uptodate)
343: return bh;
344: brelse(bh);
345: return (NULL);
346: }
347:
1.1.1.2 root 348: void buffer_init(long buffer_end)
1.1 root 349: {
350: struct buffer_head * h = start_buffer;
1.1.1.2 root 351: void * b;
1.1 root 352: int i;
353:
1.1.1.2 root 354: if (buffer_end == 1<<20)
355: b = (void *) (640*1024);
356: else
357: b = (void *) buffer_end;
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.