📄 log_work.c
字号:
* * **note: (see reference in LOG_FREEPXDLIST above) * * Each extent of a file MUST be an even multiple of 4096 byte * pages, except the last extent, which need only be an even * multiple of filesystem blocks. This means that, if the last * extent is not a whole page, then it must be extended to a * whole page before another extent can be added. If the * filesystem blocks immediately following the current last * extent are not available, then it is necessary to select * a larger storage area and copy the contents of the current * last extent and the new data (the reason the file is being * extended in the first place) into it. * * To illustrate: * suppose the filesystem block size is 1024 and a particular * files is 9216 bytes long, stored as * 1 extent 8 fs blocks (8192 bytes = 2 * 4096) and * 1 extent 1 fs block (1024 bytes) * now suppose another 5120 bytes are appended to the file. * The 2nd extent must be extended because it must either * become an even multiple of 4096 or it must remain the last * extent in the file. * Both: * 1 extent 8 fs blocks (8192 bytes) * 1 extent 6 fs blocks (6144 bytes) * and: * 1 extent 8 fs blocks (8192 bytes) * 1 extent 4 fs blocks (4096 bytes) * 1 extent 2 fs blocks (2048 bytes) * are possible and correct outcomes. * * * NOTE: Since UPDATEMAP log records only affect the block map, * the noredofile hash chain is not checked and the transaction * should not be skipped. * * When a file system object is deleted, UPDATEMAP log records * are created (as appropriate) to release storage from (and * possibly for) metadata xtree pages. No NoRedoPage log records * are written for these pages. * */int doUpdateMap(struct lrd *ld){ /* pointer to log record descriptor */ int i, vol, rc = 0; xad_t *l_xad; pxd_t *l_pxd; pxd_t pxd1; /* * If it's not part of a committed transaction then it * should be ignored, so just return. */ if (!findCommit(ld->logtid)) return (0); /* * if it's the last entry for the current committed transaction, * remove the commit record from the commit list because we won't * be needing it any more. */ if (ld->backchain == 0) deleteCommit(ld->logtid); /* * if the filesystem was cleanly unmounted or if the last * thing that happened was a logredo failure, skip this * record. (Necessary for the case of logredo a log shared * by multiple filesystems. We want to process log records * for those filesystems which don't meet this criteria, but * skip log records for those which do.) */ vol = ld->aggregate; if (vopen[vol].status == FM_CLEAN || vopen[vol].status == FM_LOGREDO) return (0); if (ld->log.updatemap.type & LOG_FREEXADLIST) { /* * The data area contains an array of XAD's, with * updatemap.nxd elements. */ l_xad = (xad_t *) afterdata; for (i = 0; i < ld->log.updatemap.nxd; i++) { PXDaddress(&pxd1, addressXAD(l_xad)); PXDlength(&pxd1, lengthXAD(l_xad)); rc = markBmap((struct dmap *) vopen[vol].bmap_ctl, pxd1, 0, vol); if (rc != 0) { return (rc); } l_xad += 1; } } else if (ld->log.updatemap.type & LOG_FREEPXDLIST) { /* * The data area contains an array of PXD's, with * updatemap.nxd elements. */ l_pxd = (pxd_t *) afterdata; for (i = 0; i < ld->log.updatemap.nxd; i++, l_pxd++) rc = markBmap((struct dmap *) vopen[vol].bmap_ctl, *l_pxd, 0, vol); if (rc != 0) { return (rc); } } else if (ld->log.updatemap.type & LOG_FREEPXD) { /* * The updatemap.nxd should be 1 in this case. */ if (ld->log.updatemap.nxd > 1) fsError(LOGRCERR, vol, ld->log.updatemap.nxd); rc = markBmap((struct dmap *) vopen[vol].bmap_ctl, ld->log.updatemap.pxd, 0, vol); if (rc != 0) { return (rc); } } else if (ld->log.updatemap.type & LOG_ALLOCPXD) { /* * The updatemap.nxd should be 1 in this case. */ if (ld->log.updatemap.nxd > 1) fsError(LOGRCERR, vol, ld->log.updatemap.nxd); rc = markBmap((struct dmap *) vopen[vol].bmap_ctl, ld->log.updatemap.pxd, 1, vol); if (rc != 0) { return (rc); } } else fsck_send_msg(lrdo_DUMPUNKNOWNTYPE); return (0);}/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * NAME: dtpg_resetFreeList(ld) * * FUNCTION: Reset the freelist in the given Directory Btree (nonroot) * node. * * NOTE: none * */int dtpg_resetFreeList(int32_t vol, int *buf){ /* buf contains on-disk page image */ int16_t pxd_len; int16_t nslots; /* number of slots in log.redopage.pxd */ dtpage_t *dtpg; int16_t stbl_nslots; /* number of slots occupied by * the stbl for the page */ int8_t slot_map[DTPAGEMAXSLOT]; int8_t *slot_table; int16_t sidx, slot_idx = 0; struct dtslot *this_slot; struct dtslot *last_slot = 0; struct idtentry *intern_hdr_slot; struct ldtentry *leaf_hdr_slot; dtpg = (dtpage_t *) buf; if (dtpg->header.nextindex == -1) { /* * the stbl is full, no slots * can be available */ dtpg->header.freecnt = 0; dtpg->header.freelist = -1; return 0; } /* the stbl isn't full. slots may be free. */ /* * The dtree page size is 512, 1024, 2048, or 4096 bytes. * We need to know how many slots it contains and how many * slots are occupied by its slot table (stbl). */ pxd_len = (lengthPXD(&dtpg->header.self)) << vopen[vol].l2bsize; switch (pxd_len) { case DT8THPGNODEBYTES: /* 512 bytes */ nslots = DT8THPGNODESLOTS; stbl_nslots = DT8THPGNODETSLOTS; break; case DTQTRPGNODEBYTES: /* 1024 bytes */ nslots = DTQTRPGNODESLOTS; stbl_nslots = DTQTRPGNODETSLOTS; break; case DTHALFPGNODEBYTES: /* 2048 bytes */ nslots = DTHALFPGNODESLOTS; stbl_nslots = DTHALFPGNODETSLOTS; break; default: /* 4096 bytes */ nslots = DTFULLPGNODESLOTS; stbl_nslots = DTFULLPGNODETSLOTS; break; } /* end switch */ /* * clear the slot map */ for (sidx = 0; sidx < nslots; sidx++) { slot_map[sidx] = 0; } /* * account for the header and for the stbl slots */ slot_map[0] = -1; /* the header */ for (sidx = 0; sidx < stbl_nslots; sidx++) { slot_map[dtpg->header.stblindex + sidx] = -1; } /* end for */ slot_table = (int8_t *) & (dtpg->slot[dtpg->header.stblindex]); /* * figure out which slots are in use */ for (sidx = 0; sidx < dtpg->header.nextindex; sidx++) { /* * the dir entry header slot */ /* * If the index is out of bounds or if we've * already seen it in use then something is * seriously wrong and we need a full fsck. * Since the problem could have been caused * by something in this logredo session, * signal fsck to reformat the log. */ if ((slot_table[sidx] >= nslots) || (slot_map[slot_table[sidx]] != 0)) { fsck_send_msg(lrdo_DPRFBADSTBLENTRY, (long long) (addressPXD(&dtpg->header.self))); return (DTPAGE_BADSTBLENTRY1); } /* endif */ slot_map[slot_table[sidx]] = -1; /* * any continuation slots for the dir entry */ if ((dtpg->header.flag & BT_LEAF) == BT_LEAF) { leaf_hdr_slot = (struct ldtentry *) &(dtpg->slot[slot_table[sidx]]); slot_idx = leaf_hdr_slot->next; } else { /* internal page */ intern_hdr_slot = (struct idtentry *) &(dtpg->slot[slot_table[sidx]]); slot_idx = intern_hdr_slot->next; } /* end else internal page */ while (slot_idx != -1) { /* * if the index is out of bounds or * if we've already seen it in use then * something is seriously wrong and we * need a full fsck. * Since the problem could have been caused * by something in this logredo session, * signal fsck to reformat the log. */ if ((slot_idx >= nslots) || (slot_map[slot_idx] != 0)) { fsck_send_msg(lrdo_DPRFBADSLOTNXTIDX, (long long) (addressPXD(&dtpg->header.self))); return (DTPAGE_BADSLOTNEXTIDX1); } /* endif */ slot_map[slot_idx] = -1; this_slot = &(dtpg->slot[slot_idx]); slot_idx = this_slot->next; } /* end while slot_idx */ } /* end for sidx */ /* * find the first available slot */ dtpg->header.freecnt = 0; /* assume none free */ dtpg->header.freelist = -1; /* assume none free */ for (sidx = 0; ((sidx < nslots) && (dtpg->header.freecnt == 0)); sidx++) { if (slot_map[sidx] == 0) { dtpg->header.freecnt = 1; dtpg->header.freelist = sidx; slot_idx = sidx; last_slot = &(dtpg->slot[sidx]); } /* end if */ } /* end for */ /* * count and chain together all available slots */ if (dtpg->header.freecnt != 0) { /* found a free one */ for (sidx = (slot_idx + 1); sidx < nslots; sidx++) { if (slot_map[sidx] == 0) { last_slot->next = sidx; dtpg->header.freecnt += 1; last_slot = &(dtpg->slot[sidx]); } /* end if */ } /* end for */ last_slot->next = -1; /* terminate the chain */ } /* end found a free one */ return (0);}/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * NAME: dtrt_resetFreeList(ld) * * FUNCTION: Reset the freelist in the given Directory inode Btree root. * * NOTE: none */int dtrt_resetFreeList(int32_t vol, struct doblk *db, struct lrd *ld, caddr_t buf_btroot){ dtroot_t *dtrt; int8_t slot_map[DTROOTMAXSLOT]; int16_t sidx, slot_idx = 0; struct dtslot *this_slot; struct dtslot *last_slot = 0; struct idtentry *intern_hdr_slot; struct ldtentry *leaf_hdr_slot; /* * The doblk.i_dtroot (or doblk.dtpage_word) tracks which slots * slots have been updated, but since some of those updates may * be deletions, we can't use it to create the freelist. */ dtrt = (dtroot_t *) buf_btroot; if (dtrt->header.nextindex == -1) { /* * the stbl is full, no slots * can be available */ dtrt->header.freecnt = 0; dtrt->header.freelist = -1; return 0; } /* the stbl isn't full. slots may be free. */ /* * clear the slot map */ for (sidx = 0; sidx < DTROOTMAXSLOT; sidx++) { slot_map[sidx] = 0; } slot_map[0] = -1; /* the header occupies this space */ /* * figure out which slots are in use */ for (sidx = 0; sidx < dtrt->header.nextindex; sidx++) { /* * the dir entry header slot */ /* * If the index is out of bounds or if we've * already seen it in use then something is * seriously wrong and we need a full fsck. * Since the problem could have been caused * by something in this logredo session, * signal fsck to reformat the log. */ if ((dtrt->header.stbl[sidx] >= DTROOTMAXSLOT) || (slot_map[dtrt->header.stbl[sidx]] != 0)) { fsck_send_msg(lrdo_DRRFBADSTBLENTRY); return (DTPAGE_BADSTBLENTRY2); } /* endif */ slot_map[dtrt->header.stbl[sidx]] = -1; /* * any continuation slots for the dir entry */ if ((dtrt->header.flag & BT_LEAF) == BT_LEAF) { leaf_hdr_slot = (struct ldtentry *) &(dtrt->slot[dtrt->header.stbl[sidx]]); slot_idx = leaf_hdr_slot->next; } else { /* internal page */ intern_hdr_slot = (struct idtentry *) &(dtrt->slot[dtrt->header.stbl[sidx]]); slot_idx = intern_hdr_slot->next; } /* end else internal page */ while (slot_idx != -1) { /* * if the index is out of bounds or if we've * already seen it in use then something is * seriously wrong and we need a full fsck. * * Since the problem could have been caused by * something in this logredo session, signal * fsck to reformat the log. */ if ((slot_idx >= DTROOTMAXSLOT) || (slot_map[slot_idx] != 0)) { fsck_send_msg(lrdo_DRRFBADSLOTNXTIDX); return (DTPAGE_BADSLOTNEXTIDX2); } /* endif */ slot_map[slot_idx] = -1; this_slot = &(dtrt->slot[slot_idx]); slot_idx = this_slot->next; } /* end while slot_idx */ } /* end for sidx */ /* * find the first available slot */ dtrt->header.freecnt = 0; /* assume none free */ dtrt->header.freelist = -1; /* assume none free */ for (sidx = 0; ((sidx < DTROOTMAXSLOT) && (dtrt->header.freecnt == 0)); sidx++) { if (slot_map[sidx] == 0) { dtrt->header.freecnt = 1; dtrt->header.freelist = sidx; slot_idx = sidx; last_slot = &(dtrt->slot[sidx]); } } /* * count and chain together all available slots */ if (dtrt->header.freecnt != 0) { /* found a free one */ for (sidx = (slot_idx + 1); sidx < DTROOTMAXSLOT; sidx++) { if (slot_map[sidx] == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -