xfs_attr_leaf.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,154 行 · 第 1/5 页
C
2,154 行
oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL); newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL); return(error);}/* * Add a name to the leaf attribute list structure. */intxfs_attr_leaf_add(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; int tablesize, entsize, sum, tmp, i; leaf = bp->data; ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); ASSERT((args->index >= 0) && (args->index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); hdr = &leaf->hdr; entsize = xfs_attr_leaf_newentsize(args, args->trans->t_mountp->m_sb.sb_blocksize, NULL); /* * Search through freemap for first-fit on new name length. * (may need to figure in size of entry struct too) */ tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) * sizeof(xfs_attr_leaf_entry_t) + sizeof(xfs_attr_leaf_hdr_t); map = &hdr->freemap[XFS_ATTR_LEAF_MAPSIZE-1]; for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { sum += INT_GET(map->size, ARCH_CONVERT); continue; } if (INT_ISZERO(map->size, ARCH_CONVERT)) continue; /* no space in this map */ tmp = entsize; if (INT_GET(map->base, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) tmp += sizeof(xfs_attr_leaf_entry_t); if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { tmp = xfs_attr_leaf_add_work(bp, args, i); return(tmp); } sum += INT_GET(map->size, ARCH_CONVERT); } /* * If there are no holes in the address space of the block, * and we don't have enough freespace, then compaction will do us * no good and we should just give up. */ if (!hdr->holes && (sum < entsize)) return(XFS_ERROR(ENOSPC)); /* * Compact the entries to coalesce free space. * This may change the hdr->count via dropping INCOMPLETE entries. */ xfs_attr_leaf_compact(args->trans, bp); /* * After compaction, the block is guaranteed to have only one * free region, in freemap[0]. If it is not big enough, give up. */ if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) < (entsize + sizeof(xfs_attr_leaf_entry_t))) return(XFS_ERROR(ENOSPC)); return(xfs_attr_leaf_add_work(bp, args, 0));}/* * Add a name to a leaf attribute list structure. */STATIC intxfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex){ xfs_attr_leafblock_t *leaf; xfs_attr_leaf_hdr_t *hdr; xfs_attr_leaf_entry_t *entry; xfs_attr_leaf_name_local_t *name_loc; xfs_attr_leaf_name_remote_t *name_rmt; xfs_attr_leaf_map_t *map; xfs_mount_t *mp; int tmp, i; leaf = bp->data; ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); hdr = &leaf->hdr; ASSERT((mapindex >= 0) && (mapindex < XFS_ATTR_LEAF_MAPSIZE)); ASSERT((args->index >= 0) && (args->index <= INT_GET(hdr->count, ARCH_CONVERT))); /* * Force open some space in the entry array and fill it in. */ entry = &leaf->entries[args->index]; if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) { tmp = INT_GET(hdr->count, ARCH_CONVERT) - args->index; tmp *= sizeof(xfs_attr_leaf_entry_t); memmove((char *)(entry+1), (char *)entry, tmp); xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); } INT_MOD(hdr->count, ARCH_CONVERT, 1); /* * Allocate space for the new string (at the end of the run). */ map = &hdr->freemap[mapindex]; mp = args->trans->t_mountp; ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); ASSERT((INT_GET(map->base, ARCH_CONVERT) & 0x3) == 0); ASSERT(INT_GET(map->size, ARCH_CONVERT) >= xfs_attr_leaf_newentsize(args, mp->m_sb.sb_blocksize, NULL)); ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); ASSERT((INT_GET(map->size, ARCH_CONVERT) & 0x3) == 0); INT_MOD(map->size, ARCH_CONVERT, -xfs_attr_leaf_newentsize(args, mp->m_sb.sb_blocksize, &tmp)); INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)); INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); entry->flags = tmp ? XFS_ATTR_LOCAL : 0; entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE : ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0); if (args->rename) { entry->flags |= XFS_ATTR_INCOMPLETE; if ((args->blkno2 == args->blkno) && (args->index2 <= args->index)) { args->index2++; } } xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); ASSERT((args->index == 0) || (INT_GET(entry->hashval, ARCH_CONVERT) >= INT_GET((entry-1)->hashval, ARCH_CONVERT))); ASSERT((args->index == INT_GET(hdr->count, ARCH_CONVERT)-1) || (INT_GET(entry->hashval, ARCH_CONVERT) <= (INT_GET((entry+1)->hashval, ARCH_CONVERT)))); /* * Copy the attribute name and value into the new space. * * For "remote" attribute values, simply note that we need to * allocate space for the "remote" value. We can't actually * allocate the extents in this transaction, and we can't decide * which blocks they should be as we might allocate more blocks * as part of this transaction (a split operation for example). */ if (entry->flags & XFS_ATTR_LOCAL) { name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); name_loc->namelen = args->namelen; INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen); memcpy((char *)name_loc->nameval, args->name, args->namelen); memcpy((char *)&name_loc->nameval[args->namelen], args->value, INT_GET(name_loc->valuelen, ARCH_CONVERT)); } else { name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); name_rmt->namelen = args->namelen; memcpy((char *)name_rmt->name, args->name, args->namelen); entry->flags |= XFS_ATTR_INCOMPLETE; /* just in case */ INT_ZERO(name_rmt->valuelen, ARCH_CONVERT); INT_ZERO(name_rmt->valueblk, ARCH_CONVERT); args->rmtblkno = 1; args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen); } xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), xfs_attr_leaf_entsize(leaf, args->index))); /* * Update the control info for this leaf node */ if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) { /* both on-disk, don't endian-flip twice */ hdr->firstused = entry->nameidx; } ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT) * sizeof(*entry))+sizeof(*hdr))); tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) * sizeof(xfs_attr_leaf_entry_t) + sizeof(xfs_attr_leaf_hdr_t); map = &hdr->freemap[0]; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { if (INT_GET(map->base, ARCH_CONVERT) == tmp) { INT_MOD(map->base, ARCH_CONVERT, sizeof(xfs_attr_leaf_entry_t)); INT_MOD(map->size, ARCH_CONVERT, -sizeof(xfs_attr_leaf_entry_t)); } } INT_MOD(hdr->usedbytes, ARCH_CONVERT, xfs_attr_leaf_entsize(leaf, args->index)); xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); return(0);}/* * Garbage collect a leaf attribute list block by copying it to a new buffer. */STATIC voidxfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp){ xfs_attr_leafblock_t *leaf_s, *leaf_d; xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; xfs_mount_t *mp; char *tmpbuffer; mp = trans->t_mountp; tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP); ASSERT(tmpbuffer != NULL); memcpy(tmpbuffer, bp->data, XFS_LBSIZE(mp)); memset(bp->data, 0, XFS_LBSIZE(mp)); /* * Copy basic information */ leaf_s = (xfs_attr_leafblock_t *)tmpbuffer; leaf_d = bp->data; hdr_s = &leaf_s->hdr; hdr_d = &leaf_d->hdr; hdr_d->info = hdr_s->info; /* struct copy */ INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp)); /* handle truncation gracefully */ if (INT_ISZERO(hdr_d->firstused, ARCH_CONVERT)) { INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp) - XFS_ATTR_LEAF_NAME_ALIGN); } INT_ZERO(hdr_d->usedbytes, ARCH_CONVERT); INT_ZERO(hdr_d->count, ARCH_CONVERT); hdr_d->holes = 0; INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, sizeof(xfs_attr_leaf_hdr_t)); INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); /* * Copy all entry's in the same (sorted) order, * but allocate name/value pairs packed and in sequence. */ xfs_attr_leaf_moveents(leaf_s, 0, leaf_d, 0, (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1); kmem_free(tmpbuffer, XFS_LBSIZE(mp));}/* * Redistribute the attribute list entries between two leaf nodes, * taking into account the size of the new entry. * * NOTE: if new block is empty, then it will get the upper half of the * old block. At present, all (one) callers pass in an empty second block. * * This code adjusts the args->index/blkno and args->index2/blkno2 fields * to match what it is doing in splitting the attribute leaf block. Those * values are used in "atomic rename" operations on attributes. Note that * the "new" and "old" values can end up in different blocks. */STATIC voidxfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, xfs_da_state_blk_t *blk2){ xfs_da_args_t *args; xfs_da_state_blk_t *tmp_blk; xfs_attr_leafblock_t *leaf1, *leaf2; xfs_attr_leaf_hdr_t *hdr1, *hdr2; int count, totallen, max, space, swap; /* * Set up environment. */ ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC); ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC); leaf1 = blk1->bp->data; leaf2 = blk2->bp->data; ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); args = state->args; /* * Check ordering of blocks, reverse if it makes things simpler. * * NOTE: Given that all (current) callers pass in an empty * second block, this code should never set "swap". */ swap = 0; if (xfs_attr_leaf_order(blk1->bp, blk2->bp)) { tmp_blk = blk1; blk1 = blk2; blk2 = tmp_blk; leaf1 = blk1->bp->data; leaf2 = blk2->bp->data; swap = 1; } hdr1 = &leaf1->hdr; hdr2 = &leaf2->hdr; /* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. Then get * the direction to copy and the number of elements to move. * * "inleaf" is true if the new entry should be inserted into blk1. * If "swap" is also true, then reverse the sense of "inleaf". */ state->inleaf = xfs_attr_leaf_figure_balance(state, blk1, blk2, &count, &totallen); if (swap) state->inleaf = !state->inleaf; /* * Move any entries required from leaf to leaf: */ if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { /* * Figure the total bytes to be added to the destination leaf. */ /* number entries being moved */ count = INT_GET(hdr1->count, ARCH_CONVERT) - count; space = INT_GET(hdr1->usedbytes, ARCH_CONVERT) - totallen; space += count * sizeof(xfs_attr_leaf_entry_t); /* * leaf2 is the destination, compact it if it looks tight. */ max = INT_GET(hdr2->firstused, ARCH_CONVERT) - sizeof(xfs_attr_leaf_hdr_t); max -= INT_GET(hdr2->count, ARCH_CONVERT) * sizeof(xfs_attr_leaf_entry_t); if (space > max) { xfs_attr_leaf_compact(args->trans, blk2->bp); } /* * Move high entries from leaf1 to low end of leaf2. */ xfs_attr_leaf_moveents(leaf1, INT_GET(hdr1->count, ARCH_CONVERT)-count, leaf2, 0, count, state->mp); xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { /* * I assert that since all callers pass in an empty * second buffer, this code should never execute. */ /* * Figure the total bytes to be added to the destination leaf. */ /* number entries being moved */ count -= INT_GET(hdr1->count, ARCH_CONVERT); space = totallen - INT_GET(hdr1->usedbytes, ARCH_CONVERT); space += count * sizeof(xfs_attr_leaf_entry_t); /* * leaf1 is the destination, compact it if it looks tight. */ max = INT_GET(hdr1->firstused, ARCH_CONVERT) - sizeof(xfs_attr_leaf_hdr_t); max -= INT_GET(hdr1->count, ARCH_CONVERT) * sizeof(xfs_attr_leaf_entry_t); if (space > max) { xfs_attr_leaf_compact(args->trans, blk1->bp); } /* * Move low entries from leaf2 to high end of leaf1. */ xfs_attr_leaf_moveents(leaf2, 0, leaf1, (int)INT_GET(hdr1->count, ARCH_CONVERT), count, state->mp); xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); } /* * Copy out last hashval in each block for B-tree code. */ blk1->hashval = INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT); blk2->hashval = INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT); /* * Adjust the expected index for insertion. * NOTE: this code depends on the (current) situation that the * second block was originally empty. * * If the insertion point moved to the 2nd block, we must adjust * the index. We must also track the entry just following the * new entry for use in an "atomic rename" operation, that entry * is always the "old" entry and the "new" entry is what we are * inserting. The index/blkno fields refer to the "old" entry, * while the index2/blkno2 fields refer to the "new" entry. */ if (blk1->index > INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { ASSERT(state->inleaf == 0); blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); args->index = args->index2 = blk2->index; args->blkno = args->blkno2 = blk2->blkno; } else if (blk1->index == INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { if (state->inleaf) { args->index = blk1->index; args->blkno = blk1->blkno; args->index2 = 0; args->blkno2 = blk2->blkno; } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?