?? cache.c
字號:
static voidrelease_iovec_array(struct iovec *iov){ int i; LOCK(iovec_lock); for(i=0; i < MAX_IOVECS; i++) { if (iov == iovec_pool[i]) break; } if (i < MAX_IOVECS) iovec_used[i] = 0; else /* uh-oh */ printf("cache: released an iovec I don't own (iov 0x%x)\n", iov); UNLOCK(iovec_lock);}static voidreal_dump_cache_list(cache_ent_list *cel){ cache_ent *ce; kprintf("starting from LRU end:\n"); for(ce=cel->lru; ce; ce=ce->next) { kprintf("ce 0x%.8lx dev %2d bnum %6ld lock %d flag %d arg 0x%.8lx " "clone 0x%.8lx\n", (ulong)ce, ce->dev, ce->block_num,ce->lock, ce->flags, (ulong)ce->arg, (ulong)ce->clone); } kprintf("MRU end\n");}static voiddump_cache_list(void){ kprintf("NORMAL BLOCKS\n"); real_dump_cache_list(&bc.normal); kprintf("LOCKED BLOCKS\n"); real_dump_cache_list(&bc.locked); kprintf("cur blocks %d, max blocks %d ht @ 0x%lx\n", bc.cur_blocks, bc.max_blocks, (ulong)&bc.ht);}static voidcheck_bcache(char *str){ int count = 0; cache_ent *ce, *prev = NULL; LOCK(bc.lock); for(ce=bc.normal.lru; ce; prev=ce, ce=ce->next) { count++; } for(ce=bc.locked.lru; ce; prev=ce, ce=ce->next) { count++; } if (count != bc.cur_blocks) { if (count < bc.cur_blocks - 16) panic("%s: count == %d, cur_blocks %d, prev 0x%x\n", str, count, bc.cur_blocks, prev); else printf("%s: count == %d, cur_blocks %d, prev 0x%x\n", str, count, bc.cur_blocks, prev); } UNLOCK(bc.lock);}static voiddump_lists(void){ cache_ent *nce; printf("LOCKED 0x%x (tail 0x%x, head 0x%x)\n", &bc.locked, bc.locked.lru, bc.locked.mru); for(nce=bc.locked.lru; nce; nce=nce->next) printf("nce @ 0x%x dev %d bnum %ld flags %d lock %d clone 0x%x func 0x%x\n", nce, nce->dev, nce->block_num, nce->flags, nce->lock, nce->clone, nce->func); printf("NORMAL 0x%x (tail 0x%x, head 0x%x)\n", &bc.normal, bc.normal.lru, bc.normal.mru); for(nce=bc.normal.lru; nce; nce=nce->next) printf("nce @ 0x%x dev %d bnum %ld flags %d lock %d clone 0x%x func 0x%x\n", nce, nce->dev, nce->block_num, nce->flags, nce->lock, nce->clone, nce->func);}static voidcheck_lists(void){ cache_ent *ce, *prev, *oce; cache_ent_list *cel; cel = &bc.normal; for(ce=cel->lru,prev=NULL; ce; prev=ce, ce=ce->next) { for(oce=bc.locked.lru; oce; oce=oce->next) { if (oce == ce) { dump_lists(); panic("1:ce @ 0x%x is in two lists(cel 0x%x &LOCKED)\n",ce,cel); } } } if (prev && prev != cel->mru) { dump_lists(); panic("*** last element in list != cel mru (ce 0x%x, cel 0x%x)\n", prev, cel); } cel = &bc.locked; for(ce=cel->lru,prev=NULL; ce; prev=ce, ce=ce->next) { for(oce=bc.normal.lru; oce; oce=oce->next) { if (oce == ce) { dump_lists(); panic("3:ce @ 0x%x is in two lists(cel 0x%x & DIRTY)\n",ce,cel); } } } if (prev && prev != cel->mru) { dump_lists(); panic("*** last element in list != cel mru (ce 0x%x, cel 0x%x)\n", prev, cel); }}#ifdef DEBUGstatic intdo_dump(int argc, char **argv){ dump_cache_list(); return 1;}static intdo_find_block(int argc, char **argv){ int i; fs_off_t bnum; cache_ent *ce; if (argc < 2) { kprintf("%s: needs a block # argument\n", argv[0]); return 1; } for(i=1; i < argc; i++) { bnum = strtoul(argv[i], NULL, 0); for(ce=bc.normal.lru; ce; ce=ce->next) { if (ce->block_num == bnum) { kprintf("found clean bnum %ld @ 0x%lx (data @ 0x%lx)\n", bnum, ce, ce->data); } } for(ce=bc.locked.lru; ce; ce=ce->next) { if (ce->block_num == bnum) { kprintf("found locked bnum %ld @ 0x%lx (data @ 0x%lx)\n", bnum, ce, ce->data); } } } return 0;}static intdo_find_data(int argc, char **argv){ int i; void *data; cache_ent *ce; if (argc < 2) { kprintf("%s: needs a block # argument\n", argv[0]); return 1; } for(i=1; i < argc; i++) { data = (void *)strtoul(argv[i], NULL, 0); for(ce=bc.normal.lru; ce; ce=ce->next) { if (ce->data == data) { kprintf("found normal data ptr for bnum %ld @ ce 0x%lx\n", ce->block_num, ce); } } for(ce=bc.locked.lru; ce; ce=ce->next) { if (ce->data == data) { kprintf("found locked data ptr for bnum %ld @ ce 0x%lx\n", ce->block_num, ce); } } } return 0;}#endif /* DEBUG *//* this function detaches the cache_ent from the list.*/ static voiddelete_from_list(cache_ent_list *cel, cache_ent *ce){ if (ce->next) ce->next->prev = ce->prev; if (ce->prev) ce->prev->next = ce->next; if (cel->lru == ce) cel->lru = ce->next; if (cel->mru == ce) cel->mru = ce->prev; ce->next = NULL; ce->prev = NULL;}/* this function adds the cache_ent ce to the head of the list (i.e. the MRU end). the cache_ent should *not* be in any lists.*/ static voidadd_to_head(cache_ent_list *cel, cache_ent *ce){if (ce->next != NULL || ce->prev != NULL) { panic("*** ath: ce has non-null next/prev ptr (ce 0x%x nxt 0x%x, prv 0x%x)\n", ce, ce->next, ce->prev);} ce->next = NULL; ce->prev = cel->mru; if (cel->mru) cel->mru->next = ce; cel->mru = ce; if (cel->lru == NULL) cel->lru = ce;}/* this function adds the cache_ent ce to the tail of the list (i.e. the MRU end). the cache_ent should *not* be in any lists.*/ static voidadd_to_tail(cache_ent_list *cel, cache_ent *ce){if (ce->next != NULL || ce->prev != NULL) { panic("*** att: ce has non-null next/prev ptr (ce 0x%x nxt 0x%x, prv 0x%x)\n", ce, ce->next, ce->prev);} ce->next = cel->lru; ce->prev = NULL; if (cel->lru) cel->lru->prev = ce; cel->lru = ce; if (cel->mru == NULL) cel->mru = ce;}static intcache_ent_cmp(const void *a, const void *b){ fs_off_t diff; cache_ent *p1 = *(cache_ent **)a, *p2 = *(cache_ent **)b; if (p1 == NULL || p2 == NULL) panic("cache_ent pointers are null?!? (a 0x%lx, b 0x%lx\n)\n", a, b); if (p1->dev == p2->dev) { diff = p1->block_num - p2->block_num; return (int)diff; } else { return p1->dev - p2->dev; }}static voidcache_flusher(void *arg, int phase){ int i, num_ents, err; bigtime_t now = system_time(); static cache_ent *ce = NULL; static cache_ent *ents[NUM_FLUSH_BLOCKS]; /* if someone else was in the cache recently then just bail out so we don't lock them out unnecessarily */ if ((now - last_cache_access) < 1000000) return; LOCK(bc.lock); ce = bc.normal.lru; for(num_ents=0; ce && num_ents < NUM_FLUSH_BLOCKS; ce=ce->next) { if (ce->flags & CE_BUSY) continue; if ((ce->flags & CE_DIRTY) == 0 && ce->clone == NULL) continue; ents[num_ents] = ce; ents[num_ents]->flags |= CE_BUSY; num_ents++; } /* if we've got some room left over, look for cloned locked blocks */ if (num_ents < NUM_FLUSH_BLOCKS) { ce = bc.locked.lru; for(; num_ents < NUM_FLUSH_BLOCKS;) { for(; ce && ((ce->flags & CE_BUSY) || ce->clone == NULL); ce=ce->next) /* skip ents that meet the above criteria */; if (ce == NULL) break; ents[num_ents] = ce; ents[num_ents]->flags |= CE_BUSY; ce = ce->next; num_ents++; } } UNLOCK(bc.lock); if (num_ents == 0) return; qsort(ents, num_ents, sizeof(cache_ent **), cache_ent_cmp); if ((err = flush_ents(ents, num_ents)) != 0) { printf("flush ents failed (ents @ 0x%lx, num_ents %d!\n", (ulong)ents, num_ents); } for(i=0; i < num_ents; i++) { /* clear the busy bit on each of ent */ ents[i]->flags &= ~CE_BUSY; }}static intflush_cache_ent(cache_ent *ce){ int ret = 0; void *data; /* if true, then there's nothing to flush */ if ((ce->flags & CE_DIRTY) == 0 && ce->clone == NULL) return 0; /* same thing here */ if (ce->clone == NULL && ce->lock != 0) return 0; restart: if (ce->clone) data = ce->clone; else data = ce->data; /* printf("flush: %7d\n", ce->block_num); */ ret = write_phys_blocks(ce->dev, ce->block_num, data, 1, ce->bsize); if (ce->func) { ce->func(ce->logged_bnum, 1, ce->arg); ce->func = NULL; } if (ce->clone) { free(ce->clone); ce->clone = NULL; if (ce->lock == 0 && (ce->flags & CE_DIRTY)) goto restart; /* also write the real data ptr */ } else { ce->flags &= ~CE_DIRTY; } return ret;}static intflush_ents(cache_ent **ents, int n_ents){ int i, j, k, ret = 0, bsize, iocnt, do_again = 0; fs_off_t start_bnum; struct iovec *iov; iov = get_iovec_array(); if (iov == NULL) return ENOMEM;restart: for(i=0; i < n_ents; i++) { /* if true, then there's nothing to flush */ if ((ents[i]->flags & CE_DIRTY) == 0 && ents[i]->clone == NULL) continue; /* if true we can't touch the dirty data yet because it's locked */ if (ents[i]->clone == NULL && ents[i]->lock != 0) continue; bsize = ents[i]->bsize; start_bnum = ents[i]->block_num; for(j=i+1; j < n_ents && (j - i) < NUM_FLUSH_BLOCKS; j++) { if (ents[j]->dev != ents[i]->dev || ents[j]->block_num != start_bnum + (j - i)) break; if (ents[j]->clone == NULL && ents[j]->lock != 0) break; } if (j == i+1) { /* only one block, just flush it directly */ if ((ret = flush_cache_ent(ents[i])) != 0) break; continue; } for(k=i,iocnt=0; k < j; k++,iocnt++) { if (ents[k]->clone) iov[iocnt].iov_base = ents[k]->clone; else iov[iocnt].iov_base = ents[k]->data; iov[iocnt].iov_len = bsize; } /* printf("writev @ %ld for %d blocks", start_bnum, iocnt); */ ret = writev_pos(ents[i]->dev, start_bnum * (fs_off_t)bsize, &iov[0], iocnt); if (ret != iocnt*bsize) { int idx; printf("flush_ents: writev failed: iocnt %d start bnum %ld " "bsize %d, ret %d\n", iocnt, start_bnum, bsize, ret);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -