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

📄 xfs_itable.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2000-2002,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_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_ialloc.h"#include "xfs_itable.h"#include "xfs_error.h"#include "xfs_btree.h"intxfs_internal_inum(	xfs_mount_t	*mp,	xfs_ino_t	ino){	return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||		(XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&		 (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));}STATIC intxfs_bulkstat_one_iget(	xfs_mount_t	*mp,		/* mount point for filesystem */	xfs_ino_t	ino,		/* inode number to get data for */	xfs_daddr_t	bno,		/* starting bno of inode cluster */	xfs_bstat_t	*buf,		/* return buffer */	int		*stat)		/* BULKSTAT_RV_... */{	xfs_icdinode_t	*dic;	/* dinode core info pointer */	xfs_inode_t	*ip;		/* incore inode pointer */	bhv_vnode_t	*vp;	int		error;	error = xfs_iget(mp, NULL, ino,			 XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno);	if (error) {		*stat = BULKSTAT_RV_NOTHING;		return error;	}	ASSERT(ip != NULL);	ASSERT(ip->i_blkno != (xfs_daddr_t)0);	if (ip->i_d.di_mode == 0) {		*stat = BULKSTAT_RV_NOTHING;		error = XFS_ERROR(ENOENT);		goto out_iput;	}	vp = XFS_ITOV(ip);	dic = &ip->i_d;	/* xfs_iget returns the following without needing	 * further change.	 */	buf->bs_nlink = dic->di_nlink;	buf->bs_projid = dic->di_projid;	buf->bs_ino = ino;	buf->bs_mode = dic->di_mode;	buf->bs_uid = dic->di_uid;	buf->bs_gid = dic->di_gid;	buf->bs_size = dic->di_size;	vn_atime_to_bstime(vp, &buf->bs_atime);	buf->bs_mtime.tv_sec = dic->di_mtime.t_sec;	buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec;	buf->bs_ctime.tv_sec = dic->di_ctime.t_sec;	buf->bs_ctime.tv_nsec = dic->di_ctime.t_nsec;	buf->bs_xflags = xfs_ip2xflags(ip);	buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;	buf->bs_extents = dic->di_nextents;	buf->bs_gen = dic->di_gen;	memset(buf->bs_pad, 0, sizeof(buf->bs_pad));	buf->bs_dmevmask = dic->di_dmevmask;	buf->bs_dmstate = dic->di_dmstate;	buf->bs_aextents = dic->di_anextents;	switch (dic->di_format) {	case XFS_DINODE_FMT_DEV:		buf->bs_rdev = ip->i_df.if_u2.if_rdev;		buf->bs_blksize = BLKDEV_IOSIZE;		buf->bs_blocks = 0;		break;	case XFS_DINODE_FMT_LOCAL:	case XFS_DINODE_FMT_UUID:		buf->bs_rdev = 0;		buf->bs_blksize = mp->m_sb.sb_blocksize;		buf->bs_blocks = 0;		break;	case XFS_DINODE_FMT_EXTENTS:	case XFS_DINODE_FMT_BTREE:		buf->bs_rdev = 0;		buf->bs_blksize = mp->m_sb.sb_blocksize;		buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks;		break;	} out_iput:	xfs_iput(ip, XFS_ILOCK_SHARED);	return error;}STATIC intxfs_bulkstat_one_dinode(	xfs_mount_t	*mp,		/* mount point for filesystem */	xfs_ino_t	ino,		/* inode number to get data for */	xfs_dinode_t	*dip,		/* dinode inode pointer */	xfs_bstat_t	*buf)		/* return buffer */{	xfs_dinode_core_t *dic;		/* dinode core info pointer */	dic = &dip->di_core;	/*	 * The inode format changed when we moved the link count and	 * made it 32 bits long.  If this is an old format inode,	 * convert it in memory to look like a new one.  If it gets	 * flushed to disk we will convert back before flushing or	 * logging it.  We zero out the new projid field and the old link	 * count field.  We'll handle clearing the pad field (the remains	 * of the old uuid field) when we actually convert the inode to	 * the new format. We don't change the version number so that we	 * can distinguish this from a real new format inode.	 */	if (dic->di_version == XFS_DINODE_VERSION_1) {		buf->bs_nlink = be16_to_cpu(dic->di_onlink);		buf->bs_projid = 0;	} else {		buf->bs_nlink = be32_to_cpu(dic->di_nlink);		buf->bs_projid = be16_to_cpu(dic->di_projid);	}	buf->bs_ino = ino;	buf->bs_mode = be16_to_cpu(dic->di_mode);	buf->bs_uid = be32_to_cpu(dic->di_uid);	buf->bs_gid = be32_to_cpu(dic->di_gid);	buf->bs_size = be64_to_cpu(dic->di_size);	buf->bs_atime.tv_sec = be32_to_cpu(dic->di_atime.t_sec);	buf->bs_atime.tv_nsec = be32_to_cpu(dic->di_atime.t_nsec);	buf->bs_mtime.tv_sec = be32_to_cpu(dic->di_mtime.t_sec);	buf->bs_mtime.tv_nsec = be32_to_cpu(dic->di_mtime.t_nsec);	buf->bs_ctime.tv_sec = be32_to_cpu(dic->di_ctime.t_sec);	buf->bs_ctime.tv_nsec = be32_to_cpu(dic->di_ctime.t_nsec);	buf->bs_xflags = xfs_dic2xflags(dic);	buf->bs_extsize = be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog;	buf->bs_extents = be32_to_cpu(dic->di_nextents);	buf->bs_gen = be32_to_cpu(dic->di_gen);	memset(buf->bs_pad, 0, sizeof(buf->bs_pad));	buf->bs_dmevmask = be32_to_cpu(dic->di_dmevmask);	buf->bs_dmstate = be16_to_cpu(dic->di_dmstate);	buf->bs_aextents = be16_to_cpu(dic->di_anextents);	switch (dic->di_format) {	case XFS_DINODE_FMT_DEV:		buf->bs_rdev = be32_to_cpu(dip->di_u.di_dev);		buf->bs_blksize = BLKDEV_IOSIZE;		buf->bs_blocks = 0;		break;	case XFS_DINODE_FMT_LOCAL:	case XFS_DINODE_FMT_UUID:		buf->bs_rdev = 0;		buf->bs_blksize = mp->m_sb.sb_blocksize;		buf->bs_blocks = 0;		break;	case XFS_DINODE_FMT_EXTENTS:	case XFS_DINODE_FMT_BTREE:		buf->bs_rdev = 0;		buf->bs_blksize = mp->m_sb.sb_blocksize;		buf->bs_blocks = be64_to_cpu(dic->di_nblocks);		break;	}	return 0;}STATIC intxfs_bulkstat_one_fmt(	void			__user *ubuffer,	const xfs_bstat_t	*buffer){	if (copy_to_user(ubuffer, buffer, sizeof(*buffer)))		return -EFAULT;	return sizeof(*buffer);}/* * Return stat information for one inode. * Return 0 if ok, else errno. */int		       		/* error status */xfs_bulkstat_one(	xfs_mount_t	*mp,		/* mount point for filesystem */	xfs_ino_t	ino,		/* inode number to get data for */	void		__user *buffer,	/* buffer to place output in */	int		ubsize,		/* size of buffer */	void		*private_data,	/* my private data */	xfs_daddr_t	bno,		/* starting bno of inode cluster */	int		*ubused,	/* bytes used by me */	void		*dibuff,	/* on-disk inode buffer */	int		*stat)		/* BULKSTAT_RV_... */{	xfs_bstat_t	*buf;		/* return buffer */	int		error = 0;	/* error value */	xfs_dinode_t	*dip;		/* dinode inode pointer */	bulkstat_one_fmt_pf formatter = private_data ? : xfs_bulkstat_one_fmt;	dip = (xfs_dinode_t *)dibuff;	*stat = BULKSTAT_RV_NOTHING;	if (!buffer || xfs_internal_inum(mp, ino))		return XFS_ERROR(EINVAL);	if (ubsize < sizeof(*buf))		return XFS_ERROR(ENOMEM);	buf = kmem_alloc(sizeof(*buf), KM_SLEEP);	if (dip == NULL) {		/* We're not being passed a pointer to a dinode.  This happens		 * if BULKSTAT_FG_IGET is selected.  Do the iget.		 */		error = xfs_bulkstat_one_iget(mp, ino, bno, buf, stat);		if (error)			goto out_free;	} else {		xfs_bulkstat_one_dinode(mp, ino, dip, buf);	}	error = formatter(buffer, buf);	if (error < 0)  {		error = EFAULT;		goto out_free;	}	*stat = BULKSTAT_RV_DIDONE;	if (ubused)		*ubused = error; out_free:	kmem_free(buf, sizeof(*buf));	return error;}/* * Test to see whether we can use the ondisk inode directly, based * on the given bulkstat flags, filling in dipp accordingly. * Returns zero if the inode is dodgey. */STATIC intxfs_bulkstat_use_dinode(	xfs_mount_t	*mp,	int		flags,	xfs_buf_t	*bp,	int		clustidx,	xfs_dinode_t	**dipp){	xfs_dinode_t	*dip;	unsigned int	aformat;	*dipp = NULL;	if (!bp || (flags & BULKSTAT_FG_IGET))		return 1;	dip = (xfs_dinode_t *)			xfs_buf_offset(bp, clustidx << mp->m_sb.sb_inodelog);	/*	 * Check the buffer containing the on-disk inode for di_nlink == 0.	 * This is to prevent xfs_bulkstat from picking up just reclaimed	 * inodes that have their in-core state initialized but not flushed	 * to disk yet. This is a temporary hack that would require a proper	 * fix in the future.	 */	if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC ||	    !XFS_DINODE_GOOD_VERSION(dip->di_core.di_version) ||	    !dip->di_core.di_nlink)		return 0;	if (flags & BULKSTAT_FG_QUICK) {		*dipp = dip;		return 1;	}	/* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */	aformat = dip->di_core.di_aformat;	if ((XFS_CFORK_Q(&dip->di_core) == 0) ||	    (aformat == XFS_DINODE_FMT_LOCAL) ||	    (aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_core.di_anextents)) {		*dipp = dip;		return 1;	}	return 1;}#define XFS_BULKSTAT_UBLEFT(ubleft)	((ubleft) >= statstruct_size)/* * Return stat information in bulk (by-inode) for the filesystem. */int					/* error status */xfs_bulkstat(	xfs_mount_t		*mp,	/* mount point for filesystem */	xfs_ino_t		*lastinop, /* last inode returned */	int			*ubcountp, /* size of buffer/count returned */	bulkstat_one_pf		formatter, /* func that'd fill a single buf */	void			*private_data,/* private data for formatter */	size_t			statstruct_size, /* sizeof struct filling */	char			__user *ubuffer, /* buffer with inode stats */	int			flags,	/* defined in xfs_itable.h */	int			*done)	/* 1 if there are more stats to get */{	xfs_agblock_t		agbno=0;/* allocation group block number */	xfs_buf_t		*agbp;	/* agi header buffer */	xfs_agi_t		*agi;	/* agi header data */	xfs_agino_t		agino;	/* inode # in allocation group */	xfs_agnumber_t		agno;	/* allocation group number */	xfs_daddr_t		bno;	/* inode cluster start daddr */	int			chunkidx; /* current index into inode chunk */	int			clustidx; /* current index into inode cluster */	xfs_btree_cur_t		*cur;	/* btree cursor for ialloc btree */	int			end_of_ag; /* set if we've seen the ag end */	int			error;	/* error code */	int                     fmterror;/* bulkstat formatter result */	__int32_t		gcnt;	/* current btree rec's count */	xfs_inofree_t		gfree;	/* current btree rec's free mask */	xfs_agino_t		gino;	/* current btree rec's start inode */	int			i;	/* loop index */	int			icount;	/* count of inodes good in irbuf */	size_t			irbsize; /* size of irec buffer in bytes */	xfs_ino_t		ino;	/* inode number (filesystem) */	xfs_inobt_rec_incore_t	*irbp;	/* current irec buffer pointer */	xfs_inobt_rec_incore_t	*irbuf;	/* start of irec buffer */	xfs_inobt_rec_incore_t	*irbufend; /* end of good irec buffer entries */	xfs_ino_t		lastino; /* last inode number returned */	int			nbcluster; /* # of blocks in a cluster */	int			nicluster; /* # of inodes in a cluster */	int			nimask;	/* mask for inode clusters */	int			nirbuf;	/* size of irbuf */	int			rval;	/* return value error code */	int			tmp;	/* result value from btree calls */	int			ubcount; /* size of user's buffer */	int			ubleft;	/* bytes left in user's buffer */	char			__user *ubufp;	/* pointer into user's buffer */	int			ubelem;	/* spaces used in user's buffer */	int			ubused;	/* bytes used by formatter */	xfs_buf_t		*bp;	/* ptr to on-disk inode cluster buf */	xfs_dinode_t		*dip;	/* ptr into bp for specific inode */	xfs_inode_t		*ip;	/* ptr to in-core inode struct */	/*	 * Get the last inode value, see if there's nothing to do.	 */	ino = (xfs_ino_t)*lastinop;	lastino = ino;	dip = NULL;	agno = XFS_INO_TO_AGNO(mp, ino);	agino = XFS_INO_TO_AGINO(mp, ino);	if (agno >= mp->m_sb.sb_agcount ||	    ino != XFS_AGINO_TO_INO(mp, agno, agino)) {		*done = 1;		*ubcountp = 0;		return 0;	}	if (!ubcountp || *ubcountp <= 0) {		return EINVAL;	}	ubcount = *ubcountp; /* statstruct's */	ubleft = ubcount * statstruct_size; /* bytes */	*ubcountp = ubelem = 0;	*done = 0;	fmterror = 0;	ubufp = ubuffer;	nicluster = mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp) ?		mp->m_sb.sb_inopblock :		(XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);	nimask = ~(nicluster - 1);	nbcluster = nicluster >> mp->m_sb.sb_inopblog;	irbuf = kmem_zalloc_greedy(&irbsize, NBPC, NBPC * 4,				   KM_SLEEP | KM_MAYFAIL | KM_LARGE);	nirbuf = irbsize / sizeof(*irbuf);	/*	 * Loop over the allocation groups, starting from the last	 * inode returned; 0 means start of the allocation group.	 */	rval = 0;	while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {		cond_resched();		bp = NULL;		down_read(&mp->m_peraglock);		error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);		up_read(&mp->m_peraglock);		if (error) {			/*			 * Skip this allocation group and go to the next one.			 */			agno++;			agino = 0;			continue;		}		agi = XFS_BUF_TO_AGI(agbp);		/*		 * Allocate and initialize a btree cursor for ialloc btree.		 */		cur = xfs_btree_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_INO,						(xfs_inode_t *)0, 0);		irbp = irbuf;		irbufend = irbuf + nirbuf;		end_of_ag = 0;		/*		 * If we're returning in the middle of an allocation group,		 * we need to get the remainder of the chunk we're in.		 */		if (agino > 0) {			/*			 * Lookup the inode chunk that this inode lives in.			 */			error = xfs_inobt_lookup_le(cur, agino, 0, 0, &tmp);			if (!error &&	/* no I/O error */			    tmp &&	/* lookup succeeded */					/* got the record, should always work */			    !(error = xfs_inobt_get_rec(cur, &gino, &gcnt,				    &gfree, &i)) &&			    i == 1 &&					/* this is the right chunk */			    agino < gino + XFS_INODES_PER_CHUNK &&					/* lastino was not last in chunk */			    (chunkidx = agino - gino + 1) <				    XFS_INODES_PER_CHUNK &&					/* there are some left allocated */			    XFS_INOBT_MASKN(chunkidx,				    XFS_INODES_PER_CHUNK - chunkidx) & ~gfree) {				/*				 * Grab the chunk record.  Mark all the				 * uninteresting inodes (because they're				 * before our start point) free.				 */				for (i = 0; i < chunkidx; i++) {					if (XFS_INOBT_MASK(i) & ~gfree)						gcnt++;				}				gfree |= XFS_INOBT_MASKN(0, chunkidx);

⌨️ 快捷键说明

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