Annotation of linux/fs/buffer.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  *  'buffer.c' implements the buffer-cache functions. Race-conditions have
                      3:  * been avoided by NEVER letting a interrupt change a buffer (except for the
                      4:  * data, of course), but instead letting the caller do it. NOTE! As interrupts
                      5:  * can wake up a caller, some cli-sti sequences are needed to check for
                      6:  * sleep-on-calls. These should be extremely quick, though (I hope).
                      7:  */
                      8: 
                      9: #include <linux/config.h>
                     10: #include <linux/sched.h>
                     11: #include <linux/kernel.h>
                     12: #include <asm/system.h>
                     13: 
                     14: #if (BUFFER_END & 0xfff)
                     15: #error "Bad BUFFER_END value"
                     16: #endif
                     17: 
                     18: #if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000)
                     19: #error "Bad BUFFER_END value"
                     20: #endif
                     21: 
                     22: extern int end;
                     23: struct buffer_head * start_buffer = (struct buffer_head *) &end;
                     24: struct buffer_head * hash_table[NR_HASH];
                     25: static struct buffer_head * free_list;
                     26: static struct task_struct * buffer_wait = NULL;
                     27: int NR_BUFFERS = 0;
                     28: 
                     29: static inline void wait_on_buffer(struct buffer_head * bh)
                     30: {
                     31:        cli();
                     32:        while (bh->b_lock)
                     33:                sleep_on(&bh->b_wait);
                     34:        sti();
                     35: }
                     36: 
                     37: int sys_sync(void)
                     38: {
                     39:        int i;
                     40:        struct buffer_head * bh;
                     41: 
                     42:        sync_inodes();          /* write out inodes into buffers */
                     43:        bh = start_buffer;
                     44:        for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
                     45:                wait_on_buffer(bh);
                     46:                if (bh->b_dirt)
                     47:                        ll_rw_block(WRITE,bh);
                     48:        }
                     49:        return 0;
                     50: }
                     51: 
                     52: static int sync_dev(int dev)
                     53: {
                     54:        int i;
                     55:        struct buffer_head * bh;
                     56: 
                     57:        bh = start_buffer;
                     58:        for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
                     59:                if (bh->b_dev != dev)
                     60:                        continue;
                     61:                wait_on_buffer(bh);
                     62:                if (bh->b_dirt)
                     63:                        ll_rw_block(WRITE,bh);
                     64:        }
                     65:        return 0;
                     66: }
                     67: 
                     68: #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
                     69: #define hash(dev,block) hash_table[_hashfn(dev,block)]
                     70: 
                     71: static inline void remove_from_queues(struct buffer_head * bh)
                     72: {
                     73: /* remove from hash-queue */
                     74:        if (bh->b_next)
                     75:                bh->b_next->b_prev = bh->b_prev;
                     76:        if (bh->b_prev)
                     77:                bh->b_prev->b_next = bh->b_next;
                     78:        if (hash(bh->b_dev,bh->b_blocknr) == bh)
                     79:                hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
                     80: /* remove from free list */
                     81:        if (!(bh->b_prev_free) || !(bh->b_next_free))
                     82:                panic("Free block list corrupted");
                     83:        bh->b_prev_free->b_next_free = bh->b_next_free;
                     84:        bh->b_next_free->b_prev_free = bh->b_prev_free;
                     85:        if (free_list == bh)
                     86:                free_list = bh->b_next_free;
                     87: }
                     88: 
                     89: static inline void insert_into_queues(struct buffer_head * bh)
                     90: {
                     91: /* put at end of free list */
                     92:        bh->b_next_free = free_list;
                     93:        bh->b_prev_free = free_list->b_prev_free;
                     94:        free_list->b_prev_free->b_next_free = bh;
                     95:        free_list->b_prev_free = bh;
                     96: /* put the buffer in new hash-queue if it has a device */
                     97:        bh->b_prev = NULL;
                     98:        bh->b_next = NULL;
                     99:        if (!bh->b_dev)
                    100:                return;
                    101:        bh->b_next = hash(bh->b_dev,bh->b_blocknr);
                    102:        hash(bh->b_dev,bh->b_blocknr) = bh;
                    103:        bh->b_next->b_prev = bh;
                    104: }
                    105: 
                    106: static struct buffer_head * find_buffer(int dev, int block)
                    107: {              
                    108:        struct buffer_head * tmp;
                    109: 
                    110:        for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
                    111:                if (tmp->b_dev==dev && tmp->b_blocknr==block)
                    112:                        return tmp;
                    113:        return NULL;
                    114: }
                    115: 
                    116: /*
                    117:  * Why like this, I hear you say... The reason is race-conditions.
                    118:  * As we don't lock buffers (unless we are readint them, that is),
                    119:  * something might happen to it while we sleep (ie a read-error
                    120:  * will force it bad). This shouldn't really happen currently, but
                    121:  * the code is ready.
                    122:  */
                    123: struct buffer_head * get_hash_table(int dev, int block)
                    124: {
                    125:        struct buffer_head * bh;
                    126: 
                    127: repeat:
                    128:        if (!(bh=find_buffer(dev,block)))
                    129:                return NULL;
                    130:        bh->b_count++;
                    131:        wait_on_buffer(bh);
                    132:        if (bh->b_dev != dev || bh->b_blocknr != block) {
                    133:                brelse(bh);
                    134:                goto repeat;
                    135:        }
                    136:        return bh;
                    137: }
                    138: 
                    139: /*
                    140:  * Ok, this is getblk, and it isn't very clear, again to hinder
                    141:  * race-conditions. Most of the code is seldom used, (ie repeating),
                    142:  * so it should be much more efficient than it looks.
                    143:  */
                    144: struct buffer_head * getblk(int dev,int block)
                    145: {
                    146:        struct buffer_head * tmp;
                    147: 
                    148: repeat:
1.1.1.2 ! root      149:        if ((tmp=get_hash_table(dev,block)))
1.1       root      150:                return tmp;
                    151:        tmp = free_list;
                    152:        do {
                    153:                if (!tmp->b_count) {
                    154:                        wait_on_buffer(tmp);    /* we still have to wait */
                    155:                        if (!tmp->b_count)      /* on it, it might be dirty */
                    156:                                break;
                    157:                }
                    158:                tmp = tmp->b_next_free;
                    159:        } while (tmp != free_list || (tmp=NULL));
                    160:        /* Kids, don't try THIS at home ^^^^^. Magic */
                    161:        if (!tmp) {
                    162:                printk("Sleeping on free buffer ..");
                    163:                sleep_on(&buffer_wait);
                    164:                printk("ok\n");
                    165:                goto repeat;
                    166:        }
                    167:        tmp->b_count++;
                    168:        remove_from_queues(tmp);
                    169: /*
                    170:  * Now, when we know nobody can get to this node (as it's removed from the
                    171:  * free list), we write it out. We can sleep here without fear of race-
                    172:  * conditions.
                    173:  */
                    174:        if (tmp->b_dirt)
                    175:                sync_dev(tmp->b_dev);
                    176: /* update buffer contents */
                    177:        tmp->b_dev=dev;
                    178:        tmp->b_blocknr=block;
                    179:        tmp->b_dirt=0;
                    180:        tmp->b_uptodate=0;
                    181: /* NOTE!! While we possibly slept in sync_dev(), somebody else might have
                    182:  * added "this" block already, so check for that. Thank God for goto's.
                    183:  */
                    184:        if (find_buffer(dev,block)) {
                    185:                tmp->b_dev=0;           /* ok, someone else has beaten us */
                    186:                tmp->b_blocknr=0;       /* to it - free this block and */
                    187:                tmp->b_count=0;         /* try again */
                    188:                insert_into_queues(tmp);
                    189:                goto repeat;
                    190:        }
                    191: /* and then insert into correct position */
                    192:        insert_into_queues(tmp);
                    193:        return tmp;
                    194: }
                    195: 
                    196: void brelse(struct buffer_head * buf)
                    197: {
                    198:        if (!buf)
                    199:                return;
                    200:        wait_on_buffer(buf);
                    201:        if (!(buf->b_count--))
                    202:                panic("Trying to free free buffer");
                    203:        wake_up(&buffer_wait);
                    204: }
                    205: 
                    206: /*
                    207:  * bread() reads a specified block and returns the buffer that contains
                    208:  * it. It returns NULL if the block was unreadable.
                    209:  */
                    210: struct buffer_head * bread(int dev,int block)
                    211: {
                    212:        struct buffer_head * bh;
                    213: 
                    214:        if (!(bh=getblk(dev,block)))
                    215:                panic("bread: getblk returned NULL\n");
                    216:        if (bh->b_uptodate)
                    217:                return bh;
                    218:        ll_rw_block(READ,bh);
                    219:        if (bh->b_uptodate)
                    220:                return bh;
                    221:        brelse(bh);
                    222:        return (NULL);
                    223: }
                    224: 
                    225: void buffer_init(void)
                    226: {
                    227:        struct buffer_head * h = start_buffer;
                    228:        void * b = (void *) BUFFER_END;
                    229:        int i;
                    230: 
                    231:        while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
                    232:                h->b_dev = 0;
                    233:                h->b_dirt = 0;
                    234:                h->b_count = 0;
                    235:                h->b_lock = 0;
                    236:                h->b_uptodate = 0;
                    237:                h->b_wait = NULL;
                    238:                h->b_next = NULL;
                    239:                h->b_prev = NULL;
                    240:                h->b_data = (char *) b;
                    241:                h->b_prev_free = h-1;
                    242:                h->b_next_free = h+1;
                    243:                h++;
                    244:                NR_BUFFERS++;
                    245:                if (b == (void *) 0x100000)
                    246:                        b = (void *) 0xA0000;
                    247:        }
                    248:        h--;
                    249:        free_list = start_buffer;
                    250:        free_list->b_prev_free = h;
                    251:        h->b_next_free = free_list;
                    252:        for (i=0;i<NR_HASH;i++)
                    253:                hash_table[i]=NULL;
                    254: }      

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.