xfs_dir2.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 860 行 · 第 1/2 页

C
860
字号
/* * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like.  Any license provided herein, whether implied or * otherwise, applies only to this software file.  Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA  94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ *//* * XFS v2 directory implmentation. * Top-level and utility routines. */#include "xfs.h"#include "xfs_macros.h"#include "xfs_types.h"#include "xfs_inum.h"#include "xfs_log.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_alloc_btree.h"#include "xfs_bmap_btree.h"#include "xfs_attr_sf.h"#include "xfs_dir_sf.h"#include "xfs_dir2_sf.h"#include "xfs_dinode.h"#include "xfs_inode_item.h"#include "xfs_inode.h"#include "xfs_bmap.h"#include "xfs_da_btree.h"#include "xfs_dir_leaf.h"#include "xfs_dir2_data.h"#include "xfs_dir2_leaf.h"#include "xfs_dir2_block.h"#include "xfs_dir2_node.h"#include "xfs_dir2_trace.h"#include "xfs_error.h"#include "xfs_bit.h"/* * Declarations for interface routines. */static void	xfs_dir2_mount(xfs_mount_t *mp);static int	xfs_dir2_isempty(xfs_inode_t *dp);static int	xfs_dir2_init(xfs_trans_t *tp, xfs_inode_t *dp,			      xfs_inode_t *pdp);static int	xfs_dir2_createname(xfs_trans_t *tp, xfs_inode_t *dp,				    char *name, int namelen, xfs_ino_t inum,				    xfs_fsblock_t *first,				    xfs_bmap_free_t *flist, xfs_extlen_t total);static int	xfs_dir2_lookup(xfs_trans_t *tp, xfs_inode_t *dp, char *name,				int namelen, xfs_ino_t *inum);static int	xfs_dir2_removename(xfs_trans_t *tp, xfs_inode_t *dp,				    char *name, int namelen, xfs_ino_t ino,				    xfs_fsblock_t *first,				    xfs_bmap_free_t *flist, xfs_extlen_t total);static int	xfs_dir2_getdents(xfs_trans_t *tp, xfs_inode_t *dp, uio_t *uio,				  int *eofp);static int	xfs_dir2_replace(xfs_trans_t *tp, xfs_inode_t *dp, char *name,				 int namelen, xfs_ino_t inum,				 xfs_fsblock_t *first, xfs_bmap_free_t *flist,				 xfs_extlen_t total);static int	xfs_dir2_canenter(xfs_trans_t *tp, xfs_inode_t *dp, char *name,				  int namelen);static int	xfs_dir2_shortform_validate_ondisk(xfs_mount_t *mp,						   xfs_dinode_t *dip);/* * Utility routine declarations. */static int	xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa);static int	xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa);/* * Directory operations vector. */xfs_dirops_t	xfsv2_dirops = {	.xd_mount			= xfs_dir2_mount,	.xd_isempty			= xfs_dir2_isempty,	.xd_init			= xfs_dir2_init,	.xd_createname			= xfs_dir2_createname,	.xd_lookup			= xfs_dir2_lookup,	.xd_removename			= xfs_dir2_removename,	.xd_getdents			= xfs_dir2_getdents,	.xd_replace			= xfs_dir2_replace,	.xd_canenter			= xfs_dir2_canenter,	.xd_shortform_validate_ondisk	= xfs_dir2_shortform_validate_ondisk,	.xd_shortform_to_single		= xfs_dir2_sf_to_block,};/* * Interface routines. *//* * Initialize directory-related fields in the mount structure. */static voidxfs_dir2_mount(	xfs_mount_t	*mp)		/* filesystem mount point */{	mp->m_dirversion = 2;	ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=	       XFS_MAX_BLOCKSIZE);	mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);	mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;	mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp));	mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp));	mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp));	mp->m_attr_node_ents =		(mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /		(uint)sizeof(xfs_da_node_entry_t);	mp->m_dir_node_ents =		(mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /		(uint)sizeof(xfs_da_node_entry_t);	mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;}/* * Return 1 if directory contains only "." and "..". */static int				/* return code */xfs_dir2_isempty(	xfs_inode_t	*dp)		/* incore inode structure */{	xfs_dir2_sf_t	*sfp;		/* shortform directory structure */	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	/*	 * Might happen during shutdown.	 */	if (dp->i_d.di_size == 0) {		return 1;	}	if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))		return 0;	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	return INT_ISZERO(sfp->hdr.count, ARCH_CONVERT);}/* * Initialize a directory with its "." and ".." entries. */static int				/* error */xfs_dir2_init(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_inode_t	*dp,		/* incore directory inode */	xfs_inode_t	*pdp)		/* incore parent directory inode */{	xfs_da_args_t	args;		/* operation arguments */	int		error;		/* error return value */	memset((char *)&args, 0, sizeof(args));	args.dp = dp;	args.trans = tp;	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) {		return error;	}	return xfs_dir2_sf_create(&args, pdp->i_ino);}/*  Enter a name in a directory. */static int					/* error */xfs_dir2_createname(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_inode_t		*dp,		/* incore directory inode */	char			*name,		/* new entry name */	int			namelen,	/* new entry name length */	xfs_ino_t		inum,		/* new entry inode number */	xfs_fsblock_t		*first,		/* bmap's firstblock */	xfs_bmap_free_t		*flist,		/* bmap's freeblock list */	xfs_extlen_t		total)		/* bmap's total block count */{	xfs_da_args_t		args;		/* operation arguments */	int			rval;		/* return value */	int			v;		/* type-checking value */	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {		return rval;	}	XFS_STATS_INC(xs_dir_create);	/*	 * 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 = first;	args.flist = flist;	args.total = total;	args.whichfork = XFS_DATA_FORK;	args.trans = tp;	args.justcheck = 0;	args.addname = 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)		rval = xfs_dir2_sf_addname(&args);	else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {		return rval;	} else if (v)		rval = xfs_dir2_block_addname(&args);	else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {		return rval;	} else if (v)		rval = xfs_dir2_leaf_addname(&args);	else		rval = xfs_dir2_node_addname(&args);	return rval;}/* * Lookup a name in a directory, give back the inode number. */static int				/* error */xfs_dir2_lookup(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_inode_t	*dp,		/* incore directory inode */	char		*name,		/* lookup name */	int		namelen,	/* lookup name length */	xfs_ino_t	*inum)		/* out: inode number */{	xfs_da_args_t	args;		/* operation arguments */	int		rval;		/* return value */	int		v;		/* type-checking value */	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 = tp;	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)		rval = xfs_dir2_sf_lookup(&args);	else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {		return rval;	} else if (v)		rval = xfs_dir2_block_lookup(&args);	else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {		return rval;	} else if (v)		rval = xfs_dir2_leaf_lookup(&args);	else		rval = xfs_dir2_node_lookup(&args);	if (rval == EEXIST)		rval = 0;	if (rval == 0)		*inum = args.inumber;	return rval;}/* * Remove an entry from a directory. */static int				/* error */xfs_dir2_removename(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_inode_t	*dp,		/* incore directory inode */	char		*name,		/* name of entry to remove */	int		namelen,	/* name length of entry to remove */	xfs_ino_t	ino,		/* inode number of entry to remove */	xfs_fsblock_t	*first,		/* bmap's firstblock */	xfs_bmap_free_t	*flist,		/* bmap's freeblock list */	xfs_extlen_t	total)		/* bmap's total block count */{	xfs_da_args_t	args;		/* operation arguments */	int		rval;		/* return value */	int		v;		/* type-checking value */	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	XFS_STATS_INC(xs_dir_remove);	/*	 * Fill in the arg structure for this request.	 */	args.name = name;	args.namelen = namelen;	args.hashval = xfs_da_hashname(name, namelen);	args.inumber = ino;	args.dp = dp;	args.firstblock = first;	args.flist = flist;	args.total = total;	args.whichfork = XFS_DATA_FORK;	args.trans = tp;	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)		rval = xfs_dir2_sf_removename(&args);	else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {		return rval;	} else if (v)		rval = xfs_dir2_block_removename(&args);	else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {		return rval;	} else if (v)		rval = xfs_dir2_leaf_removename(&args);	else		rval = xfs_dir2_node_removename(&args);	return rval;}/* * Read a directory. */static int				/* error */xfs_dir2_getdents(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_inode_t	*dp,		/* incore directory inode */	uio_t		*uio,		/* caller's buffer control */	int		*eofp)		/* out: eof reached */{	int		alignment;	/* alignment required for ABI */	xfs_dirent_t	*dbp;		/* malloc'ed buffer */	xfs_dir2_put_t	put;		/* entry formatting routine */	int		rval;		/* return value */	int		v;		/* type-checking value */	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	XFS_STATS_INC(xs_dir_getdents);	/*	 * If our caller has given us a single contiguous aligned 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_dir2_put_dirent64_direct;	} else {		dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP);		put = xfs_dir2_put_dirent64_uio;	}	*eofp = 0;	/*	 * Decide on what work routines to call based on the inode size.	 */	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)		rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put);	else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {		;	} else if (v)		rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put);	else		rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put);	if (dbp != NULL)		kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN);	return rval;}/* * Replace the inode number of a directory entry. */static int				/* error */xfs_dir2_replace(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_inode_t	*dp,		/* incore directory inode */	char		*name,		/* name of entry to replace */	int		namelen,	/* name length of entry to replace */	xfs_ino_t	inum,		/* new inode number */	xfs_fsblock_t	*first,		/* bmap's firstblock */	xfs_bmap_free_t	*flist,		/* bmap's freeblock list */	xfs_extlen_t	total)		/* bmap's total block count */{	xfs_da_args_t	args;		/* operation arguments */	int		rval;		/* return value */	int		v;		/* type-checking value */	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {		return rval;	}	/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?