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

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: }      

unix.superglobalmegacorp.com

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