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

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