xfs_inode.c

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

C
2,125
字号
/* * 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/ */#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_trans_priv.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_btree.h"#include "xfs_imap.h"#include "xfs_alloc.h"#include "xfs_ialloc.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_buf_item.h"#include "xfs_rw.h"#include "xfs_error.h"#include "xfs_bit.h"#include "xfs_utils.h"#include "xfs_dir2_trace.h"#include "xfs_quota.h"#include "xfs_mac.h"#include "xfs_acl.h"kmem_zone_t *xfs_ifork_zone;kmem_zone_t *xfs_inode_zone;kmem_zone_t *xfs_chashlist_zone;/* * Used in xfs_itruncate().  This is the maximum number of extents * freed from a file in a single transaction. */#define	XFS_ITRUNC_MAX_EXTENTS	2STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int);STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int);STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);#ifdef DEBUG/* * Make sure that the extents in the given memory buffer * are valid. */STATIC voidxfs_validate_extents(	xfs_bmbt_rec_t		*ep,	int			nrecs,	int			disk,	xfs_exntfmt_t		fmt){	xfs_bmbt_irec_t		irec;	xfs_bmbt_rec_t		rec;	int			i;	for (i = 0; i < nrecs; i++) {		rec.l0 = get_unaligned((__uint64_t*)&ep->l0);		rec.l1 = get_unaligned((__uint64_t*)&ep->l1);		if (disk)			xfs_bmbt_disk_get_all(&rec, &irec);		else			xfs_bmbt_get_all(&rec, &irec);		if (fmt == XFS_EXTFMT_NOSTATE)			ASSERT(irec.br_state == XFS_EXT_NORM);		ep++;	}}#else /* DEBUG */#define xfs_validate_extents(ep, nrecs, disk, fmt)#endif /* DEBUG *//* * Check that none of the inode's in the buffer have a next * unlinked field of 0. */#if defined(DEBUG)voidxfs_inobp_check(	xfs_mount_t	*mp,	xfs_buf_t	*bp){	int		i;	int		j;	xfs_dinode_t	*dip;	j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;	for (i = 0; i < j; i++) {		dip = (xfs_dinode_t *)xfs_buf_offset(bp,					i * mp->m_sb.sb_inodesize);		if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT))  {			xfs_fs_cmn_err(CE_ALERT, mp,				"Detected a bogus zero next_unlinked field in incore inode buffer 0x%p.  About to pop an ASSERT.",				bp);			ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT));		}	}}#endif/* * called from bwrite on xfs inode buffers */voidxfs_inobp_bwcheck(xfs_buf_t *bp){	xfs_mount_t	*mp;	int		i;	int		j;	xfs_dinode_t	*dip;	ASSERT(XFS_BUF_FSPRIVATE3(bp, void *) != NULL);	mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *);	j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;	for (i = 0; i < j; i++)  {		dip = (xfs_dinode_t *) xfs_buf_offset(bp,						i * mp->m_sb.sb_inodesize);		if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) {			cmn_err(CE_WARN,"Bad magic # 0x%x in XFS inode buffer 0x%Lx, starting blockno %Ld, offset 0x%x",				INT_GET(dip->di_core.di_magic, ARCH_CONVERT),				(__uint64_t)(__psunsigned_t) bp,				(__int64_t) XFS_BUF_ADDR(bp),				xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize));			xfs_fs_cmn_err(CE_WARN, mp,				"corrupt, unmount and run xfs_repair");		}		if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT))  {			cmn_err(CE_WARN,"Bad next_unlinked field (0) in XFS inode buffer 0x%p, starting blockno %Ld, offset 0x%x",				(__uint64_t)(__psunsigned_t) bp,				(__int64_t) XFS_BUF_ADDR(bp),				xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize));			xfs_fs_cmn_err(CE_WARN, mp,				"corrupt, unmount and run xfs_repair");		}	}	return;}/* * This routine is called to map an inode number within a file * system to the buffer containing the on-disk version of the * inode.  It returns a pointer to the buffer containing the * on-disk inode in the bpp parameter, and in the dip parameter * it returns a pointer to the on-disk inode within that buffer. * * If a non-zero error is returned, then the contents of bpp and * dipp are undefined. * * Use xfs_imap() to determine the size and location of the * buffer to read from disk. */intxfs_inotobp(	xfs_mount_t	*mp,	xfs_trans_t	*tp,	xfs_ino_t	ino,	xfs_dinode_t	**dipp,	xfs_buf_t	**bpp,	int		*offset){	int		di_ok;	xfs_imap_t	imap;	xfs_buf_t	*bp;	int		error;	xfs_dinode_t	*dip;	/*	 * Call the space managment code to find the location of the	 * inode on disk.	 */	imap.im_blkno = 0;	error = xfs_imap(mp, tp, ino, &imap, XFS_IMAP_LOOKUP);	if (error != 0) {		cmn_err(CE_WARN,	"xfs_inotobp: xfs_imap()  returned an "	"error %d on %s.  Returning error.", error, mp->m_fsname);		return error;	}	/*	 * If the inode number maps to a block outside the bounds of the	 * file system then return NULL rather than calling read_buf	 * and panicing when we get an error from the driver.	 */	if ((imap.im_blkno + imap.im_len) >	    XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {		cmn_err(CE_WARN,	"xfs_inotobp: inode number (%d + %d) maps to a block outside the bounds "	"of the file system %s.  Returning EINVAL.",			imap.im_blkno, imap.im_len,mp->m_fsname);		return XFS_ERROR(EINVAL);	}	/*	 * Read in the buffer.  If tp is NULL, xfs_trans_read_buf() will	 * default to just a read_buf() call.	 */	error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno,				   (int)imap.im_len, XFS_BUF_LOCK, &bp);	if (error) {		cmn_err(CE_WARN,	"xfs_inotobp: xfs_trans_read_buf()  returned an "	"error %d on %s.  Returning error.", error, mp->m_fsname);		return error;	}	dip = (xfs_dinode_t *)xfs_buf_offset(bp, 0);	di_ok =		INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC &&		XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT));	if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP,			XFS_RANDOM_ITOBP_INOTOBP))) {		XFS_CORRUPTION_ERROR("xfs_inotobp", XFS_ERRLEVEL_LOW, mp, dip);		xfs_trans_brelse(tp, bp);		cmn_err(CE_WARN,	"xfs_inotobp: XFS_TEST_ERROR()  returned an "	"error on %s.  Returning EFSCORRUPTED.",  mp->m_fsname);		return XFS_ERROR(EFSCORRUPTED);	}	xfs_inobp_check(mp, bp);	/*	 * Set *dipp to point to the on-disk inode in the buffer.	 */	*dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);	*bpp = bp;	*offset = imap.im_boffset;	return 0;}/* * This routine is called to map an inode to the buffer containing * the on-disk version of the inode.  It returns a pointer to the * buffer containing the on-disk inode in the bpp parameter, and in * the dip parameter it returns a pointer to the on-disk inode within * that buffer. * * If a non-zero error is returned, then the contents of bpp and * dipp are undefined. * * If the inode is new and has not yet been initialized, use xfs_imap() * to determine the size and location of the buffer to read from disk. * If the inode has already been mapped to its buffer and read in once, * then use the mapping information stored in the inode rather than * calling xfs_imap().  This allows us to avoid the overhead of looking * at the inode btree for small block file systems (see xfs_dilocate()). * We can tell whether the inode has been mapped in before by comparing * its disk block address to 0.  Only uninitialized inodes will have * 0 for the disk block address. */intxfs_itobp(	xfs_mount_t	*mp,	xfs_trans_t	*tp,	xfs_inode_t	*ip,	xfs_dinode_t	**dipp,	xfs_buf_t	**bpp,	xfs_daddr_t	bno){	xfs_buf_t	*bp;	int		error;	xfs_imap_t	imap;#ifdef __KERNEL__	int		i;	int		ni;#endif	if (ip->i_blkno == (xfs_daddr_t)0) {		/*		 * Call the space management code to find the location of the		 * inode on disk.		 */		imap.im_blkno = bno;		error = xfs_imap(mp, tp, ip->i_ino, &imap, XFS_IMAP_LOOKUP);		if (error != 0) {			return error;		}		/*		 * If the inode number maps to a block outside the bounds		 * of the file system then return NULL rather than calling		 * read_buf and panicing when we get an error from the		 * driver.		 */		if ((imap.im_blkno + imap.im_len) >		    XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {#ifdef DEBUG			xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: "					"(imap.im_blkno (0x%llx) "					"+ imap.im_len (0x%llx)) > "					" XFS_FSB_TO_BB(mp, "					"mp->m_sb.sb_dblocks) (0x%llx)",					(unsigned long long) imap.im_blkno,					(unsigned long long) imap.im_len,					XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));#endif /* DEBUG */			return XFS_ERROR(EINVAL);		}		/*		 * Fill in the fields in the inode that will be used to		 * map the inode to its buffer from now on.		 */		ip->i_blkno = imap.im_blkno;		ip->i_len = imap.im_len;		ip->i_boffset = imap.im_boffset;	} else {		/*		 * We've already mapped the inode once, so just use the		 * mapping that we saved the first time.		 */		imap.im_blkno = ip->i_blkno;		imap.im_len = ip->i_len;		imap.im_boffset = ip->i_boffset;	}	ASSERT(bno == 0 || bno == imap.im_blkno);	/*	 * Read in the buffer.  If tp is NULL, xfs_trans_read_buf() will	 * default to just a read_buf() call.	 */	error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno,				   (int)imap.im_len, XFS_BUF_LOCK, &bp);	if (error) {#ifdef DEBUG		xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: "				"xfs_trans_read_buf() returned error %d, "				"imap.im_blkno 0x%llx, imap.im_len 0x%llx",				error, (unsigned long long) imap.im_blkno,				(unsigned long long) imap.im_len);#endif /* DEBUG */		return error;	}#ifdef __KERNEL__	/*	 * Validate the magic number and version of every inode in the buffer	 * (if DEBUG kernel) or the first inode in the buffer, otherwise.	 */#ifdef DEBUG	ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog;#else	ni = 1;#endif	for (i = 0; i < ni; i++) {		int		di_ok;		xfs_dinode_t	*dip;		dip = (xfs_dinode_t *)xfs_buf_offset(bp,					(i << mp->m_sb.sb_inodelog));		di_ok = INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC &&			    XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT));		if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP,				 XFS_RANDOM_ITOBP_INOTOBP))) {#ifdef DEBUG			prdev("bad inode magic/vsn daddr %lld #%d (magic=%x)",				mp->m_ddev_targp,				(unsigned long long)imap.im_blkno, i,				INT_GET(dip->di_core.di_magic, ARCH_CONVERT));#endif			XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_HIGH,					     mp, dip);			xfs_trans_brelse(tp, bp);			return XFS_ERROR(EFSCORRUPTED);		}	}#endif	/* __KERNEL__ */	xfs_inobp_check(mp, bp);

⌨️ 快捷键说明

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