xfs_attr_leaf.c

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

C
2,154
字号
/* * Copyright (c) 2000-2003 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_attr_leaf.c * * GROT: figure out how to recover gracefully when bmap returns ENOSPC. */#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_ialloc_btree.h"#include "xfs_alloc.h"#include "xfs_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_attr.h"#include "xfs_attr_leaf.h"#include "xfs_error.h"#include "xfs_bit.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_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);/* * 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);/*======================================================================== * External routines when dirsize < XFS_LITINO(mp). *========================================================================*//* * Create the initial contents of a shortform attribute list. */intxfs_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;	INT_ZERO(hdr->count, ARCH_CONVERT);	INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr));	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);	return(0);}/* * Add a name/value pair to the shortform attribute list. * Overflow from the inode has already been checked for. */intxfs_attr_shortform_add(xfs_da_args_t *args){	xfs_attr_shortform_t *sf;	xfs_attr_sf_entry_t *sfe;	int i, offset, size;	xfs_inode_t *dp;	xfs_ifork_t *ifp;	dp = args->dp;	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 < INT_GET(sf->hdr.count, ARCH_CONVERT);				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {		if (sfe->namelen != args->namelen)			continue;		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)			continue;		if (((args->flags & ATTR_SECURE) != 0) !=		    ((sfe->flags & XFS_ATTR_SECURE) != 0))			continue;		if (((args->flags & ATTR_ROOT) != 0) !=		    ((sfe->flags & XFS_ATTR_ROOT) != 0))			continue;		return(XFS_ERROR(EEXIST));	}	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;	INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen);	sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :			((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);	memcpy(sfe->nameval, args->name, args->namelen);	memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);	INT_MOD(sf->hdr.count, ARCH_CONVERT, 1);	INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size);	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);	return(0);}/* * Remove a name 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_inode_t *dp;	/*	 * Remove the attribute.	 */	dp = args->dp;	base = sizeof(xfs_attr_sf_hdr_t);	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;	sfe = &sf->list[0];	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);				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 (((args->flags & ATTR_SECURE) != 0) !=		    ((sfe->flags & XFS_ATTR_SECURE) != 0))			continue;		if (((args->flags & ATTR_ROOT) != 0) !=		    ((sfe->flags & XFS_ATTR_ROOT) != 0))			continue;		break;	}	if (i == INT_GET(sf->hdr.count, ARCH_CONVERT))		return(XFS_ERROR(ENOATTR));	end = base + size;	totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT);	if (end != totsize) {		memmove(&((char *)sf)[base], &((char *)sf)[end],							totsize - end);	}	INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);	INT_MOD(sf->hdr.totsize, ARCH_CONVERT, -size);	xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);	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 < INT_GET(sf->hdr.count, ARCH_CONVERT);				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {		if (sfe->namelen != args->namelen)			continue;		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)			continue;		if (((args->flags & ATTR_SECURE) != 0) !=		    ((sfe->flags & XFS_ATTR_SECURE) != 0))			continue;		if (((args->flags & ATTR_ROOT) != 0) !=		    ((sfe->flags & XFS_ATTR_ROOT) != 0))			continue;		return(XFS_ERROR(EEXIST));	}	return(XFS_ERROR(ENOATTR));}/* * Look up a name in a shortform attribute list structure. *//*ARGSUSED*/intxfs_attr_shortform_getvalue(xfs_da_args_t *args){	xfs_attr_shortform_t *sf;	xfs_attr_sf_entry_t *sfe;	int i;	ASSERT(args->dp->i_d.di_aformat == XFS_IFINLINE);	sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data;	sfe = &sf->list[0];	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {		if (sfe->namelen != args->namelen)			continue;		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)			continue;		if (((args->flags & ATTR_SECURE) != 0) !=		    ((sfe->flags & XFS_ATTR_SECURE) != 0))			continue;		if (((args->flags & ATTR_ROOT) != 0) !=		    ((sfe->flags & XFS_ATTR_ROOT) != 0))			continue;		if (args->flags & ATTR_KERNOVAL) {			args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);			return(XFS_ERROR(EEXIST));		}		if (args->valuelen < INT_GET(sfe->valuelen, ARCH_CONVERT)) {			args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);			return(XFS_ERROR(ERANGE));		}		args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);		memcpy(args->value, &sfe->nameval[args->namelen],						    args->valuelen);		return(XFS_ERROR(EEXIST));	}	return(XFS_ERROR(ENOATTR));}/* * Convert from using the shortform to the leaf. */intxfs_attr_shortform_to_leaf(xfs_da_args_t *args){	xfs_inode_t *dp;	xfs_attr_shortform_t *sf;	xfs_attr_sf_entry_t *sfe;	xfs_da_args_t nargs;	char *tmpbuffer;	int error, i, size;	xfs_dablk_t blkno;	xfs_dabuf_t *bp;	xfs_ifork_t *ifp;	dp = args->dp;	ifp = dp->i_afp;	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;	size = INT_GET(sf->hdr.totsize, ARCH_CONVERT);	tmpbuffer = kmem_alloc(size, KM_SLEEP);	ASSERT(tmpbuffer != NULL);	memcpy(tmpbuffer, ifp->if_u1.if_data, size);	sf = (xfs_attr_shortform_t *)tmpbuffer;	xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);	bp = NULL;	error = xfs_da_grow_inode(args, &blkno);	if (error) {		/*		 * If we hit an IO error middle of the transaction inside		 * grow_inode(), we may have inconsistent data. Bail out.		 */		if (error == EIO)			goto out;		xfs_idata_realloc(dp, size, XFS_ATTR_FORK);	/* try to put */		memcpy(ifp->if_u1.if_data, tmpbuffer, size);	/* it back */		goto out;	}	ASSERT(blkno == 0);	error = xfs_attr_leaf_create(args, blkno, &bp);	if (error) {		error = xfs_da_shrink_inode(args, 0, bp);		bp = NULL;		if (error)			goto out;		xfs_idata_realloc(dp, size, XFS_ATTR_FORK);	/* try to put */		memcpy(ifp->if_u1.if_data, tmpbuffer, size);	/* it back */		goto out;	}	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;	sfe = &sf->list[0];	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {		nargs.name = (char *)sfe->nameval;		nargs.namelen = sfe->namelen;		nargs.value = (char *)&sfe->nameval[nargs.namelen];		nargs.valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);		nargs.hashval = xfs_da_hashname((char *)sfe->nameval,						sfe->namelen);		nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :				((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);		error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */		ASSERT(error == ENOATTR);		error = xfs_attr_leaf_add(bp, &nargs);		ASSERT(error != ENOSPC);		if (error)			goto out;		sfe = XFS_ATTR_SF_NEXTENTRY(sfe);	}	error = 0;out:	if(bp)		xfs_da_buf_done(bp);	kmem_free(tmpbuffer, size);	return(error);}STATIC intxfs_attr_shortform_compare(const void *a, const void *b){	xfs_attr_sf_sort_t *sa, *sb;	sa = (xfs_attr_sf_sort_t *)a;	sb = (xfs_attr_sf_sort_t *)b;	if (INT_GET(sa->hash, ARCH_CONVERT)				< INT_GET(sb->hash, ARCH_CONVERT)) {		return(-1);	} else if (INT_GET(sa->hash, ARCH_CONVERT)				> INT_GET(sb->hash, ARCH_CONVERT)) {		return(1);	} else {		return(sa->entno - sb->entno);	}}/* * Copy out entries of shortform attribute lists for attr_list(). * Shortform atrtribute lists are not stored in hashval sorted order. * If the output buffer is not large enough to hold them all, then we * we have to calculate each entries' hashvalue and sort them before * we can begin returning them to the user. *//*ARGSUSED*/intxfs_attr_shortform_list(xfs_attr_list_context_t *context)

⌨️ 快捷键说明

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