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

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

unix.superglobalmegacorp.com

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