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

📄 xfs_inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2000-2006 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_imap.h"#include "xfs_trans.h"#include "xfs_trans_priv.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_buf_item.h"#include "xfs_inode_item.h"#include "xfs_btree.h"#include "xfs_alloc.h"#include "xfs_ialloc.h"#include "xfs_bmap.h"#include "xfs_rw.h"#include "xfs_error.h"#include "xfs_utils.h"#include "xfs_dir2_trace.h"#include "xfs_quota.h"#include "xfs_acl.h"#include "xfs_filestream.h"#include "xfs_vnodeops.h"kmem_zone_t *xfs_ifork_zone;kmem_zone_t *xfs_inode_zone;kmem_zone_t *xfs_icluster_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_ifork_t		*ifp,	int			nrecs,	xfs_exntfmt_t		fmt){	xfs_bmbt_irec_t		irec;	xfs_bmbt_rec_host_t	rec;	int			i;	for (i = 0; i < nrecs; i++) {		xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);		rec.l0 = get_unaligned(&ep->l0);		rec.l1 = get_unaligned(&ep->l1);		xfs_bmbt_get_all(&rec, &irec);		if (fmt == XFS_EXTFMT_NOSTATE)			ASSERT(irec.br_state == XFS_EXT_NORM);	}}#else /* DEBUG */#define xfs_validate_extents(ifp, nrecs, 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 (!dip->di_next_unlinked)  {			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(dip->di_next_unlinked);		}	}}#endif/* * 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. */STATIC 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 management 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 (%llu + %d) maps to a block outside the bounds "	"of the file system %s.  Returning EINVAL.",			(unsigned long long)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 =		be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&		XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);	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,	uint		imap_flags){	xfs_imap_t	imap;	xfs_buf_t	*bp;	int		error;	int		i;	int		ni;	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;		if ((error = xfs_imap(mp, tp, ip->i_ino, &imap,					XFS_IMAP_LOOKUP | imap_flags)))			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;	}	/*	 * Validate the magic number and version of every inode in the buffer	 * (if DEBUG kernel) or the first inode in the buffer, otherwise.	 * No validation is done here in userspace (xfs_repair).	 */#if !defined(__KERNEL__)	ni = 0;#elif defined(DEBUG)	ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog;#else	/* usual case */	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 = be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&			    XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);		if (unlikely(XFS_TEST_ERROR(!di_ok, mp,						XFS_ERRTAG_ITOBP_INOTOBP,						XFS_RANDOM_ITOBP_INOTOBP))) {			if (imap_flags & XFS_IMAP_BULKSTAT) {				xfs_trans_brelse(tp, bp);				return XFS_ERROR(EINVAL);			}#ifdef DEBUG			cmn_err(CE_ALERT,					"Device %s - bad inode magic/vsn "					"daddr %lld #%d (magic=%x)",				XFS_BUFTARG_NAME(mp->m_ddev_targp),				(unsigned long long)imap.im_blkno, i,				be16_to_cpu(dip->di_core.di_magic));#endif			XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_HIGH,					     mp, dip);			xfs_trans_brelse(tp, bp);			return XFS_ERROR(EFSCORRUPTED);		}	}	xfs_inobp_check(mp, bp);	/*	 * Mark the buffer as an inode buffer now that it looks good	 */	XFS_BUF_SET_VTYPE(bp, B_FS_INO);	/*	 * 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;	return 0;}/* * Move inode type and inode format specific information from the * on-disk inode to the in-core inode.  For fifos, devs, and sockets * this means set if_rdev to the proper value.  For files, directories, * and symlinks this means to bring in the in-line data or extent * pointers.  For a file in B-tree format, only the root is immediately * brought in-core.  The rest will be in-lined in if_extents when it * is first referenced (see xfs_iread_extents()). */STATIC intxfs_iformat(	xfs_inode_t		*ip,	xfs_dinode_t		*dip){	xfs_attr_shortform_t	*atp;	int			size;	int			error;	xfs_fsize_t             di_size;	ip->i_df.if_ext_max =		XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);	error = 0;	if (unlikely(be32_to_cpu(dip->di_core.di_nextents) +		     be16_to_cpu(dip->di_core.di_anextents) >		     be64_to_cpu(dip->di_core.di_nblocks))) {		xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,			"corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",			(unsigned long long)ip->i_ino,			(int)(be32_to_cpu(dip->di_core.di_nextents) +			      be16_to_cpu(dip->di_core.di_anextents)),			(unsigned long long)				be64_to_cpu(dip->di_core.di_nblocks));		XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW,				     ip->i_mount, dip);		return XFS_ERROR(EFSCORRUPTED);	}	if (unlikely(dip->di_core.di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {		xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,			"corrupt dinode %Lu, forkoff = 0x%x.",			(unsigned long long)ip->i_ino,			dip->di_core.di_forkoff);		XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,				     ip->i_mount, dip);		return XFS_ERROR(EFSCORRUPTED);	}	switch (ip->i_d.di_mode & S_IFMT) {

⌨️ 快捷键说明

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