xfs_dir.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,224 行 · 第 1/3 页
C
1,224 行
xfs_da_args_t args; int retval; ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); XFS_STATS_INC(xs_dir_lookup); /* * Fill in the arg structure for this request. */ args.name = name; args.namelen = namelen; args.hashval = xfs_da_hashname(name, namelen); args.inumber = 0; args.dp = dp; args.firstblock = NULL; args.flist = NULL; args.total = 0; args.whichfork = XFS_DATA_FORK; args.trans = trans; args.justcheck = args.addname = 0; args.oknoent = 1; /* * Decide on what work routines to call based on the inode size. */ if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { retval = xfs_dir_shortform_lookup(&args); } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { retval = xfs_dir_leaf_lookup(&args); } else { retval = xfs_dir_node_lookup(&args); } if (retval == EEXIST) retval = 0; *inum = args.inumber; return(retval);}/* * Implement readdir. */static int /* error */xfs_dir_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, int *eofp){ xfs_dirent_t *dbp; int alignment, retval; xfs_dir_put_t put; XFS_STATS_INC(xs_dir_getdents); ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); /* * If our caller has given us a single contiguous memory buffer, * just work directly within that buffer. If it's in user memory, * lock it down first. */ alignment = sizeof(xfs_off_t) - 1; if ((uio->uio_iovcnt == 1) && (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) && ((uio->uio_iov[0].iov_len & alignment) == 0)) { dbp = NULL; put = xfs_dir_put_dirent64_direct; } else { dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP); put = xfs_dir_put_dirent64_uio; } /* * Decide on what work routines to call based on the inode size. */ *eofp = 0; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { retval = xfs_dir_shortform_getdents(dp, uio, eofp, dbp, put); } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { retval = xfs_dir_leaf_getdents(trans, dp, uio, eofp, dbp, put); } else { retval = xfs_dir_node_getdents(trans, dp, uio, eofp, dbp, put); } if (dbp != NULL) kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN); return(retval);}static int /* error */xfs_dir_replace(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock, xfs_bmap_free_t *flist, xfs_extlen_t total){ xfs_da_args_t args; int retval; ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) return retval; /* * Fill in the arg structure for this request. */ args.name = name; args.namelen = namelen; args.hashval = xfs_da_hashname(name, namelen); args.inumber = inum; args.dp = dp; args.firstblock = firstblock; args.flist = flist; args.total = total; args.whichfork = XFS_DATA_FORK; args.trans = trans; args.justcheck = args.addname = args.oknoent = 0; /* * Decide on what work routines to call based on the inode size. */ if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { retval = xfs_dir_shortform_replace(&args); } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { retval = xfs_dir_leaf_replace(&args); } else { retval = xfs_dir_node_replace(&args); } return(retval);}static intxfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp){ xfs_ino_t ino; int namelen_sum; int count; xfs_dir_shortform_t *sf; xfs_dir_sf_entry_t *sfe; int i; if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & S_IFMT) != S_IFDIR) { return 0; } if (INT_GET(dp->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_LOCAL) { return 0; } if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) { xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p", dp); return 1; } sf = (xfs_dir_shortform_t *)(&dp->di_u.di_dirsf); ino = XFS_GET_DIR_INO_ARCH(mp, sf->hdr.parent, ARCH_CONVERT); if (xfs_dir_ino_validate(mp, ino)) return 1; count = sf->hdr.count; if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) { xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform count: dp 0x%p", dp); return(1); } if (count == 0) { return 0; } namelen_sum = 0; sfe = &sf->list[0]; for (i = sf->hdr.count - 1; i >= 0; i--) { ino = XFS_GET_DIR_INO_ARCH(mp, sfe->inumber, ARCH_CONVERT); xfs_dir_ino_validate(mp, ino); if (sfe->namelen >= XFS_LITINO(mp)) { xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform namelen: dp 0x%p", dp); return 1; } namelen_sum += sfe->namelen; sfe = XFS_DIR_SF_NEXTENTRY(sfe); } if (namelen_sum >= XFS_LITINO(mp)) { xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform namelen: dp 0x%p", dp); return 1; } return 0;}/*======================================================================== * External routines when dirsize == XFS_LBSIZE(dp->i_mount). *========================================================================*//* * Add a name to the leaf directory structure * This is the external routine. */intxfs_dir_leaf_addname(xfs_da_args_t *args){ int index, retval; xfs_dabuf_t *bp; retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, XFS_DATA_FORK); if (retval) return(retval); ASSERT(bp != NULL); retval = xfs_dir_leaf_lookup_int(bp, args, &index); if (retval == ENOENT) retval = xfs_dir_leaf_add(bp, args, index); xfs_da_buf_done(bp); return(retval);}/* * Remove a name from the leaf directory structure * This is the external routine. */STATIC intxfs_dir_leaf_removename(xfs_da_args_t *args, int *count, int *totallen){ xfs_dir_leafblock_t *leaf; int index, retval; xfs_dabuf_t *bp; retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, XFS_DATA_FORK); if (retval) return(retval); ASSERT(bp != NULL); leaf = bp->data; ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); retval = xfs_dir_leaf_lookup_int(bp, args, &index); if (retval == EEXIST) { (void)xfs_dir_leaf_remove(args->trans, bp, index); *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); *totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); retval = 0; } xfs_da_buf_done(bp); return(retval);}/* * Look up a name in a leaf directory structure. * This is the external routine. */STATIC intxfs_dir_leaf_lookup(xfs_da_args_t *args){ int index, retval; xfs_dabuf_t *bp; retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, XFS_DATA_FORK); if (retval) return(retval); ASSERT(bp != NULL); retval = xfs_dir_leaf_lookup_int(bp, args, &index); xfs_da_brelse(args->trans, bp); return(retval);}/* * Copy out directory entries for getdents(), for leaf directories. */STATIC intxfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put){ xfs_dabuf_t *bp; int retval, eob; retval = xfs_da_read_buf(dp->i_transp, dp, 0, -1, &bp, XFS_DATA_FORK); if (retval) return(retval); ASSERT(bp != NULL); retval = xfs_dir_leaf_getdents_int(bp, dp, 0, uio, &eob, dbp, put, -1); xfs_da_brelse(trans, bp); *eofp = (eob == 0); return(retval);}/* * Look up a name in a leaf directory structure, replace the inode number. * This is the external routine. */STATIC intxfs_dir_leaf_replace(xfs_da_args_t *args){ int index, retval; xfs_dabuf_t *bp; xfs_ino_t inum; xfs_dir_leafblock_t *leaf; xfs_dir_leaf_entry_t *entry; xfs_dir_leaf_name_t *namest; inum = args->inumber; retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, XFS_DATA_FORK); if (retval) return(retval); ASSERT(bp != NULL); retval = xfs_dir_leaf_lookup_int(bp, args, &index); if (retval == EEXIST) { leaf = bp->data; entry = &leaf->entries[index]; namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); /* XXX - replace assert? */ XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT); xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); xfs_da_buf_done(bp); retval = 0; } else xfs_da_brelse(args->trans, bp); return(retval);}/*======================================================================== * External routines when dirsize > XFS_LBSIZE(mp). *========================================================================*//* * Add a name to a Btree-format directory. * * This will involve walking down the Btree, and may involve splitting * leaf nodes and even splitting intermediate nodes up to and including * the root node (a special case of an intermediate node). */STATIC intxfs_dir_node_addname(xfs_da_args_t *args){ xfs_da_state_t *state; xfs_da_state_blk_t *blk; int retval, error; /* * Fill in bucket of arguments/results/context to carry around. */ 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_dir_node_ents; /* * Search to see if name already exists, and get back a pointer * to where it should go. */ error = xfs_da_node_lookup_int(state, &retval); if (error) retval = error; if (retval != ENOENT) goto error; blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); retval = xfs_dir_leaf_add(blk->bp, args, blk->index); if (retval == 0) { /* * Addition succeeded, update Btree hashvals. */ if (!args->justcheck) xfs_da_fixhashpath(state, &state->path); } else { /* * Addition failed, split as many Btree elements as required. */ if (args->total == 0) { ASSERT(retval == ENOSPC); goto error; } retval = xfs_da_split(state); }error: xfs_da_state_free(state); return(retval);}/* * Remove a name from a B-tree directory. * * This will involve walking down the Btree, and may involve joining * leaf nodes and even joining intermediate nodes up to and including * the root node (a special case of an intermediate node). */STATIC intxfs_dir_node_removename(xfs_da_args_t *args){ xfs_da_state_t *state; xfs_da_state_blk_t *blk; int retval, error; 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_dir_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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?