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

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: {
                     61:        sync_inodes();          /* write out inodes into buffers */
                     62:        sync_buffers(0);
1.1       root       63:        return 0;
                     64: }
                     65: 
1.1.1.2   root       66: int sync_dev(int dev)
1.1       root       67: {
1.1.1.4   root       68:        sync_buffers(dev);
1.1.1.2   root       69:        sync_inodes();
1.1.1.4   root       70:        sync_buffers(dev);
1.1       root       71:        return 0;
                     72: }
                     73: 
1.1.1.3   root       74: void inline invalidate_buffers(int dev)
                     75: {
                     76:        int i;
                     77:        struct buffer_head * bh;
                     78: 
                     79:        bh = start_buffer;
                     80:        for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
                     81:                if (bh->b_dev != dev)
                     82:                        continue;
                     83:                wait_on_buffer(bh);
                     84:                if (bh->b_dev == dev)
                     85:                        bh->b_uptodate = bh->b_dirt = 0;
                     86:        }
                     87: }
                     88: 
1.1.1.2   root       89: /*
                     90:  * This routine checks whether a floppy has been changed, and
                     91:  * invalidates all buffer-cache-entries in that case. This
                     92:  * is a relatively slow routine, so we have to try to minimize using
                     93:  * it. Thus it is called only upon a 'mount' or 'open'. This
                     94:  * is the best way of combining speed and utility, I think.
                     95:  * People changing diskettes in the middle of an operation deserve
                     96:  * to loose :-)
                     97:  *
                     98:  * NOTE! Although currently this is only for floppies, the idea is
                     99:  * that any additional removable block-device will use this routine,
                    100:  * and that mount/open needn't know that floppies/whatever are
                    101:  * special.
                    102:  */
                    103: void check_disk_change(int dev)
                    104: {
                    105:        int i;
1.1.1.5   root      106:        struct buffer_head * bh;
1.1.1.2   root      107: 
                    108:        if (MAJOR(dev) != 2)
                    109:                return;
1.1.1.5   root      110:        if (!(bh = getblk(dev,0)))
                    111:                return;
                    112:        i = floppy_change(bh);
                    113:        brelse(bh);
                    114:        if (!i)
1.1.1.2   root      115:                return;
                    116:        for (i=0 ; i<NR_SUPER ; i++)
1.1.1.3   root      117:                if (super_block[i].s_dev == dev)
1.1.1.2   root      118:                        put_super(super_block[i].s_dev);
1.1.1.3   root      119:        invalidate_inodes(dev);
                    120:        invalidate_buffers(dev);
1.1.1.2   root      121: }
                    122: 
1.1       root      123: #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
                    124: #define hash(dev,block) hash_table[_hashfn(dev,block)]
                    125: 
1.1.1.4   root      126: static inline void remove_from_hash_queue(struct buffer_head * bh)
1.1       root      127: {
                    128:        if (bh->b_next)
                    129:                bh->b_next->b_prev = bh->b_prev;
                    130:        if (bh->b_prev)
                    131:                bh->b_prev->b_next = bh->b_next;
                    132:        if (hash(bh->b_dev,bh->b_blocknr) == bh)
                    133:                hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
1.1.1.4   root      134:        bh->b_next = bh->b_prev = NULL;
                    135: }
                    136: 
                    137: static inline void remove_from_free_list(struct buffer_head * bh)
                    138: {
1.1       root      139:        if (!(bh->b_prev_free) || !(bh->b_next_free))
                    140:                panic("Free block list corrupted");
                    141:        bh->b_prev_free->b_next_free = bh->b_next_free;
                    142:        bh->b_next_free->b_prev_free = bh->b_prev_free;
                    143:        if (free_list == bh)
                    144:                free_list = bh->b_next_free;
1.1.1.4   root      145:        bh->b_next_free = bh->b_prev_free = NULL;
                    146: }
                    147: 
                    148: static inline void remove_from_queues(struct buffer_head * bh)
                    149: {
                    150:        remove_from_hash_queue(bh);
                    151:        remove_from_free_list(bh);
                    152: }
                    153: 
                    154: static inline void put_first_free(struct buffer_head * bh)
                    155: {
                    156:        if (!bh || (bh == free_list))
                    157:                return;
                    158:        remove_from_free_list(bh);
                    159: /* add to front of free list */
                    160:        bh->b_next_free = free_list;
                    161:        bh->b_prev_free = free_list->b_prev_free;
                    162:        free_list->b_prev_free->b_next_free = bh;
                    163:        free_list->b_prev_free = bh;
                    164:        free_list = bh;
                    165: }
                    166: 
                    167: static inline void put_last_free(struct buffer_head * bh)
                    168: {
                    169:        if (!bh)
                    170:                return;
                    171:        if (bh == free_list) {
                    172:                free_list = bh->b_next_free;
                    173:                return;
                    174:        }
                    175:        remove_from_free_list(bh);
                    176: /* add to back of free list */
                    177:        bh->b_next_free = free_list;
                    178:        bh->b_prev_free = free_list->b_prev_free;
                    179:        free_list->b_prev_free->b_next_free = bh;
                    180:        free_list->b_prev_free = bh;
1.1       root      181: }
                    182: 
                    183: static inline void insert_into_queues(struct buffer_head * bh)
                    184: {
                    185: /* put at end of free list */
                    186:        bh->b_next_free = free_list;
                    187:        bh->b_prev_free = free_list->b_prev_free;
                    188:        free_list->b_prev_free->b_next_free = bh;
                    189:        free_list->b_prev_free = bh;
                    190: /* put the buffer in new hash-queue if it has a device */
                    191:        bh->b_prev = NULL;
                    192:        bh->b_next = NULL;
                    193:        if (!bh->b_dev)
                    194:                return;
                    195:        bh->b_next = hash(bh->b_dev,bh->b_blocknr);
                    196:        hash(bh->b_dev,bh->b_blocknr) = bh;
1.1.1.7 ! root      197:        if (bh->b_next)
        !           198:                bh->b_next->b_prev = bh;
1.1       root      199: }
                    200: 
                    201: static struct buffer_head * find_buffer(int dev, int block)
                    202: {              
                    203:        struct buffer_head * tmp;
                    204: 
                    205:        for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
                    206:                if (tmp->b_dev==dev && tmp->b_blocknr==block)
                    207:                        return tmp;
                    208:        return NULL;
                    209: }
                    210: 
                    211: /*
                    212:  * Why like this, I hear you say... The reason is race-conditions.
                    213:  * As we don't lock buffers (unless we are readint them, that is),
                    214:  * something might happen to it while we sleep (ie a read-error
                    215:  * will force it bad). This shouldn't really happen currently, but
                    216:  * the code is ready.
                    217:  */
                    218: struct buffer_head * get_hash_table(int dev, int block)
                    219: {
                    220:        struct buffer_head * bh;
                    221: 
1.1.1.2   root      222:        for (;;) {
                    223:                if (!(bh=find_buffer(dev,block)))
                    224:                        return NULL;
                    225:                bh->b_count++;
                    226:                wait_on_buffer(bh);
1.1.1.4   root      227:                if (bh->b_dev == dev && bh->b_blocknr == block) {
                    228:                        put_last_free(bh);
1.1.1.2   root      229:                        return bh;
1.1.1.4   root      230:                }
1.1.1.2   root      231:                bh->b_count--;
1.1       root      232:        }
                    233: }
                    234: 
                    235: /*
                    236:  * Ok, this is getblk, and it isn't very clear, again to hinder
                    237:  * race-conditions. Most of the code is seldom used, (ie repeating),
                    238:  * so it should be much more efficient than it looks.
1.1.1.2   root      239:  *
1.1.1.3   root      240:  * The algoritm is changed: hopefully better, and an elusive bug removed.
1.1.1.4   root      241:  *
                    242:  * 14.02.92: changed it to sync dirty buffers a bit: better performance
                    243:  * when the filesystem starts to get full of dirty blocks (I hope).
1.1       root      244:  */
1.1.1.2   root      245: #define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
1.1       root      246: struct buffer_head * getblk(int dev,int block)
                    247: {
1.1.1.4   root      248:        struct buffer_head * bh, * tmp;
                    249:        int buffers;
1.1       root      250: 
                    251: repeat:
1.1.1.2   root      252:        if (bh = get_hash_table(dev,block))
                    253:                return bh;
1.1.1.4   root      254:        buffers = NR_BUFFERS;
1.1.1.7 ! root      255:        for (tmp = free_list ; buffers-- > 0 ; tmp = tmp->b_next_free) {
1.1.1.2   root      256:                if (tmp->b_count)
                    257:                        continue;
                    258:                if (!bh || BADNESS(tmp)<BADNESS(bh)) {
                    259:                        bh = tmp;
                    260:                        if (!BADNESS(tmp))
1.1       root      261:                                break;
                    262:                }
1.1.1.7 ! root      263: #if 0
1.1.1.4   root      264:                if (tmp->b_dirt)
                    265:                        ll_rw_block(WRITEA,tmp);
1.1.1.7 ! root      266: #endif
        !           267:        }
1.1.1.3   root      268: /* and repeat until we find something good */
1.1.1.2   root      269:        if (!bh) {
1.1       root      270:                sleep_on(&buffer_wait);
                    271:                goto repeat;
                    272:        }
1.1.1.2   root      273:        wait_on_buffer(bh);
                    274:        if (bh->b_count)
1.1       root      275:                goto repeat;
1.1.1.2   root      276:        while (bh->b_dirt) {
1.1.1.7 ! root      277:                sync_buffers(bh->b_dev);
1.1.1.2   root      278:                wait_on_buffer(bh);
                    279:                if (bh->b_count)
                    280:                        goto repeat;
1.1       root      281:        }
1.1.1.2   root      282: /* NOTE!! While we slept waiting for this block, somebody else might */
                    283: /* already have added "this" block to the cache. check it */
                    284:        if (find_buffer(dev,block))
                    285:                goto repeat;
                    286: /* OK, FINALLY we know that this buffer is the only one of it's kind, */
                    287: /* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
                    288:        bh->b_count=1;
                    289:        bh->b_dirt=0;
                    290:        bh->b_uptodate=0;
                    291:        remove_from_queues(bh);
                    292:        bh->b_dev=dev;
                    293:        bh->b_blocknr=block;
                    294:        insert_into_queues(bh);
                    295:        return bh;
1.1       root      296: }
                    297: 
                    298: void brelse(struct buffer_head * buf)
                    299: {
                    300:        if (!buf)
                    301:                return;
                    302:        wait_on_buffer(buf);
                    303:        if (!(buf->b_count--))
                    304:                panic("Trying to free free buffer");
                    305:        wake_up(&buffer_wait);
                    306: }
                    307: 
                    308: /*
                    309:  * bread() reads a specified block and returns the buffer that contains
                    310:  * it. It returns NULL if the block was unreadable.
                    311:  */
                    312: struct buffer_head * bread(int dev,int block)
                    313: {
                    314:        struct buffer_head * bh;
                    315: 
                    316:        if (!(bh=getblk(dev,block)))
                    317:                panic("bread: getblk returned NULL\n");
                    318:        if (bh->b_uptodate)
                    319:                return bh;
                    320:        ll_rw_block(READ,bh);
1.1.1.2   root      321:        wait_on_buffer(bh);
                    322:        if (bh->b_uptodate)
                    323:                return bh;
                    324:        brelse(bh);
                    325:        return NULL;
                    326: }
                    327: 
1.1.1.3   root      328: #define COPYBLK(from,to) \
                    329: __asm__("cld\n\t" \
                    330:        "rep\n\t" \
                    331:        "movsl\n\t" \
                    332:        ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
                    333:        :"cx","di","si")
                    334: 
                    335: /*
                    336:  * bread_page reads four buffers into memory at the desired address. It's
                    337:  * a function of its own, as there is some speed to be got by reading them
                    338:  * all at the same time, not waiting for one to be read, and then another
                    339:  * etc.
                    340:  */
                    341: void bread_page(unsigned long address,int dev,int b[4])
                    342: {
                    343:        struct buffer_head * bh[4];
                    344:        int i;
                    345: 
                    346:        for (i=0 ; i<4 ; i++)
                    347:                if (b[i]) {
                    348:                        if (bh[i] = getblk(dev,b[i]))
                    349:                                if (!bh[i]->b_uptodate)
                    350:                                        ll_rw_block(READ,bh[i]);
                    351:                } else
                    352:                        bh[i] = NULL;
                    353:        for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
                    354:                if (bh[i]) {
                    355:                        wait_on_buffer(bh[i]);
                    356:                        if (bh[i]->b_uptodate)
                    357:                                COPYBLK((unsigned long) bh[i]->b_data,address);
                    358:                        brelse(bh[i]);
                    359:                }
                    360: }
                    361: 
1.1.1.2   root      362: /*
                    363:  * Ok, breada can be used as bread, but additionally to mark other
                    364:  * blocks for reading as well. End the argument list with a negative
                    365:  * number.
                    366:  */
                    367: struct buffer_head * breada(int dev,int first, ...)
                    368: {
                    369:        va_list args;
                    370:        struct buffer_head * bh, *tmp;
                    371: 
                    372:        va_start(args,first);
                    373:        if (!(bh=getblk(dev,first)))
                    374:                panic("bread: getblk returned NULL\n");
                    375:        if (!bh->b_uptodate)
                    376:                ll_rw_block(READ,bh);
                    377:        while ((first=va_arg(args,int))>=0) {
                    378:                tmp=getblk(dev,first);
                    379:                if (tmp) {
                    380:                        if (!tmp->b_uptodate)
1.1.1.7 ! root      381:                                ll_rw_block(READA,tmp);
1.1.1.2   root      382:                        tmp->b_count--;
                    383:                }
                    384:        }
                    385:        va_end(args);
                    386:        wait_on_buffer(bh);
1.1       root      387:        if (bh->b_uptodate)
                    388:                return bh;
                    389:        brelse(bh);
                    390:        return (NULL);
                    391: }
                    392: 
1.1.1.2   root      393: void buffer_init(long buffer_end)
1.1       root      394: {
                    395:        struct buffer_head * h = start_buffer;
1.1.1.2   root      396:        void * b;
1.1       root      397:        int i;
                    398: 
1.1.1.2   root      399:        if (buffer_end == 1<<20)
                    400:                b = (void *) (640*1024);
                    401:        else
                    402:                b = (void *) buffer_end;
1.1       root      403:        while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
1.1.1.6   root      404:                if (((unsigned long) (h+1)) > 0xA0000) {
                    405:                        printk("buffer-list doesn't fit in low meg - contact Linus\n");
                    406:                        break;
                    407:                }
1.1       root      408:                h->b_dev = 0;
                    409:                h->b_dirt = 0;
                    410:                h->b_count = 0;
                    411:                h->b_lock = 0;
                    412:                h->b_uptodate = 0;
                    413:                h->b_wait = NULL;
                    414:                h->b_next = NULL;
                    415:                h->b_prev = NULL;
                    416:                h->b_data = (char *) b;
1.1.1.7 ! root      417:                h->b_reqnext = NULL;
1.1       root      418:                h->b_prev_free = h-1;
                    419:                h->b_next_free = h+1;
                    420:                h++;
                    421:                NR_BUFFERS++;
                    422:                if (b == (void *) 0x100000)
                    423:                        b = (void *) 0xA0000;
                    424:        }
                    425:        h--;
                    426:        free_list = start_buffer;
                    427:        free_list->b_prev_free = h;
                    428:        h->b_next_free = free_list;
                    429:        for (i=0;i<NR_HASH;i++)
1.1.1.4   root      430:                hash_table[i] = NULL;
1.1       root      431: }      

unix.superglobalmegacorp.com

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