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

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:
        !           149:        if (tmp=get_hash_table(dev,block))
        !           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.