xfs_attr.c

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

C
2,474
字号
/* * Copyright (c) 2000-2004 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/ */#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"#include "xfs_quota.h"#include "xfs_rw.h"#include "xfs_trans_space.h"#include "xfs_acl.h"/* * xfs_attr.c * * Provide the external interfaces to manage attribute lists. *//*======================================================================== * Function prototypes for the kernel. *========================================================================*//* * Internal routines when attribute list fits inside the inode. */STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);/* * Internal routines when attribute list is one block. */STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context);/* * Internal routines when attribute list is more than one block. */STATIC int xfs_attr_node_addname(xfs_da_args_t *args);STATIC int xfs_attr_node_removename(xfs_da_args_t *args);STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context);STATIC int xfs_attr_fillstate(xfs_da_state_t *state);STATIC int xfs_attr_refillstate(xfs_da_state_t *state);/* * Routines to manipulate out-of-line attribute values. */STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);#define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */#if defined(XFS_ATTR_TRACE)ktrace_t *xfs_attr_trace_buf;#endif/*======================================================================== * Overall external interface routines. *========================================================================*/intxfs_attr_fetch(xfs_inode_t *ip, char *name, int namelen,	       char *value, int *valuelenp, int flags, struct cred *cred){	xfs_da_args_t   args;	int             error;	if ((XFS_IFORK_Q(ip) == 0) ||	    (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&	     ip->i_d.di_anextents == 0))		return(ENOATTR);	if (!(flags & (ATTR_KERNACCESS|ATTR_SECURE))) {		if ((error = xfs_iaccess(ip, S_IRUSR, cred)))			return(XFS_ERROR(error));	}	/*	 * Fill in the arg structure for this request.	 */	memset((char *)&args, 0, sizeof(args));	args.name = name;	args.namelen = namelen;	args.value = value;	args.valuelen = *valuelenp;	args.flags = flags;	args.hashval = xfs_da_hashname(args.name, args.namelen);	args.dp = ip;	args.whichfork = XFS_ATTR_FORK;	/*	 * Decide on what work routines to call based on the inode size.	 */	if (XFS_IFORK_Q(ip) == 0 ||	    (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&	     ip->i_d.di_anextents == 0)) {		error = XFS_ERROR(ENOATTR);	} else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {		error = xfs_attr_shortform_getvalue(&args);	} else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {		error = xfs_attr_leaf_get(&args);	} else {		error = xfs_attr_node_get(&args);	}	/*	 * Return the number of bytes in the value to the caller.	 */	*valuelenp = args.valuelen;	if (error == EEXIST)		error = 0;	return(error);}intxfs_attr_get(bhv_desc_t *bdp, char *name, char *value, int *valuelenp,	     int flags, struct cred *cred){	xfs_inode_t	*ip = XFS_BHVTOI(bdp);	int		error, namelen;	XFS_STATS_INC(xs_attr_get);	if (!name)		return(EINVAL);	namelen = strlen(name);	if (namelen >= MAXNAMELEN)		return(EFAULT);		/* match IRIX behaviour */	if (XFS_FORCED_SHUTDOWN(ip->i_mount))		return(EIO);	xfs_ilock(ip, XFS_ILOCK_SHARED);	error = xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred);	xfs_iunlock(ip, XFS_ILOCK_SHARED);	return(error);}/*ARGSUSED*/int								/* error */xfs_attr_set(bhv_desc_t *bdp, char *name, char *value, int valuelen, int flags,		     struct cred *cred){	xfs_da_args_t	args;	xfs_inode_t	*dp;	xfs_fsblock_t	firstblock;	xfs_bmap_free_t flist;	int		error, err2, committed;	int		local, size;	uint		nblks;	xfs_mount_t	*mp;	int             rsvd = (flags & ATTR_ROOT) != 0;	int             namelen;	namelen = strlen(name);	if (namelen >= MAXNAMELEN)		return EFAULT;		/* match IRIX behaviour */	XFS_STATS_INC(xs_attr_set);	dp = XFS_BHVTOI(bdp);	mp = dp->i_mount;	if (XFS_FORCED_SHUTDOWN(mp))		return (EIO);	xfs_ilock(dp, XFS_ILOCK_SHARED);	if (!(flags & ATTR_SECURE) &&	     (error = xfs_iaccess(dp, S_IWUSR, cred))) {		xfs_iunlock(dp, XFS_ILOCK_SHARED);		return(XFS_ERROR(error));	}	xfs_iunlock(dp, XFS_ILOCK_SHARED);	/*	 * Attach the dquots to the inode.	 */	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))		return (error);	/*	 * If the inode doesn't have an attribute fork, add one.	 * (inode must not be locked when we call this routine)	 */	if (XFS_IFORK_Q(dp) == 0) {		error = xfs_bmap_add_attrfork(dp, rsvd);		if (error)			return(error);	}	/*	 * Fill in the arg structure for this request.	 */	memset((char *)&args, 0, sizeof(args));	args.name = name;	args.namelen = namelen;	args.value = value;	args.valuelen = valuelen;	args.flags = flags;	args.hashval = xfs_da_hashname(args.name, args.namelen);	args.dp = dp;	args.firstblock = &firstblock;	args.flist = &flist;	args.whichfork = XFS_ATTR_FORK;	args.oknoent = 1;	/* Determine space new attribute will use, and if it will be inline	 * or out of line.	 */	size = xfs_attr_leaf_newentsize(&args, mp->m_sb.sb_blocksize, &local);	nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);	if (local) {		if (size > (mp->m_sb.sb_blocksize >> 1)) {			/* Double split possible */			nblks <<= 1;		}	} else {		uint	dblocks = XFS_B_TO_FSB(mp, valuelen);		/* Out of line attribute, cannot double split, but make		 * room for the attribute value itself.		 */		nblks += dblocks;		nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);	}	/* Size is now blocks for attribute data */	args.total = nblks;	/*	 * Start our first transaction of the day.	 *	 * All future transactions during this code must be "chained" off	 * this one via the trans_dup() call.  All transactions will contain	 * the inode, and the inode will always be marked with trans_ihold().	 * Since the inode will be locked in all transactions, we must log	 * the inode in every transaction to let it float upward through	 * the log.	 */	args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET);	/*	 * Root fork attributes can use reserved data blocks for this	 * operation if necessary	 */	if (rsvd)		args.trans->t_flags |= XFS_TRANS_RESERVE;	if ((error = xfs_trans_reserve(args.trans, (uint) nblks,				      XFS_ATTRSET_LOG_RES(mp, nblks),				      0, XFS_TRANS_PERM_LOG_RES,				      XFS_ATTRSET_LOG_COUNT))) {		xfs_trans_cancel(args.trans, 0);		return(error);	}	xfs_ilock(dp, XFS_ILOCK_EXCL);	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0,			 rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :				XFS_QMOPT_RES_REGBLKS);	if (error) {		xfs_iunlock(dp, XFS_ILOCK_EXCL);		xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);		return (error);	}	xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);	xfs_trans_ihold(args.trans, dp);	/*	 * If the attribute list is non-existant or a shortform list,	 * upgrade it to a single-leaf-block attribute list.	 */	if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||	    ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&	     (dp->i_d.di_anextents == 0))) {		/*		 * Build initial attribute list (if required).		 */		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)			(void)xfs_attr_shortform_create(&args);		/*		 * Try to add the attr to the attribute list in		 * the inode.		 */		error = xfs_attr_shortform_addname(&args);		if (error != ENOSPC) {			/*			 * Commit the shortform mods, and we're done.			 * NOTE: this is also the error path (EEXIST, etc).			 */			ASSERT(args.trans != NULL);			/*			 * If this is a synchronous mount, make sure that			 * the transaction goes to disk before returning			 * to the user.			 */			if (mp->m_flags & XFS_MOUNT_WSYNC) {				xfs_trans_set_sync(args.trans);			}			err2 = xfs_trans_commit(args.trans,						 XFS_TRANS_RELEASE_LOG_RES,						 NULL);			xfs_iunlock(dp, XFS_ILOCK_EXCL);			/*			 * Hit the inode change time.			 */			if (!error && (flags & ATTR_KERNOTIME) == 0) {				xfs_ichgtime(dp, XFS_ICHGTIME_CHG);			}			return(error == 0 ? err2 : error);		}		/*		 * It won't fit in the shortform, transform to a leaf block.		 * GROT: another possible req'mt for a double-split btree op.		 */		XFS_BMAP_INIT(args.flist, args.firstblock);		error = xfs_attr_shortform_to_leaf(&args);		if (!error) {			error = xfs_bmap_finish(&args.trans, args.flist,						*args.firstblock, &committed);		}		if (error) {			ASSERT(committed);			args.trans = NULL;			xfs_bmap_cancel(&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 leaf transformation.  We'll need another (linked)		 * transaction to add the new attribute to the leaf.		 */		if ((error = xfs_attr_rolltrans(&args.trans, dp)))			goto out;	}	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {		error = xfs_attr_leaf_addname(&args);	} else {		error = xfs_attr_node_addname(&args);	}	if (error) {		goto out;	}	/*	 * If this is a synchronous mount, make sure that the	 * transaction goes to disk before returning to the user.	 */	if (mp->m_flags & XFS_MOUNT_WSYNC) {		xfs_trans_set_sync(args.trans);	}	/*	 * Commit the last in the sequence of transactions.	 */	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,				 NULL);	xfs_iunlock(dp, XFS_ILOCK_EXCL);	/*	 * Hit the inode change time.	 */	if (!error && (flags & ATTR_KERNOTIME) == 0) {		xfs_ichgtime(dp, XFS_ICHGTIME_CHG);	}	return(error);out:	if (args.trans)		xfs_trans_cancel(args.trans,			XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);	xfs_iunlock(dp, XFS_ILOCK_EXCL);	return(error);}/* * Generic handler routine to remove a name from an attribute list. * Transitions attribute list from Btree to shortform as necessary. *//*ARGSUSED*/int								/* error */xfs_attr_remove(bhv_desc_t *bdp, char *name, int flags, struct cred *cred){	xfs_da_args_t       args;	xfs_inode_t         *dp;	xfs_fsblock_t       firstblock;	xfs_bmap_free_t     flist;	int                 error;	xfs_mount_t         *mp;	int                 namelen;	ASSERT(MAXNAMELEN-1<=0xff); /* length is stored in uint8 */	namelen = strlen(name);	if (namelen>=MAXNAMELEN)		return EFAULT; /* match irix behaviour */	XFS_STATS_INC(xs_attr_remove);	dp = XFS_BHVTOI(bdp);	mp = dp->i_mount;	if (XFS_FORCED_SHUTDOWN(mp))		return (EIO);	xfs_ilock(dp, XFS_ILOCK_SHARED);	if (!(flags & ATTR_SECURE) &&	     (error = xfs_iaccess(dp, S_IWUSR, cred))) {		xfs_iunlock(dp, XFS_ILOCK_SHARED);		return(XFS_ERROR(error));	} else if (XFS_IFORK_Q(dp) == 0 ||		   (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&		    dp->i_d.di_anextents == 0)) {		xfs_iunlock(dp, XFS_ILOCK_SHARED);		return(XFS_ERROR(ENOATTR));	}	xfs_iunlock(dp, XFS_ILOCK_SHARED);	/*	 * Fill in the arg structure for this request.	 */

⌨️ 快捷键说明

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