xfs_attr_leaf.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,154 行 · 第 1/5 页
C
2,154 行
blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); args->index = args->index2 = blk2->index; args->blkno = args->blkno2 = blk2->blkno; } } else { ASSERT(state->inleaf == 1); args->index = args->index2 = blk1->index; args->blkno = args->blkno2 = blk1->blkno; }}/* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. * GROT: Is this really necessary? With other than a 512 byte blocksize, * GROT: there will always be enough room in either block for a new entry. * GROT: Do a double-split for this case? */STATIC intxfs_attr_leaf_figure_balance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, xfs_da_state_blk_t *blk2, int *countarg, int *usedbytesarg){ xfs_attr_leafblock_t *leaf1, *leaf2; xfs_attr_leaf_hdr_t *hdr1, *hdr2; xfs_attr_leaf_entry_t *entry; int count, max, index, totallen, half; int lastdelta, foundit, tmp; /* * Set up environment. */ leaf1 = blk1->bp->data; leaf2 = blk2->bp->data; hdr1 = &leaf1->hdr; hdr2 = &leaf2->hdr; foundit = 0; totallen = 0; /* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. */ max = INT_GET(hdr1->count, ARCH_CONVERT) + INT_GET(hdr2->count, ARCH_CONVERT); half = (max+1) * sizeof(*entry); half += INT_GET(hdr1->usedbytes, ARCH_CONVERT) + INT_GET(hdr2->usedbytes, ARCH_CONVERT) + xfs_attr_leaf_newentsize(state->args, state->blocksize, NULL); half /= 2; lastdelta = state->blocksize; entry = &leaf1->entries[0]; for (count = index = 0; count < max; entry++, index++, count++) {#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A)) /* * The new entry is in the first block, account for it. */ if (count == blk1->index) { tmp = totallen + sizeof(*entry) + xfs_attr_leaf_newentsize(state->args, state->blocksize, NULL); if (XFS_ATTR_ABS(half - tmp) > lastdelta) break; lastdelta = XFS_ATTR_ABS(half - tmp); totallen = tmp; foundit = 1; } /* * Wrap around into the second block if necessary. */ if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { leaf1 = leaf2; entry = &leaf1->entries[0]; index = 0; } /* * Figure out if next leaf entry would be too much. */ tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1, index); if (XFS_ATTR_ABS(half - tmp) > lastdelta) break; lastdelta = XFS_ATTR_ABS(half - tmp); totallen = tmp;#undef XFS_ATTR_ABS } /* * Calculate the number of usedbytes that will end up in lower block. * If new entry not in lower block, fix up the count. */ totallen -= count * sizeof(*entry); if (foundit) { totallen -= sizeof(*entry) + xfs_attr_leaf_newentsize(state->args, state->blocksize, NULL); } *countarg = count; *usedbytesarg = totallen; return(foundit);}/*======================================================================== * Routines used for shrinking the Btree. *========================================================================*//* * Check a leaf block and its neighbors to see if the block should be * collapsed into one or the other neighbor. Always keep the block * with the smaller block number. * If the current block is over 50% full, don't try to join it, return 0. * If the block is empty, fill in the state structure and return 2. * If it can be collapsed, fill in the state structure and return 1. * If nothing can be done, return 0. * * GROT: allow for INCOMPLETE entries in calculation. */intxfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action){ xfs_attr_leafblock_t *leaf; xfs_da_state_blk_t *blk; xfs_da_blkinfo_t *info; int count, bytes, forward, error, retval, i; xfs_dablk_t blkno; xfs_dabuf_t *bp; /* * Check for the degenerate case of the block being over 50% full. * If so, it's not worth even looking to see if we might be able * to coalesce with a sibling. */ blk = &state->path.blk[ state->path.active-1 ]; info = blk->bp->data; ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); leaf = (xfs_attr_leafblock_t *)info; count = INT_GET(leaf->hdr.count, ARCH_CONVERT); bytes = sizeof(xfs_attr_leaf_hdr_t) + count * sizeof(xfs_attr_leaf_entry_t) + INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); if (bytes > (state->blocksize >> 1)) { *action = 0; /* blk over 50%, don't try to join */ return(0); } /* * Check for the degenerate case of the block being empty. * If the block is empty, we'll simply delete it, no need to * coalesce it with a sibling block. We choose (aribtrarily) * to merge with the forward block unless it is NULL. */ if (count == 0) { /* * Make altpath point to the block we want to keep and * path point to the block we want to drop (this one). */ forward = (!INT_ISZERO(info->forw, ARCH_CONVERT)); memcpy(&state->altpath, &state->path, sizeof(state->path)); error = xfs_da_path_shift(state, &state->altpath, forward, 0, &retval); if (error) return(error); if (retval) { *action = 0; } else { *action = 2; } return(0); } /* * Examine each sibling block to see if we can coalesce with * at least 25% free space to spare. We need to figure out * whether to merge with the forward or the backward block. * We prefer coalescing with the lower numbered sibling so as * to shrink an attribute list over time. */ /* start with smaller blk num */ forward = (INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT)); for (i = 0; i < 2; forward = !forward, i++) { if (forward) blkno = INT_GET(info->forw, ARCH_CONVERT); else blkno = INT_GET(info->back, ARCH_CONVERT); if (blkno == 0) continue; error = xfs_da_read_buf(state->args->trans, state->args->dp, blkno, -1, &bp, XFS_ATTR_FORK); if (error) return(error); ASSERT(bp != NULL); leaf = (xfs_attr_leafblock_t *)info; count = INT_GET(leaf->hdr.count, ARCH_CONVERT); bytes = state->blocksize - (state->blocksize>>2); bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); leaf = bp->data; ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); count += INT_GET(leaf->hdr.count, ARCH_CONVERT); bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); bytes -= count * sizeof(xfs_attr_leaf_entry_t); bytes -= sizeof(xfs_attr_leaf_hdr_t); xfs_da_brelse(state->args->trans, bp); if (bytes >= 0) break; /* fits with at least 25% to spare */ } if (i >= 2) { *action = 0; return(0); } /* * Make altpath point to the block we want to keep (the lower * numbered block) and path point to the block we want to drop. */ memcpy(&state->altpath, &state->path, sizeof(state->path)); if (blkno < blk->blkno) { error = xfs_da_path_shift(state, &state->altpath, forward, 0, &retval); } else { error = xfs_da_path_shift(state, &state->path, forward, 0, &retval); } if (error) return(error); if (retval) { *action = 0; } else { *action = 1; } return(0);}/* * Remove a name from the leaf attribute list structure. * * Return 1 if leaf is less than 37% full, 0 if >= 37% full. * If two leaves are 37% full, when combined they will leave 25% free. */intxfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args){ xfs_attr_leafblock_t *leaf; xfs_attr_leaf_hdr_t *hdr; xfs_attr_leaf_map_t *map; xfs_attr_leaf_entry_t *entry; int before, after, smallest, entsize; int tablesize, tmp, i; xfs_mount_t *mp; leaf = bp->data; ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); hdr = &leaf->hdr; mp = args->trans->t_mountp; ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); ASSERT((args->index >= 0) && (args->index < INT_GET(hdr->count, ARCH_CONVERT))); ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT) * sizeof(*entry))+sizeof(*hdr))); entry = &leaf->entries[args->index]; ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); /* * Scan through free region table: * check for adjacency of free'd entry with an existing one, * find smallest free region in case we need to replace it, * adjust any map that borders the entry table, */ tablesize = INT_GET(hdr->count, ARCH_CONVERT) * sizeof(xfs_attr_leaf_entry_t) + sizeof(xfs_attr_leaf_hdr_t); map = &hdr->freemap[0]; tmp = INT_GET(map->size, ARCH_CONVERT); before = after = -1; smallest = XFS_ATTR_LEAF_MAPSIZE - 1; entsize = xfs_attr_leaf_entsize(leaf, args->index); for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { INT_MOD(map->base, ARCH_CONVERT, -sizeof(xfs_attr_leaf_entry_t)); INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_attr_leaf_entry_t)); } if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == INT_GET(entry->nameidx, ARCH_CONVERT)) { before = i; } else if (INT_GET(map->base, ARCH_CONVERT) == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) { after = i; } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { tmp = INT_GET(map->size, ARCH_CONVERT); smallest = i; } } /* * Coalesce adjacent freemap regions, * or replace the smallest region. */ if ((before >= 0) || (after >= 0)) { if ((before >= 0) && (after >= 0)) { map = &hdr->freemap[before]; INT_MOD(map->size, ARCH_CONVERT, entsize); INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT)); INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT); INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT); } else if (before >= 0) { map = &hdr->freemap[before]; INT_MOD(map->size, ARCH_CONVERT, entsize); } else { map = &hdr->freemap[after]; /* both on-disk, don't endian flip twice */ map->base = entry->nameidx; INT_MOD(map->size, ARCH_CONVERT, entsize); } } else { /* * Replace smallest region (if it is smaller than free'd entry) */ map = &hdr->freemap[smallest]; if (INT_GET(map->size, ARCH_CONVERT) < entsize) { INT_SET(map->base, ARCH_CONVERT, INT_GET(entry->nameidx, ARCH_CONVERT)); INT_SET(map->size, ARCH_CONVERT, entsize); } } /* * Did we remove the first entry? */ if (INT_GET(entry->nameidx, ARCH_CONVERT) == INT_GET(hdr->firstused, ARCH_CONVERT)) smallest = 1; else smallest = 0; /* * Compress the remaining entries and zero out the removed stuff. */ memset(XFS_ATTR_LEAF_NAME(leaf, args->index), 0, entsize); INT_MOD(hdr->usedbytes, ARCH_CONVERT, -entsize); xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), entsize)); tmp = (INT_GET(hdr->count, ARCH_CONVERT) - args->index) * sizeof(xfs_attr_leaf_entry_t); memmove((char *)entry, (char *)(entry+1), tmp); INT_MOD(hdr->count, ARCH_CONVERT, -1); xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)]; memset((char *)entry, 0, sizeof(xfs_attr_leaf_entry_t)); /* * If we removed the first entry, re-find the first used byte * in the name area. Note that if the entry was the "firstused", * then we don't have a "hole" in our block resulting from * removing the name. */ if (smallest) { tmp = XFS_LBSIZE(mp); entry = &leaf->entries[0]; for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp) tmp = INT_GET(entry->nameidx, ARCH_CONVERT); } INT_SET(hdr->firstused, ARCH_CONVERT, tmp); if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) { INT_SET(hdr->firstused, ARCH_CONVERT, tmp - XFS_ATTR_LEAF_NAME_ALIGN); } } else { hdr->holes = 1; /* mark as needing compaction */ } xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); /* * Check if leaf is less than 50% full, caller may want to * "join" the leaf with a sibling if so. */ tmp = sizeof(xfs_attr_leaf_hdr_t); tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * sizeof(xfs_attr_leaf_entry_t); tmp += INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); return(tmp < mp->m_attr_magicpct); /* leaf is < 37% full */}/* * Move all the attribute list entries from drop_leaf into save_leaf. */voidxfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, xfs_da_state_blk_t *save_blk){ xfs_attr_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; xfs_attr_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; xfs_mount_t *mp; char *tmpbuffer; /* * Set up environment. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?