xfs_attr.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,474 行 · 第 1/5 页
C
2,474 行
* remote value. */ error = xfs_attr_leaf_setflag(args); if (error) goto out; error = xfs_attr_rmtval_remove(args); if (error) goto out; /* * Refill the state structure with buffers, the prior calls * released our buffers. */ error = xfs_attr_refillstate(state); if (error) goto out; } /* * Remove the name and update the hashvals in the tree. */ blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); retval = xfs_attr_leaf_remove(blk->bp, args); xfs_da_fixhashpath(state, &state->path); /* * Check to see if the tree needs to be collapsed. */ if (retval && (state->path.active > 1)) { XFS_BMAP_INIT(args->flist, args->firstblock); error = xfs_da_join(state); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, *args->firstblock, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); goto out; } /* * bmap_finish() may have committed the last trans and started * a new one. We need the inode to be in all transactions. */ if (committed) { xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); xfs_trans_ihold(args->trans, dp); } /* * Commit the Btree join operation and start a new trans. */ if ((error = xfs_attr_rolltrans(&args->trans, dp))) goto out; } /* * If the result is small enough, push it all into the inode. */ if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { /* * Have to get rid of the copy of this dabuf in the state. */ ASSERT(state->path.active == 1); ASSERT(state->path.blk[0].bp); xfs_da_buf_done(state->path.blk[0].bp); state->path.blk[0].bp = NULL; error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, XFS_ATTR_FORK); if (error) goto out; ASSERT(INT_GET(((xfs_attr_leafblock_t *) bp->data)->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); if (xfs_attr_shortform_allfit(bp, dp)) { XFS_BMAP_INIT(args->flist, args->firstblock); error = xfs_attr_leaf_to_shortform(bp, args); /* bp is gone due to xfs_da_shrink_inode */ if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, *args->firstblock, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); goto out; } /* * bmap_finish() may have committed the last trans * and started a new one. We need the inode to be * in all transactions. */ if (committed) { xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); xfs_trans_ihold(args->trans, dp); } } else xfs_da_brelse(args->trans, bp); } error = 0;out: xfs_da_state_free(state); return(error);}/* * Fill in the disk block numbers in the state structure for the buffers * that are attached to the state structure. * This is done so that we can quickly reattach ourselves to those buffers * after some set of transaction commit's has released these buffers. */STATIC intxfs_attr_fillstate(xfs_da_state_t *state){ xfs_da_state_path_t *path; xfs_da_state_blk_t *blk; int level; /* * Roll down the "path" in the state structure, storing the on-disk * block number for those buffers in the "path". */ path = &state->path; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->bp) { blk->disk_blkno = xfs_da_blkno(blk->bp); xfs_da_buf_done(blk->bp); blk->bp = NULL; } else { blk->disk_blkno = 0; } } /* * Roll down the "altpath" in the state structure, storing the on-disk * block number for those buffers in the "altpath". */ path = &state->altpath; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->bp) { blk->disk_blkno = xfs_da_blkno(blk->bp); xfs_da_buf_done(blk->bp); blk->bp = NULL; } else { blk->disk_blkno = 0; } } return(0);}/* * Reattach the buffers to the state structure based on the disk block * numbers stored in the state structure. * This is done after some set of transaction commit's has released those * buffers from our grip. */STATIC intxfs_attr_refillstate(xfs_da_state_t *state){ xfs_da_state_path_t *path; xfs_da_state_blk_t *blk; int level, error; /* * Roll down the "path" in the state structure, storing the on-disk * block number for those buffers in the "path". */ path = &state->path; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->disk_blkno) { error = xfs_da_read_buf(state->args->trans, state->args->dp, blk->blkno, blk->disk_blkno, &blk->bp, XFS_ATTR_FORK); if (error) return(error); } else { blk->bp = NULL; } } /* * Roll down the "altpath" in the state structure, storing the on-disk * block number for those buffers in the "altpath". */ path = &state->altpath; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->disk_blkno) { error = xfs_da_read_buf(state->args->trans, state->args->dp, blk->blkno, blk->disk_blkno, &blk->bp, XFS_ATTR_FORK); if (error) return(error); } else { blk->bp = NULL; } } return(0);}/* * Look up a filename in a node attribute list. * * This routine gets called for any attribute fork that has more than one * block, ie: both true Btree attr lists and for single-leaf-blocks with * "remote" values taking up more blocks. */intxfs_attr_node_get(xfs_da_args_t *args){ xfs_da_state_t *state; xfs_da_state_blk_t *blk; int error, retval; int i; state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; state->blocksize = state->mp->m_sb.sb_blocksize; state->node_ents = state->mp->m_attr_node_ents; /* * Search to see if name exists, and get back a pointer to it. */ error = xfs_da_node_lookup_int(state, &retval); if (error) { retval = error; } else if (retval == EEXIST) { blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->bp != NULL); ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); /* * Get the value, local or "remote" */ retval = xfs_attr_leaf_getvalue(blk->bp, args); if (!retval && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { retval = xfs_attr_rmtval_get(args); } } /* * If not in a transaction, we have to release all the buffers. */ for (i = 0; i < state->path.active; i++) { xfs_da_brelse(args->trans, state->path.blk[i].bp); state->path.blk[i].bp = NULL; } xfs_da_state_free(state); return(retval);}STATIC int /* error */xfs_attr_node_list(xfs_attr_list_context_t *context){ attrlist_cursor_kern_t *cursor; xfs_attr_leafblock_t *leaf; xfs_da_intnode_t *node; xfs_da_node_entry_t *btree; int error, i; xfs_dabuf_t *bp; cursor = context->cursor; cursor->initted = 1; /* * Do all sorts of validation on the passed-in cursor structure. * If anything is amiss, ignore the cursor and look up the hashval * starting from the btree root. */ bp = NULL; if (cursor->blkno > 0) { error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, &bp, XFS_ATTR_FORK); if ((error != 0) && (error != EFSCORRUPTED)) return(error); if (bp) { node = bp->data; switch (INT_GET(node->hdr.info.magic, ARCH_CONVERT)) { case XFS_DA_NODE_MAGIC: xfs_attr_trace_l_cn("wrong blk", context, node); xfs_da_brelse(NULL, bp); bp = NULL; break; case XFS_ATTR_LEAF_MAGIC: leaf = bp->data; if (cursor->hashval > INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT)) { xfs_attr_trace_l_cl("wrong blk", context, leaf); xfs_da_brelse(NULL, bp); bp = NULL; } else if (cursor->hashval <= INT_GET(leaf->entries[0].hashval, ARCH_CONVERT)) { xfs_attr_trace_l_cl("maybe wrong blk", context, leaf); xfs_da_brelse(NULL, bp); bp = NULL; } break; default: xfs_attr_trace_l_c("wrong blk - ??", context); xfs_da_brelse(NULL, bp); bp = NULL; } } } /* * We did not find what we expected given the cursor's contents, * so we start from the top and work down based on the hash value. * Note that start of node block is same as start of leaf block. */ if (bp == NULL) { cursor->blkno = 0; for (;;) { error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, &bp, XFS_ATTR_FORK); if (error) return(error); if (unlikely(bp == NULL)) { XFS_ERROR_REPORT("xfs_attr_node_list(2)", XFS_ERRLEVEL_LOW, context->dp->i_mount); return(XFS_ERROR(EFSCORRUPTED)); } node = bp->data; if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) break; if (unlikely(INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC)) { XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)", XFS_ERRLEVEL_LOW, context->dp->i_mount, node); xfs_da_brelse(NULL, bp); return(XFS_ERROR(EFSCORRUPTED)); } btree = node->btree; for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); btree++, i++) { if (cursor->hashval <= INT_GET(btree->hashval, ARCH_CONVERT)) { cursor->blkno = INT_GET(btree->before, ARCH_CONVERT); xfs_attr_trace_l_cb("descending", context, btree); break; } } if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) { xfs_da_brelse(NULL, bp); return(0); } xfs_da_brelse(NULL, bp); } } ASSERT(bp != NULL); /* * Roll upward through the blocks, processing each leaf block in * order. As long as there is space in the result buffer, keep * adding the information. */ for (;;) { leaf = bp->data; if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_ATTR_LEAF_MAGIC)) { XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)", XFS_ERRLEVEL_LOW, context->dp->i_mount, leaf); xfs_da_brelse(NULL, bp); return(XFS_ERROR(EFSCORRUPTED)); } error = xfs_attr_leaf_list_int(bp, context); if (error || (INT_ISZERO(leaf->hdr.info.forw, ARCH_CONVERT))) break; /* not really an error, buffer full or EOF */ cursor->blkno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); xfs_da_brelse(NULL, bp); error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, &bp, XFS_ATTR_FORK); if (error) return(error); if (unlikely((bp == NULL))) { XFS_ERROR_REPORT("xfs_attr_node_list(5)", XFS_ERRLEVEL_LOW, context->dp->i_mount); return(XFS_ERROR(EFSCORRUPTED)); } } xfs_da_brelse(NULL, bp); return(0);}/*======================================================================== * External routines for manipulating out-of-line attribute values. *========================================================================*//* * Read the value associated with an attribute from the out-of-line buffer * that we stored it in. */STATIC intxfs_attr_rmtval_get(xfs_da_args_t *args){ xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; xfs_mount_t *mp; xfs_daddr_t dblkno; xfs_caddr_t dst; xfs_buf_t *bp; int nmap, error, tmp, valuelen, blkcnt, i; xfs_dablk_t lblkno; ASSERT(!(args->flags & ATTR_KERNOVAL)); mp = args->dp->i_mount; dst = args->value; valuelen = args->valuelen; lblkno = args->rmtblkno; while (valuelen > 0) { nmap = ATTR_RMTVALUE_MAPSIZE; error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno, args->rmtblkcnt, XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, NULL, 0, map, &nmap, NULL); if (error) return(error); ASSERT(nmap >= 1); for (i = 0; (i < nmap) && (valuelen > 0); i++) { ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && (map[i].br_startblock != HOLESTARTBLOCK)); dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, blkcnt, XFS_BUF_LOCK, &bp); if (error) return(error); tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen : XFS_BUF_SIZE(bp); xfs_biomove(bp, 0, tmp, dst, XFS_B_READ); xfs_buf_relse(bp); dst += tmp; valuelen -= tmp; lblkno += map[i].br_blockcount; } } ASSERT(valuelen == 0); return(0);}/* * Write the value associated with an attribute into the out-of-line buffer * that we have defined for it. */STATIC intxfs_attr_rmtval_set(xfs_da_args_t *args){ xfs_mount_t *mp; xfs_fileoff_t lfileoff; xfs_inode_t *dp; xfs_bmbt_irec_t map; xfs_daddr_t dblkno; xfs_caddr_t src; xfs_buf_t *bp; xfs_dablk_t lblkno;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?