📄 jfs_dtree.c
字号:
* dtDeleteUp() * * function: * free empty pages as propagating deletion up the tree * * parameter: * * return: */static int dtDeleteUp(tid_t tid, struct inode *ip, struct metapage * fmp, dtpage_t * fp, struct btstack * btstack){ int rc = 0; struct metapage *mp; dtpage_t *p; int index, nextindex; int xlen; struct btframe *parent; struct dt_lock *dtlck; struct tlock *tlck; struct lv *lv; struct pxd_lock *pxdlock; int i; /* * keep the root leaf page which has become empty */ if (BT_IS_ROOT(fmp)) { /* * reset the root * * dtInitRoot() acquires txlock on the root */ dtInitRoot(tid, ip, PARENT(ip)); DT_PUTPAGE(fmp); return 0; } /* * free the non-root leaf page */ /* * acquire a transaction lock on the page * * write FREEXTENT|NOREDOPAGE log record * N.B. linelock is overlaid as freed extent descriptor, and * the buffer page is freed; */ tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE); pxdlock = (struct pxd_lock *) & tlck->lock; pxdlock->flag = mlckFREEPXD; pxdlock->pxd = fp->header.self; pxdlock->index = 1; /* update sibling pointers */ if ((rc = dtRelink(tid, ip, fp))) { BT_PUTPAGE(fmp); return rc; } xlen = lengthPXD(&fp->header.self); ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen); /* free/invalidate its buffer page */ discard_metapage(fmp); /* * propagate page deletion up the directory tree * * If the delete from the parent page makes it empty, * continue all the way up the tree. * stop if the root page is reached (which is never deleted) or * if the entry deletion does not empty the page. */ while ((parent = BT_POP(btstack)) != NULL) { /* pin the parent page <sp> */ DT_GETPAGE(ip, parent->bn, mp, PSIZE, p, rc); if (rc) return rc; /* * free the extent of the child page deleted */ index = parent->index; /* * delete the entry for the child page from parent */ nextindex = p->header.nextindex; /* * the parent has the single entry being deleted: * * free the parent page which has become empty. */ if (nextindex == 1) { /* * keep the root internal page which has become empty */ if (p->header.flag & BT_ROOT) { /* * reset the root * * dtInitRoot() acquires txlock on the root */ dtInitRoot(tid, ip, PARENT(ip)); DT_PUTPAGE(mp); return 0; } /* * free the parent page */ else { /* * acquire a transaction lock on the page * * write FREEXTENT|NOREDOPAGE log record */ tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE); pxdlock = (struct pxd_lock *) & tlck->lock; pxdlock->flag = mlckFREEPXD; pxdlock->pxd = p->header.self; pxdlock->index = 1; /* update sibling pointers */ if ((rc = dtRelink(tid, ip, p))) { DT_PUTPAGE(mp); return rc; } xlen = lengthPXD(&p->header.self); ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen); /* free/invalidate its buffer page */ discard_metapage(mp); /* propagate up */ continue; } } /* * the parent has other entries remaining: * * delete the router entry from the parent page. */ BT_MARK_DIRTY(mp, ip); /* * acquire a transaction lock on the page * * action: router entry deletion */ tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY); dtlck = (struct dt_lock *) & tlck->lock; /* linelock header */ if (dtlck->index >= dtlck->maxcnt) dtlck = (struct dt_lock *) txLinelock(dtlck); lv = & dtlck->lv[dtlck->index]; lv->offset = 0; lv->length = 1; dtlck->index++; /* linelock stbl of non-root leaf page */ if (!(p->header.flag & BT_ROOT)) { if (dtlck->index < dtlck->maxcnt) lv++; else { dtlck = (struct dt_lock *) txLinelock(dtlck); lv = & dtlck->lv[0]; } i = index >> L2DTSLOTSIZE; lv->offset = p->header.stblindex + i; lv->length = ((p->header.nextindex - 1) >> L2DTSLOTSIZE) - i + 1; dtlck->index++; } /* free the router entry */ dtDeleteEntry(p, index, &dtlck); /* reset key of new leftmost entry of level (for consistency) */ if (index == 0 && ((p->header.flag & BT_ROOT) || p->header.prev == 0)) dtTruncateEntry(p, 0, &dtlck); /* unpin the parent page */ DT_PUTPAGE(mp); /* exit propagation up */ break; } return 0;}#ifdef _NOTYET/* * NAME: dtRelocate() * * FUNCTION: relocate dtpage (internal or leaf) of directory; * This function is mainly used by defragfs utility. */int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd, s64 nxaddr){ int rc = 0; struct metapage *mp, *pmp, *lmp, *rmp; dtpage_t *p, *pp, *rp = 0, *lp= 0; s64 bn; int index; struct btstack btstack; pxd_t *pxd; s64 oxaddr, nextbn, prevbn; int xlen, xsize; struct tlock *tlck; struct dt_lock *dtlck; struct pxd_lock *pxdlock; s8 *stbl; struct lv *lv; oxaddr = addressPXD(opxd); xlen = lengthPXD(opxd); jfs_info("dtRelocate: lmxaddr:%Ld xaddr:%Ld:%Ld xlen:%d", (long long)lmxaddr, (long long)oxaddr, (long long)nxaddr, xlen); /* * 1. get the internal parent dtpage covering * router entry for the tartget page to be relocated; */ rc = dtSearchNode(ip, lmxaddr, opxd, &btstack); if (rc) return rc; /* retrieve search result */ DT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); jfs_info("dtRelocate: parent router entry validated."); /* * 2. relocate the target dtpage */ /* read in the target page from src extent */ DT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc); if (rc) { /* release the pinned parent page */ DT_PUTPAGE(pmp); return rc; } /* * read in sibling pages if any to update sibling pointers; */ rmp = NULL; if (p->header.next) { nextbn = le64_to_cpu(p->header.next); DT_GETPAGE(ip, nextbn, rmp, PSIZE, rp, rc); if (rc) { DT_PUTPAGE(mp); DT_PUTPAGE(pmp); return (rc); } } lmp = NULL; if (p->header.prev) { prevbn = le64_to_cpu(p->header.prev); DT_GETPAGE(ip, prevbn, lmp, PSIZE, lp, rc); if (rc) { DT_PUTPAGE(mp); DT_PUTPAGE(pmp); if (rmp) DT_PUTPAGE(rmp); return (rc); } } /* at this point, all xtpages to be updated are in memory */ /* * update sibling pointers of sibling dtpages if any; */ if (lmp) { tlck = txLock(tid, ip, lmp, tlckDTREE | tlckRELINK); dtlck = (struct dt_lock *) & tlck->lock; /* linelock header */ ASSERT(dtlck->index == 0); lv = & dtlck->lv[0]; lv->offset = 0; lv->length = 1; dtlck->index++; lp->header.next = cpu_to_le64(nxaddr); DT_PUTPAGE(lmp); } if (rmp) { tlck = txLock(tid, ip, rmp, tlckDTREE | tlckRELINK); dtlck = (struct dt_lock *) & tlck->lock; /* linelock header */ ASSERT(dtlck->index == 0); lv = & dtlck->lv[0]; lv->offset = 0; lv->length = 1; dtlck->index++; rp->header.prev = cpu_to_le64(nxaddr); DT_PUTPAGE(rmp); } /* * update the target dtpage to be relocated * * write LOG_REDOPAGE of LOG_NEW type for dst page * for the whole target page (logredo() will apply * after image and update bmap for allocation of the * dst extent), and update bmap for allocation of * the dst extent; */ tlck = txLock(tid, ip, mp, tlckDTREE | tlckNEW); dtlck = (struct dt_lock *) & tlck->lock; /* linelock header */ ASSERT(dtlck->index == 0); lv = & dtlck->lv[0]; /* update the self address in the dtpage header */ pxd = &p->header.self; PXDaddress(pxd, nxaddr); /* the dst page is the same as the src page, i.e., * linelock for afterimage of the whole page; */ lv->offset = 0; lv->length = p->header.maxslot; dtlck->index++; /* update the buffer extent descriptor of the dtpage */ xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize;#ifdef _STILL_TO_PORT bmSetXD(mp, nxaddr, xsize);#endif /* _STILL_TO_PORT */ /* unpin the relocated page */ DT_PUTPAGE(mp); jfs_info("dtRelocate: target dtpage relocated."); /* the moved extent is dtpage, then a LOG_NOREDOPAGE log rec * needs to be written (in logredo(), the LOG_NOREDOPAGE log rec * will also force a bmap update ). */ /* * 3. acquire maplock for the source extent to be freed; */ /* for dtpage relocation, write a LOG_NOREDOPAGE record * for the source dtpage (logredo() will init NoRedoPage * filter and will also update bmap for free of the source * dtpage), and upadte bmap for free of the source dtpage; */ tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE); pxdlock = (struct pxd_lock *) & tlck->lock; pxdlock->flag = mlckFREEPXD; PXDaddress(&pxdlock->pxd, oxaddr); PXDlength(&pxdlock->pxd, xlen); pxdlock->index = 1; /* * 4. update the parent router entry for relocation; * * acquire tlck for the parent entry covering the target dtpage; * write LOG_REDOPAGE to apply after image only; */ jfs_info("dtRelocate: update parent router entry."); tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY); dtlck = (struct dt_lock *) & tlck->lock; lv = & dtlck->lv[dtlck->index]; /* update the PXD with the new address */ stbl = DT_GETSTBL(pp); pxd = (pxd_t *) & pp->slot[stbl[index]]; PXDaddress(pxd, nxaddr); lv->offset = stbl[index]; lv->length = 1; dtlck->index++; /* unpin the parent dtpage */ DT_PUTPAGE(pmp); return rc;}/* * NAME: dtSearchNode() * * FUNCTION: Search for an dtpage containing a specified address * This function is mainly used by defragfs utility. * * NOTE: Search result on stack, the found page is pinned at exit. * The result page must be an internal dtpage. * lmxaddr give the address of the left most page of the * dtree level, in which the required dtpage resides. */static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd, struct btstack * btstack){ int rc = 0; s64 bn; struct metapage *mp; dtpage_t *p; int psize = 288; /* initial in-line directory */ s8 *stbl; int i; pxd_t *pxd; struct btframe *btsp; BT_CLR(btstack); /* reset stack */ /* * descend tree to the level with specified leftmost page * * by convention, root bn = 0. */ for (bn = 0;;) { /* get/pin the page to search */ DT_GETPAGE(ip, bn, mp, psize, p, rc); if (rc) return rc; /* does the xaddr of leftmost page of the levevl * matches levevl search key ? */ if (p->header.flag & BT_ROOT) { if (lmxaddr == 0) break; } else if (addressPXD(&p->header.self) == lmxaddr) break; /* * descend down to leftmost child page */ if (p->header.flag & BT_LEAF) { DT_PUTPAGE(mp); return -ESTALE; } /* get the leftmost entry */ stbl = DT_GETSTBL(p); pxd = (pxd_t *) & p->slot[stbl[0]]; /* get the child page block address */ bn = addressPXD(pxd); psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize; /* unpin the parent page */ DT_PUTPAGE(mp); } /* * search each page at the current levevl */ loop: stbl = DT_GETSTBL(p); for (i = 0; i < p->header.nextindex; i++) { pxd = (pxd_t *) & p->slot[stbl[i]]; /* found the specified router entry */ if (addressPXD(pxd) == addressPXD(kpxd) && lengthPXD(pxd) == lengthPXD(kpxd)) { btsp = btstack->top; btsp->bn = bn; btsp->index = i; btsp->mp = mp; return 0; } } /* get the right sibling page if any */ if (p->header.next) bn = le64_to_cpu(p->header.next); else { DT_PUTPAGE(mp); return -ESTALE; } /* unpin current page */ DT_PUTPAGE(mp); /* get the right sibling page */ DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); if (rc) return rc; goto loop;}#endif /* _NOTYET *//* * dtRelink() * * function: * link around a freed page. * * parameter: * fp: page to be freed * * return: */static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p){ int rc; struct metapage *mp; s64 nextbn, prevbn; struct tlock *tlck; struct dt_lock *dtlck; struct lv *lv; nextbn = le64_to_cpu(p->header.next); prevbn = le64_to_cpu(p->header.prev); /* update prev pointer of the next page */ if (nextbn != 0) { DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc); if (rc) return rc; BT_MARK_DIRTY(mp, ip); /* * acquire a transaction lock on the next page * * action: update prev pointer; */ tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK); jfs_info("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p", tlck, ip, mp); dtlck = (struct dt_lock *) & tlck->lock; /* linelock header */ if (dtlck->index >= dtlck->maxcnt) dtlck = (struct dt_lock *) txLinelock(dtlck); lv = & dtlck->lv[dtlck->index]; lv->offset = 0; lv->length = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -