?? cache.c
字號:
real_remove_cached_blocks(dev, allow_writes, &bc.normal); real_remove_cached_blocks(dev, allow_writes, &bc.locked); max_device_blocks[dev] = 0; UNLOCK(bc.lock); return 0;}intflush_blocks(int dev, fs_off_t bnum, int nblocks){ int cur, i; cache_ent *ce; cache_ent *ents[NUM_FLUSH_BLOCKS]; if (nblocks == 0) /* might as well check for this */ return 0; LOCK(bc.lock); cur = 0; for(; nblocks > 0; nblocks--, bnum++) { ce = block_lookup(dev, bnum); if (ce == NULL) continue; if (bnum != ce->block_num || dev != ce->dev) { UNLOCK(bc.lock); panic("error2: looked up dev %d block %ld but found %d %ld\n", dev, bnum, ce->dev, ce->block_num); return EBADF; } if ((ce->flags & CE_DIRTY) == 0 && ce->clone == NULL) continue; ce->flags |= CE_BUSY; ents[cur++] = ce; if (cur >= NUM_FLUSH_BLOCKS) { UNLOCK(bc.lock); qsort(ents, cur, sizeof(cache_ent **), cache_ent_cmp); flush_ents(ents, cur); LOCK(bc.lock); for(i=0; i < cur; i++) { ents[i]->flags &= ~CE_BUSY; } cur = 0; } } UNLOCK(bc.lock); if (cur == 0) /* nothing more to do */ return 0; /* flush out the last few buggers */ qsort(ents, cur, sizeof(cache_ent **), cache_ent_cmp); flush_ents(ents, cur); for(i=0; i < cur; i++) { ents[i]->flags &= ~CE_BUSY; } return 0;}intmark_blocks_dirty(int dev, fs_off_t bnum, int nblocks){ int ret = 0; cache_ent *ce; LOCK(bc.lock); while(nblocks > 0) { ce = block_lookup(dev, bnum); if (ce) { ce->flags |= CE_DIRTY; bnum += 1; nblocks -= 1; } else { /* hmmm, that's odd, didn't find it */ printf("** mark_blocks_diry couldn't find block %ld (len %d)\n", bnum, nblocks); ret = ENOENT; break; } } UNLOCK(bc.lock); return ret;}intrelease_block(int dev, fs_off_t bnum){ cache_ent *ce; /* printf("rlsb: %ld\n", bnum); */ LOCK(bc.lock); ce = block_lookup(dev, bnum); if (ce) { if (bnum != ce->block_num || dev != ce->dev) { panic("*** error3: looked up dev %d block %ld but found %d %ld\n", dev, bnum, ce->dev, ce->block_num); UNLOCK(bc.lock); return EBADF; } ce->lock--; if (ce->lock < 0) { printf("rlsb: whoa nellie! ce %ld has lock == %d\n", ce->block_num, ce->lock); } if (ce->lock == 0) { delete_from_list(&bc.locked, ce); add_to_head(&bc.normal, ce); } } else { /* hmmm, that's odd, didn't find it */ panic("** release_block asked to find %ld but it's not here\n", bnum); } UNLOCK(bc.lock); return 0;}static cache_ent *new_cache_ent(int bsize){ cache_ent *ce; ce = (cache_ent *)calloc(1, sizeof(cache_ent)); if (ce == NULL) { panic("*** error: cache can't allocate memory!\n"); return NULL; } ce->data = malloc(bsize); if (ce->data == NULL) { free(ce); panic("** error cache can't allocate data memory\n"); UNLOCK(bc.lock); return NULL; } ce->dev = -1; ce->block_num = -1; return ce;}static voidget_ents(cache_ent **ents, int num_needed, int max, int *num_gotten, int bsize){ int cur, retry_counter = 0, max_retry = num_needed * 256; cache_ent *ce; if (num_needed > max) panic("get_ents: num_needed %d but max %d (doh!)\n", num_needed, max); /* if the cache isn't full yet, just allocate the blocks */ for(cur=0; bc.cur_blocks < bc.max_blocks && cur < num_needed; cur++) { ents[cur] = new_cache_ent(bsize); if (ents[cur] == NULL) break; bc.cur_blocks++; } /* pluck off blocks from the LRU end of the normal list, keep trying too */ while(cur < num_needed && retry_counter < max_retry) { for(ce=bc.normal.lru; ce && cur < num_needed; ce=ce->next) { if (ce->lock) panic("get_ents: normal list has locked blocks (ce 0x%x)\n",ce); if (ce->flags & CE_BUSY) /* don't touch busy blocks */ continue; ce->flags |= CE_BUSY; ents[cur++] = ce; } if (cur < num_needed) { UNLOCK(bc.lock); snooze(10000); LOCK(bc.lock); retry_counter++; } } if (cur < num_needed && retry_counter >= max_retry) { /* oh shit! */ dump_cache_list(); UNLOCK(bc.lock); panic("get_ents: waited too long; can't get enough ce's (c %d n %d)\n", cur, num_needed); } /* If the last block is a dirty one, try to get more of 'em so that we can flush a bunch of blocks at once. */ if (cur && cur < max && ((ents[cur-1]->flags & CE_DIRTY) || ents[cur-1]->clone)) { for(ce=ents[cur-1]->next; ce && cur < max; ce=ce->next) { if (ce->flags & CE_BUSY) /* don't touch busy blocks */ continue; if (ce->lock) panic("get_ents:2 dirty list has locked blocks (ce 0x%x)\n",ce); ce->flags |= CE_BUSY; ents[cur++] = ce; } } *num_gotten = cur;}static intread_into_ents(int dev, fs_off_t bnum, cache_ent **ents, int num, int bsize){ int i, ret; struct iovec *iov; iov = get_iovec_array(); for(i=0; i < num; i++) { iov[i].iov_base = ents[i]->data; iov[i].iov_len = bsize; } /* printf("readv @ %ld for %d blocks\n", bnum, num); */ ret = readv_pos(dev, bnum*bsize, iov, num); release_iovec_array(iov); if (ret != num*bsize) { printf("read_into_ents: asked to read %d bytes but got %d\n", num*bsize, ret); printf("*** iov @ 0x%x (num %d)\n", iov, num); return EINVAL; } else return 0;}#define CACHE_READ 0x0001#define CACHE_WRITE 0x0002#define CACHE_NOOP 0x0004 /* for getting empty blocks */#define CACHE_LOCKED 0x0008#define CACHE_READ_AHEAD_OK 0x0010 /* it's ok to do read-ahead */static char *op_to_str(int op){ static char buff[128]; if (op & CACHE_READ) strcpy(buff, "RD"); else if (op & CACHE_WRITE) strcpy(buff, "WR"); else if (op & CACHE_NOOP) strcpy(buff, "NOP"); if (op & CACHE_LOCKED) strcat(buff, " LOCKED"); if (op & CACHE_READ_AHEAD_OK) strcat(buff, " (AHEAD)"); return buff;}static intcache_block_io(int dev, fs_off_t bnum, void *data, fs_off_t num_blocks, int bsize, int op, void **dataptr){ size_t err = 0; cache_ent *ce; cache_ent_list *cel; if (chatty_io > 1) printf("cbio: bnum %ld nblock %ld bsize %d op %s\n", bnum, num_blocks, bsize, op_to_str(op)); /* some sanity checks first */ if (bsize == 0) panic("cache_io: block size == 0 for bnum %ld?!?\n", bnum); if (num_blocks == 0) panic("cache_io: bnum %ld has num_blocks == 0!\n", bnum); if (data == NULL && dataptr == NULL) { printf("major butthead move: null data and dataptr! bnum %ld:%ld\n", bnum, num_blocks); return ENOMEM; } if (data == NULL) { if (num_blocks != 1) /* get_block() should never do that */ panic("cache_io: num_blocks %ld but should be 1\n", num_blocks); if (op & CACHE_WRITE) panic("cache_io: get_block() asked to write?!?\n"); } if (bnum + num_blocks > max_device_blocks[dev]) { printf("dev %d: access to blocks %ld:%ld but max_dev_blocks is %ld\n", dev, bnum, num_blocks, max_device_blocks[dev]);*(int *)0x3100 = 0xc0debabe; return EINVAL; } last_cache_access = system_time(); /* if the i/o is greater than 64k, do it directly */ if (num_blocks * bsize >= 64 * 1024) { char *ptr; fs_off_t tmp; if (data == NULL || (op & CACHE_LOCKED)) { panic("*** asked to do a large locked io that's too hard!\n"); } if (op & CACHE_READ) { if (read_phys_blocks(dev, bnum, data, num_blocks, bsize) != 0) { printf("cache read:read_phys_blocks failed (%s on blocks %ld:%ld)!\n", strerror(errno), bnum, num_blocks); return EINVAL; } LOCK(bc.lock); /* if any of the blocks are in the cache, grab them instead */ ptr = data; for(tmp=bnum; tmp < bnum+num_blocks; tmp++, ptr+=bsize) { ce = block_lookup(dev, tmp); /* if we find a block in the cache we have to copy its data just in case it is more recent than what we just read from disk (which could happen if someone wrote these blocks after we did the read but before we locked the cache and entered this loop). */ if (ce) { if (tmp != ce->block_num || dev != ce->dev) { UNLOCK(bc.lock); panic("*** error4: looked up dev %d block %ld but " "found %d %ld\n", dev, tmp, ce->dev, ce->block_num); } memcpy(ptr, ce->data, bsize); } } UNLOCK(bc.lock); } else if (op & CACHE_WRITE) { LOCK(bc.lock); /* if any of the blocks are in the cache, update them too */ ptr = data; for(tmp=bnum; tmp < bnum+num_blocks; tmp++, ptr+=bsize) { ce = block_lookup(dev, tmp); if (ce) { if (tmp != ce->block_num || dev != ce->dev) { UNLOCK(bc.lock); panic("*** error5: looked up dev %d block %ld but " "found %d %ld\n", dev, tmp, ce->dev, ce->block_num); return EBADF; } /* XXXdbg -- this isn't strictly necessary */ if (ce->clone) { printf("over-writing cloned data (ce 0x%x bnum %ld)...\n", ce,tmp); flush_cache_ent(ce); } /* copy the data into the cache */ memcpy(ce->data, ptr, bsize); } } UNLOCK(bc.lock); if (write_phys_blocks(dev, bnum, data, num_blocks, bsize) != 0) { printf("cache write: write_phys_blocks failed (%s on blocks " "%ld:%ld)!\n", strerror(errno), bnum, num_blocks); return EINVAL; } } else { printf("bad cache op %d (bnum %ld nblocks %ld)\n", op, bnum, num_blocks); return EINVAL; } return 0; } LOCK(bc.lock); while(num_blocks) { ce = block_lookup(dev, bnum); if (ce) { if (bnum != ce->block_num || dev != ce->dev) { UNLOCK(bc.lock); panic("*** error6: looked up dev %d block %ld but found " "%d %ld\n", dev, bnum, ce->dev, ce->block_num); return EBADF; } if (bsize != ce->bsize) { panic("*** requested bsize %d but ce->bsize %d ce @ 0x%x\n", bsize, ce->bsize, ce); } /* delete this ent from the list it is in because it may change */ if (ce->lock) cel = &bc.locked; else cel = &bc.normal; delete_from_list(cel, ce); if (op & CACHE_READ) { if (data && data != ce->data) { memcpy(data, ce->data, bsize); } else if (dataptr) { *dataptr = ce->data; } else { printf("cbio:data 0x%x dptr 0x%x ce @ 0x%x ce->data 0x%x\n", data, dataptr, ce, ce->data); } } else if (op & CACHE_WRITE) { if (data && data != ce->data) memcpy(ce->data, data, bsize); ce->flags |= CE_DIRTY; } else if (op & CACHE_NOOP) { memset(ce->data, 0, bsize); if (data) memset(data, 0, bsize); if (dataptr) *dataptr = ce->data; ce->flags |= CE_DIRTY; } else { panic("cached_block_io: bogus op %d\n", op); } if (op & CACHE_LOCKED) ce->lock++;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -