xfs_attr_leaf.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,154 行 · 第 1/5 页
C
2,154 行
{ attrlist_cursor_kern_t *cursor; xfs_attr_sf_sort_t *sbuf, *sbp; xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; xfs_inode_t *dp; int sbsize, nsbuf, count, i; ASSERT(context != NULL); dp = context->dp; ASSERT(dp != NULL); ASSERT(dp->i_afp != NULL); sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; ASSERT(sf != NULL); if (INT_ISZERO(sf->hdr.count, ARCH_CONVERT)) return(0); cursor = context->cursor; ASSERT(cursor != NULL); xfs_attr_trace_l_c("sf start", context); /* * If the buffer is large enough, do not bother with sorting. * Note the generous fudge factor of 16 overhead bytes per entry. */ if ((dp->i_afp->if_bytes + INT_GET(sf->hdr.count, ARCH_CONVERT) * 16) < context->bufsize) { for (i = 0, sfe = &sf->list[0]; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { attrnames_t *namesp; if (((context->flags & ATTR_SECURE) != 0) != ((sfe->flags & XFS_ATTR_SECURE) != 0) && !(context->flags & ATTR_KERNORMALS)) { sfe = XFS_ATTR_SF_NEXTENTRY(sfe); continue; } if (((context->flags & ATTR_ROOT) != 0) != ((sfe->flags & XFS_ATTR_ROOT) != 0) && !(context->flags & ATTR_KERNROOTLS)) { sfe = XFS_ATTR_SF_NEXTENTRY(sfe); continue; } namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure: ((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user); if (context->flags & ATTR_KERNOVAL) { ASSERT(context->flags & ATTR_KERNAMELS); context->count += namesp->attr_namelen + INT_GET(sfe->namelen, ARCH_CONVERT) + 1; } else { if (xfs_attr_put_listent(context, namesp, (char *)sfe->nameval, (int)sfe->namelen, (int)INT_GET(sfe->valuelen, ARCH_CONVERT))) break; } sfe = XFS_ATTR_SF_NEXTENTRY(sfe); } xfs_attr_trace_l_c("sf big-gulp", context); return(0); } /* * It didn't all fit, so we have to sort everything on hashval. */ sbsize = INT_GET(sf->hdr.count, ARCH_CONVERT) * sizeof(*sbuf); sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP); /* * Scan the attribute list for the rest of the entries, storing * the relevant info from only those that match into a buffer. */ nsbuf = 0; for (i = 0, sfe = &sf->list[0]; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { if (unlikely( ((char *)sfe < (char *)sf) || ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) { XFS_CORRUPTION_ERROR("xfs_attr_shortform_list", XFS_ERRLEVEL_LOW, context->dp->i_mount, sfe); xfs_attr_trace_l_c("sf corrupted", context); kmem_free(sbuf, sbsize); return XFS_ERROR(EFSCORRUPTED); } if (((context->flags & ATTR_SECURE) != 0) != ((sfe->flags & XFS_ATTR_SECURE) != 0) && !(context->flags & ATTR_KERNORMALS)) { sfe = XFS_ATTR_SF_NEXTENTRY(sfe); continue; } if (((context->flags & ATTR_ROOT) != 0) != ((sfe->flags & XFS_ATTR_ROOT) != 0) && !(context->flags & ATTR_KERNROOTLS)) { sfe = XFS_ATTR_SF_NEXTENTRY(sfe); continue; } sbp->entno = i; INT_SET(sbp->hash, ARCH_CONVERT, xfs_da_hashname((char *)sfe->nameval, sfe->namelen)); sbp->name = (char *)sfe->nameval; sbp->namelen = sfe->namelen; /* These are bytes, and both on-disk, don't endian-flip */ sbp->valuelen = sfe->valuelen; sbp->flags = sfe->flags; sfe = XFS_ATTR_SF_NEXTENTRY(sfe); sbp++; nsbuf++; } /* * Sort the entries on hash then entno. */ qsort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare); /* * Re-find our place IN THE SORTED LIST. */ count = 0; cursor->initted = 1; cursor->blkno = 0; for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) { if (INT_GET(sbp->hash, ARCH_CONVERT) == cursor->hashval) { if (cursor->offset == count) { break; } count++; } else if (INT_GET(sbp->hash, ARCH_CONVERT) > cursor->hashval) { break; } } if (i == nsbuf) { kmem_free(sbuf, sbsize); xfs_attr_trace_l_c("blk end", context); return(0); } /* * Loop putting entries into the user buffer. */ for ( ; i < nsbuf; i++, sbp++) { attrnames_t *namesp; namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure : ((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user); if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) { cursor->hashval = INT_GET(sbp->hash, ARCH_CONVERT); cursor->offset = 0; } if (context->flags & ATTR_KERNOVAL) { ASSERT(context->flags & ATTR_KERNAMELS); context->count += namesp->attr_namelen + sbp->namelen + 1; } else { if (xfs_attr_put_listent(context, namesp, sbp->name, sbp->namelen, INT_GET(sbp->valuelen, ARCH_CONVERT))) break; } cursor->offset++; } kmem_free(sbuf, sbsize); xfs_attr_trace_l_c("sf E-O-F", context); return(0);}/* * Check a leaf attribute block to see if all the entries would fit into * a shortform attribute list. */intxfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp){ xfs_attr_leafblock_t *leaf; xfs_attr_leaf_entry_t *entry; xfs_attr_leaf_name_local_t *name_loc; int bytes, i; leaf = bp->data; ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); entry = &leaf->entries[0]; bytes = sizeof(struct xfs_attr_sf_hdr); for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { if (entry->flags & XFS_ATTR_INCOMPLETE) continue; /* don't copy partial entries */ if (!(entry->flags & XFS_ATTR_LOCAL)) return(0); name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX) return(0); if (INT_GET(name_loc->valuelen, ARCH_CONVERT) >= XFS_ATTR_SF_ENTSIZE_MAX) return(0); bytes += sizeof(struct xfs_attr_sf_entry)-1 + name_loc->namelen + INT_GET(name_loc->valuelen, ARCH_CONVERT); } return( bytes < XFS_IFORK_ASIZE(dp) );}/* * Convert a leaf attribute list to shortform attribute list */intxfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args){ xfs_attr_leafblock_t *leaf; xfs_attr_leaf_entry_t *entry; xfs_attr_leaf_name_local_t *name_loc; xfs_da_args_t nargs; xfs_inode_t *dp; char *tmpbuffer; int error, i; dp = args->dp; tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP); ASSERT(tmpbuffer != NULL); ASSERT(bp != NULL); memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount)); leaf = (xfs_attr_leafblock_t *)tmpbuffer; ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); memset(bp->data, 0, XFS_LBSIZE(dp->i_mount)); /* * Clean out the prior contents of the attribute list. */ error = xfs_da_shrink_inode(args, 0, bp); if (error) goto out; error = xfs_attr_shortform_create(args); if (error) goto out; /* * Copy the attributes */ memset((char *)&nargs, 0, sizeof(nargs)); nargs.dp = dp; nargs.firstblock = args->firstblock; nargs.flist = args->flist; nargs.total = args->total; nargs.whichfork = XFS_ATTR_FORK; nargs.trans = args->trans; nargs.oknoent = 1; entry = &leaf->entries[0]; for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { if (entry->flags & XFS_ATTR_INCOMPLETE) continue; /* don't copy partial entries */ if (INT_ISZERO(entry->nameidx, ARCH_CONVERT)) continue; ASSERT(entry->flags & XFS_ATTR_LOCAL); name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); nargs.name = (char *)name_loc->nameval; nargs.namelen = name_loc->namelen; nargs.value = (char *)&name_loc->nameval[nargs.namelen]; nargs.valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT); nargs.hashval = INT_GET(entry->hashval, ARCH_CONVERT); nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE : ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0); xfs_attr_shortform_add(&nargs); } error = 0;out: kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); return(error);}/* * Convert from using a single leaf to a root node and a leaf. */intxfs_attr_leaf_to_node(xfs_da_args_t *args){ xfs_attr_leafblock_t *leaf; xfs_da_intnode_t *node; xfs_inode_t *dp; xfs_dabuf_t *bp1, *bp2; xfs_dablk_t blkno; int error; dp = args->dp; bp1 = bp2 = NULL; error = xfs_da_grow_inode(args, &blkno); if (error) goto out; error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1, XFS_ATTR_FORK); if (error) goto out; ASSERT(bp1 != NULL); bp2 = NULL; error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp2, XFS_ATTR_FORK); if (error) goto out; ASSERT(bp2 != NULL); memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount)); xfs_da_buf_done(bp1); bp1 = NULL; xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1); /* * Set up the new root node. */ error = xfs_da_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK); if (error) goto out; node = bp1->data; leaf = bp2->data; ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); /* both on-disk, don't endian-flip twice */ node->btree[0].hashval = leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval; INT_SET(node->btree[0].before, ARCH_CONVERT, blkno); INT_SET(node->hdr.count, ARCH_CONVERT, 1); xfs_da_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1); error = 0;out: if (bp1) xfs_da_buf_done(bp1); if (bp2) xfs_da_buf_done(bp2); return(error);}/*======================================================================== * Routines used for growing the Btree. *========================================================================*//* * Create the initial contents of a leaf attribute list * or a leaf in a node attribute list. */intxfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp){ xfs_attr_leafblock_t *leaf; xfs_attr_leaf_hdr_t *hdr; xfs_inode_t *dp; xfs_dabuf_t *bp; int error; dp = args->dp; ASSERT(dp != NULL); error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp, XFS_ATTR_FORK); if (error) return(error); ASSERT(bp != NULL); leaf = bp->data; memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount)); hdr = &leaf->hdr; INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC); INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) { INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN); } INT_SET(hdr->freemap[0].base, ARCH_CONVERT, sizeof(xfs_attr_leaf_hdr_t)); INT_SET(hdr->freemap[0].size, ARCH_CONVERT, INT_GET(hdr->firstused, ARCH_CONVERT) - INT_GET(hdr->freemap[0].base, ARCH_CONVERT)); xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); *bpp = bp; return(0);}/* * Split the leaf node, rebalance, then add the new entry. */intxfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, xfs_da_state_blk_t *newblk){ xfs_dablk_t blkno; int error; /* * Allocate space for a new leaf node. */ ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC); error = xfs_da_grow_inode(state->args, &blkno); if (error) return(error); error = xfs_attr_leaf_create(state->args, blkno, &newblk->bp); if (error) return(error); newblk->blkno = blkno; newblk->magic = XFS_ATTR_LEAF_MAGIC; /* * Rebalance the entries across the two leaves. * NOTE: rebalance() currently depends on the 2nd block being empty. */ xfs_attr_leaf_rebalance(state, oldblk, newblk); error = xfs_da_blk_link(state, oldblk, newblk); if (error) return(error); /* * Save info on "old" attribute for "atomic rename" ops, leaf_add() * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the * "new" attrs info. Will need the "old" info to remove it later. * * Insert the "new" entry in the correct block. */ if (state->inleaf) error = xfs_attr_leaf_add(oldblk->bp, state->args); else error = xfs_attr_leaf_add(newblk->bp, state->args); /* * Update last hashval in each block since we added the name. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?