⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_attr_leaf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms 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.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_da_btree.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_alloc.h"#include "xfs_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_inode_item.h"#include "xfs_bmap.h"#include "xfs_attr.h"#include "xfs_attr_leaf.h"#include "xfs_error.h"/* * xfs_attr_leaf.c * * Routines to implement leaf blocks of attributes as Btrees of hashed names. *//*======================================================================== * Function prototypes for the kernel. *========================================================================*//* * Routines used for growing the Btree. */STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block,				    xfs_dabuf_t **bpp);STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args,					      int freemap_index);STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer);STATIC void xfs_attr_leaf_rebalance(xfs_da_state_t *state,						   xfs_da_state_blk_t *blk1,						   xfs_da_state_blk_t *blk2);STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state,					   xfs_da_state_blk_t *leaf_blk_1,					   xfs_da_state_blk_t *leaf_blk_2,					   int *number_entries_in_blk1,					   int *number_usedbytes_in_blk1);/* * Routines used for shrinking the Btree. */STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp,				  xfs_dabuf_t *bp, int level);STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp,				  xfs_dabuf_t *bp);STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,				   xfs_dablk_t blkno, int blkcnt);/* * Utility routines. */STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf,					 int src_start,					 xfs_attr_leafblock_t *dst_leaf,					 int dst_start, int move_count,					 xfs_mount_t *mp);STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);/*======================================================================== * Namespace helper routines *========================================================================*/STATIC_INLINE attrnames_t *xfs_attr_flags_namesp(int flags){	return ((flags & XFS_ATTR_SECURE) ? &attr_secure:		  ((flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user));}/* * If namespace bits don't match return 0. * If all match then return 1. */STATIC_INLINE intxfs_attr_namesp_match(int arg_flags, int ondisk_flags){	return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags);}/* * If namespace bits don't match and we don't have an override for it * then return 0. * If all match or are overridable then return 1. */STATIC_INLINE intxfs_attr_namesp_match_overrides(int arg_flags, int ondisk_flags){	if (((arg_flags & ATTR_SECURE) == 0) !=	    ((ondisk_flags & XFS_ATTR_SECURE) == 0) &&	    !(arg_flags & ATTR_KERNORMALS))		return 0;	if (((arg_flags & ATTR_ROOT) == 0) !=	    ((ondisk_flags & XFS_ATTR_ROOT) == 0) &&	    !(arg_flags & ATTR_KERNROOTLS))		return 0;	return 1;}/*======================================================================== * External routines when attribute fork size < XFS_LITINO(mp). *========================================================================*//* * Query whether the requested number of additional bytes of extended * attribute space will be able to fit inline. * Returns zero if not, else the di_forkoff fork offset to be used in the * literal area for attribute data once the new bytes have been added. * * di_forkoff must be 8 byte aligned, hence is stored as a >>3 value; * special case for dev/uuid inodes, they have fixed size data forks. */intxfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes){	int offset;	int minforkoff;	/* lower limit on valid forkoff locations */	int maxforkoff;	/* upper limit on valid forkoff locations */	int dsize;		xfs_mount_t *mp = dp->i_mount;	offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */	switch (dp->i_d.di_format) {	case XFS_DINODE_FMT_DEV:		minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;		return (offset >= minforkoff) ? minforkoff : 0;	case XFS_DINODE_FMT_UUID:		minforkoff = roundup(sizeof(uuid_t), 8) >> 3;		return (offset >= minforkoff) ? minforkoff : 0;	}	if (!(mp->m_flags & XFS_MOUNT_ATTR2)) {		if (bytes <= XFS_IFORK_ASIZE(dp))			return mp->m_attroffset >> 3;		return 0;	}	dsize = dp->i_df.if_bytes;		switch (dp->i_d.di_format) {	case XFS_DINODE_FMT_EXTENTS:		/* 		 * If there is no attr fork and the data fork is extents, 		 * determine if creating the default attr fork will result 		 * in the extents form migrating to btree. If so, the 		 * minimum offset only needs to be the space required for 		 * the btree root.		 */ 		if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > mp->m_attroffset)			dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);		break;			case XFS_DINODE_FMT_BTREE:		/*		 * If have data btree then keep forkoff if we have one,		 * otherwise we are adding a new attr, so then we set 		 * minforkoff to where the btree root can finish so we have 		 * plenty of room for attrs		 */		if (dp->i_d.di_forkoff) {			if (offset < dp->i_d.di_forkoff) 				return 0;			else 				return dp->i_d.di_forkoff;		} else			dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot);		break;	}		/* 	 * A data fork btree root must have space for at least 	 * MINDBTPTRS key/ptr pairs if the data fork is small or empty.	 */	minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));	minforkoff = roundup(minforkoff, 8) >> 3;	/* attr fork btree root can have at least this many key/ptr pairs */	maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);	maxforkoff = maxforkoff >> 3;	/* rounded down */	if (offset >= minforkoff && offset < maxforkoff)		return offset;	if (offset >= maxforkoff)		return maxforkoff;	return 0;}/* * Switch on the ATTR2 superblock bit (implies also FEATURES2) */STATIC voidxfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp){	unsigned long s;	if ((mp->m_flags & XFS_MOUNT_ATTR2) &&	    !(XFS_SB_VERSION_HASATTR2(&mp->m_sb))) {		s = XFS_SB_LOCK(mp);		if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb)) {			XFS_SB_VERSION_ADDATTR2(&mp->m_sb);			XFS_SB_UNLOCK(mp, s);			xfs_mod_sb(tp, XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);		} else			XFS_SB_UNLOCK(mp, s);	}}/* * Create the initial contents of a shortform attribute list. */voidxfs_attr_shortform_create(xfs_da_args_t *args){	xfs_attr_sf_hdr_t *hdr;	xfs_inode_t *dp;	xfs_ifork_t *ifp;	dp = args->dp;	ASSERT(dp != NULL);	ifp = dp->i_afp;	ASSERT(ifp != NULL);	ASSERT(ifp->if_bytes == 0);	if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) {		ifp->if_flags &= ~XFS_IFEXTENTS;	/* just in case */		dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL;		ifp->if_flags |= XFS_IFINLINE;	} else {		ASSERT(ifp->if_flags & XFS_IFINLINE);	}	xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK);	hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data;	hdr->count = 0;	hdr->totsize = cpu_to_be16(sizeof(*hdr));	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);}/* * Add a name/value pair to the shortform attribute list. * Overflow from the inode has already been checked for. */voidxfs_attr_shortform_add(xfs_da_args_t *args, int forkoff){	xfs_attr_shortform_t *sf;	xfs_attr_sf_entry_t *sfe;	int i, offset, size;	xfs_mount_t *mp;	xfs_inode_t *dp;	xfs_ifork_t *ifp;	dp = args->dp;	mp = dp->i_mount;	dp->i_d.di_forkoff = forkoff;	dp->i_df.if_ext_max =		XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);	dp->i_afp->if_ext_max =		XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);	ifp = dp->i_afp;	ASSERT(ifp->if_flags & XFS_IFINLINE);	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;	sfe = &sf->list[0];	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {#ifdef DEBUG		if (sfe->namelen != args->namelen)			continue;		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)			continue;		if (!xfs_attr_namesp_match(args->flags, sfe->flags))			continue;		ASSERT(0);#endif	}	offset = (char *)sfe - (char *)sf;	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);	xfs_idata_realloc(dp, size, XFS_ATTR_FORK);	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;	sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset);	sfe->namelen = args->namelen;	sfe->valuelen = args->valuelen;	sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);	memcpy(sfe->nameval, args->name, args->namelen);	memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);	sf->hdr.count++;	be16_add(&sf->hdr.totsize, size);	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);	xfs_sbversion_add_attr2(mp, args->trans);}/* * Remove an attribute from the shortform attribute list structure. */intxfs_attr_shortform_remove(xfs_da_args_t *args){	xfs_attr_shortform_t *sf;	xfs_attr_sf_entry_t *sfe;	int base, size=0, end, totsize, i;	xfs_mount_t *mp;	xfs_inode_t *dp;	dp = args->dp;	mp = dp->i_mount;	base = sizeof(xfs_attr_sf_hdr_t);	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;	sfe = &sf->list[0];	end = sf->hdr.count;	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),					base += size, i++) {		size = XFS_ATTR_SF_ENTSIZE(sfe);		if (sfe->namelen != args->namelen)			continue;		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)			continue;		if (!xfs_attr_namesp_match(args->flags, sfe->flags))			continue;		break;	}	if (i == end)		return(XFS_ERROR(ENOATTR));	/*	 * Fix up the attribute fork data, covering the hole	 */	end = base + size;	totsize = be16_to_cpu(sf->hdr.totsize);	if (end != totsize)		memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end);	sf->hdr.count--;	be16_add(&sf->hdr.totsize, -size);	/*	 * Fix up the start offset of the attribute fork	 */	totsize -= size;	if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname &&	    (mp->m_flags & XFS_MOUNT_ATTR2) && 	    (dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) {		/*		 * Last attribute now removed, revert to original		 * inode format making all literal area available		 * to the data fork once more.		 */		xfs_idestroy_fork(dp, XFS_ATTR_FORK);		dp->i_d.di_forkoff = 0;		dp->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;		ASSERT(dp->i_d.di_anextents == 0);		ASSERT(dp->i_afp == NULL);		dp->i_df.if_ext_max =			XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);		xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);	} else {		xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);		dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);		ASSERT(dp->i_d.di_forkoff);		ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname ||			!(mp->m_flags & XFS_MOUNT_ATTR2) ||			dp->i_d.di_format == XFS_DINODE_FMT_BTREE);		dp->i_afp->if_ext_max =			XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);		dp->i_df.if_ext_max =			XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);		xfs_trans_log_inode(args->trans, dp,					XFS_ILOG_CORE | XFS_ILOG_ADATA);	}	xfs_sbversion_add_attr2(mp, args->trans);	return(0);}/* * Look up a name in a shortform attribute list structure. *//*ARGSUSED*/intxfs_attr_shortform_lookup(xfs_da_args_t *args){	xfs_attr_shortform_t *sf;	xfs_attr_sf_entry_t *sfe;	int i;	xfs_ifork_t *ifp;	ifp = args->dp->i_afp;	ASSERT(ifp->if_flags & XFS_IFINLINE);	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;	sfe = &sf->list[0];	for (i = 0; i < sf->hdr.count;				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {		if (sfe->namelen != args->namelen)			continue;		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)			continue;		if (!xfs_attr_namesp_match(args->flags, sfe->flags))			continue;		return(XFS_ERROR(EEXIST));	}	return(XFS_ERROR(ENOATTR));}/* * Look up a name in a shortform attribute list structure. *//*ARGSUSED*/int

⌨️ 快捷键说明

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