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

📄 xfs_inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	xfs_buf_t	*bp;	xfs_dinode_t	*dip;	xfs_inode_t	*ip;	int		error;	ASSERT(xfs_inode_zone != NULL);	ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP);	ip->i_ino = ino;	ip->i_mount = mp;	atomic_set(&ip->i_iocount, 0);	spin_lock_init(&ip->i_flags_lock);	/*	 * Get pointer's to the on-disk inode and the buffer containing it.	 * If the inode number refers to a block outside the file system	 * then xfs_itobp() will return NULL.  In this case we should	 * return NULL as well.  Set i_blkno to 0 so that xfs_itobp() will	 * know that this is a new incore inode.	 */	error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, imap_flags);	if (error) {		kmem_zone_free(xfs_inode_zone, ip);		return error;	}	/*	 * Initialize inode's trace buffers.	 * Do this before xfs_iformat in case it adds entries.	 */#ifdef	XFS_VNODE_TRACE	ip->i_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_BMAP_TRACE	ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_BMBT_TRACE	ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_RW_TRACE	ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_ILOCK_TRACE	ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_DIR2_TRACE	ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_SLEEP);#endif	/*	 * If we got something that isn't an inode it means someone	 * (nfs or dmi) has a stale handle.	 */	if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC) {		kmem_zone_free(xfs_inode_zone, ip);		xfs_trans_brelse(tp, bp);#ifdef DEBUG		xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "				"dip->di_core.di_magic (0x%x) != "				"XFS_DINODE_MAGIC (0x%x)",				be16_to_cpu(dip->di_core.di_magic),				XFS_DINODE_MAGIC);#endif /* DEBUG */		return XFS_ERROR(EINVAL);	}	/*	 * If the on-disk inode is already linked to a directory	 * entry, copy all of the inode into the in-core inode.	 * xfs_iformat() handles copying in the inode format	 * specific information.	 * Otherwise, just get the truly permanent information.	 */	if (dip->di_core.di_mode) {		xfs_dinode_from_disk(&ip->i_d, &dip->di_core);		error = xfs_iformat(ip, dip);		if (error)  {			kmem_zone_free(xfs_inode_zone, ip);			xfs_trans_brelse(tp, bp);#ifdef DEBUG			xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "					"xfs_iformat() returned error %d",					error);#endif /* DEBUG */			return error;		}	} else {		ip->i_d.di_magic = be16_to_cpu(dip->di_core.di_magic);		ip->i_d.di_version = dip->di_core.di_version;		ip->i_d.di_gen = be32_to_cpu(dip->di_core.di_gen);		ip->i_d.di_flushiter = be16_to_cpu(dip->di_core.di_flushiter);		/*		 * Make sure to pull in the mode here as well in		 * case the inode is released without being used.		 * This ensures that xfs_inactive() will see that		 * the inode is already free and not try to mess		 * with the uninitialized part of it.		 */		ip->i_d.di_mode = 0;		/*		 * Initialize the per-fork minima and maxima for a new		 * inode here.  xfs_iformat will do it for old inodes.		 */		ip->i_df.if_ext_max =			XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);	}	INIT_LIST_HEAD(&ip->i_reclaim);	/*	 * 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 (ip->i_d.di_version == XFS_DINODE_VERSION_1) {		ip->i_d.di_nlink = ip->i_d.di_onlink;		ip->i_d.di_onlink = 0;		ip->i_d.di_projid = 0;	}	ip->i_delayed_blks = 0;	ip->i_size = ip->i_d.di_size;	/*	 * Mark the buffer containing the inode as something to keep	 * around for a while.  This helps to keep recently accessed	 * meta-data in-core longer.	 */	 XFS_BUF_SET_REF(bp, XFS_INO_REF);	/*	 * Use xfs_trans_brelse() to release the buffer containing the	 * on-disk inode, because it was acquired with xfs_trans_read_buf()	 * in xfs_itobp() above.  If tp is NULL, this is just a normal	 * brelse().  If we're within a transaction, then xfs_trans_brelse()	 * will only release the buffer if it is not dirty within the	 * transaction.  It will be OK to release the buffer in this case,	 * because inodes on disk are never destroyed and we will be	 * locking the new in-core inode before putting it in the hash	 * table where other processes can find it.  Thus we don't have	 * to worry about the inode being changed just because we released	 * the buffer.	 */	xfs_trans_brelse(tp, bp);	*ipp = ip;	return 0;}/* * Read in extents from a btree-format inode. * Allocate and fill in if_extents.  Real work is done in xfs_bmap.c. */intxfs_iread_extents(	xfs_trans_t	*tp,	xfs_inode_t	*ip,	int		whichfork){	int		error;	xfs_ifork_t	*ifp;	xfs_extnum_t	nextents;	size_t		size;	if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {		XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW,				 ip->i_mount);		return XFS_ERROR(EFSCORRUPTED);	}	nextents = XFS_IFORK_NEXTENTS(ip, whichfork);	size = nextents * sizeof(xfs_bmbt_rec_t);	ifp = XFS_IFORK_PTR(ip, whichfork);	/*	 * We know that the size is valid (it's checked in iformat_btree)	 */	ifp->if_lastex = NULLEXTNUM;	ifp->if_bytes = ifp->if_real_bytes = 0;	ifp->if_flags |= XFS_IFEXTENTS;	xfs_iext_add(ifp, 0, nextents);	error = xfs_bmap_read_extents(tp, ip, whichfork);	if (error) {		xfs_iext_destroy(ifp);		ifp->if_flags &= ~XFS_IFEXTENTS;		return error;	}	xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip));	return 0;}/* * Allocate an inode on disk and return a copy of its in-core version. * The in-core inode is locked exclusively.  Set mode, nlink, and rdev * appropriately within the inode.  The uid and gid for the inode are * set according to the contents of the given cred structure. * * Use xfs_dialloc() to allocate the on-disk inode. If xfs_dialloc() * has a free inode available, call xfs_iget() * to obtain the in-core version of the allocated inode.  Finally, * fill in the inode and log its initial contents.  In this case, * ialloc_context would be set to NULL and call_again set to false. * * If xfs_dialloc() does not have an available inode, * it will replenish its supply by doing an allocation. Since we can * only do one allocation within a transaction without deadlocks, we * must commit the current transaction before returning the inode itself. * In this case, therefore, we will set call_again to true and return. * The caller should then commit the current transaction, start a new * transaction, and call xfs_ialloc() again to actually get the inode. * * To ensure that some other process does not grab the inode that * was allocated during the first call to xfs_ialloc(), this routine * also returns the [locked] bp pointing to the head of the freelist * as ialloc_context.  The caller should hold this buffer across * the commit and pass it back into this routine on the second call. * * If we are allocating quota inodes, we do not have a parent inode * to attach to or associate with (i.e. pip == NULL) because they * are not linked into the directory structure - they are attached * directly to the superblock - and so have no parent. */intxfs_ialloc(	xfs_trans_t	*tp,	xfs_inode_t	*pip,	mode_t		mode,	xfs_nlink_t	nlink,	xfs_dev_t	rdev,	cred_t		*cr,	xfs_prid_t	prid,	int		okalloc,	xfs_buf_t	**ialloc_context,	boolean_t	*call_again,	xfs_inode_t	**ipp){	xfs_ino_t	ino;	xfs_inode_t	*ip;	bhv_vnode_t	*vp;	uint		flags;	int		error;	/*	 * Call the space management code to pick	 * the on-disk inode to be allocated.	 */	error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,			    ialloc_context, call_again, &ino);	if (error != 0) {		return error;	}	if (*call_again || ino == NULLFSINO) {		*ipp = NULL;		return 0;	}	ASSERT(*ialloc_context == NULL);	/*	 * Get the in-core inode with the lock held exclusively.	 * This is because we're setting fields here we need	 * to prevent others from looking at until we're done.	 */	error = xfs_trans_iget(tp->t_mountp, tp, ino,				XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip);	if (error != 0) {		return error;	}	ASSERT(ip != NULL);	vp = XFS_ITOV(ip);	ip->i_d.di_mode = (__uint16_t)mode;	ip->i_d.di_onlink = 0;	ip->i_d.di_nlink = nlink;	ASSERT(ip->i_d.di_nlink == nlink);	ip->i_d.di_uid = current_fsuid(cr);	ip->i_d.di_gid = current_fsgid(cr);	ip->i_d.di_projid = prid;	memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));	/*	 * If the superblock version is up to where we support new format	 * inodes and this is currently an old format inode, then change	 * the inode version number now.  This way we only do the conversion	 * here rather than here and in the flush/logging code.	 */	if (XFS_SB_VERSION_HASNLINK(&tp->t_mountp->m_sb) &&	    ip->i_d.di_version == XFS_DINODE_VERSION_1) {		ip->i_d.di_version = XFS_DINODE_VERSION_2;		/*		 * We've already zeroed the old link count, the projid field,		 * and the pad field.		 */	}	/*	 * Project ids won't be stored on disk if we are using a version 1 inode.	 */	if ((prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1))		xfs_bump_ino_vers2(tp, ip);	if (pip && XFS_INHERIT_GID(pip)) {		ip->i_d.di_gid = pip->i_d.di_gid;		if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) {			ip->i_d.di_mode |= S_ISGID;		}	}	/*	 * If the group ID of the new file does not match the effective group	 * ID or one of the supplementary group IDs, the S_ISGID bit is cleared	 * (and only if the irix_sgid_inherit compatibility variable is set).	 */	if ((irix_sgid_inherit) &&	    (ip->i_d.di_mode & S_ISGID) &&	    (!in_group_p((gid_t)ip->i_d.di_gid))) {		ip->i_d.di_mode &= ~S_ISGID;	}	ip->i_d.di_size = 0;	ip->i_size = 0;	ip->i_d.di_nextents = 0;	ASSERT(ip->i_d.di_nblocks == 0);	xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD);	/*	 * di_gen will have been taken care of in xfs_iread.	 */	ip->i_d.di_extsize = 0;	ip->i_d.di_dmevmask = 0;	ip->i_d.di_dmstate = 0;	ip->i_d.di_flags = 0;	flags = XFS_ILOG_CORE;	switch (mode & S_IFMT) {	case S_IFIFO:	case S_IFCHR:	case S_IFBLK:	case S_IFSOCK:		ip->i_d.di_format = XFS_DINODE_FMT_DEV;		ip->i_df.if_u2.if_rdev = rdev;		ip->i_df.if_flags = 0;		flags |= XFS_ILOG_DEV;		break;	case S_IFREG:		if (pip && xfs_inode_is_filestream(pip)) {			error = xfs_filestream_associate(pip, ip);			if (error < 0)				return -error;			if (!error)				xfs_iflags_set(ip, XFS_IFILESTREAM);		}		/* fall through */	case S_IFDIR:		if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {			uint	di_flags = 0;			if ((mode & S_IFMT) == S_IFDIR) {				if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT)					di_flags |= XFS_DIFLAG_RTINHERIT;				if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) {					di_flags |= XFS_DIFLAG_EXTSZINHERIT;					ip->i_d.di_extsize = pip->i_d.di_extsize;				}			} else if ((mode & S_IFMT) == S_IFREG) {				if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) {					di_flags |= XFS_DIFLAG_REALTIME;					ip->i_iocore.io_flags |= XFS_IOCORE_RT;				}				if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) {					di_flags |= XFS_DIFLAG_EXTSIZE;					ip->i_d.di_extsize = pip->i_d.di_extsize;				}			}			if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) &&			    xfs_inherit_noatime)				di_flags |= XFS_DIFLAG_NOATIME;			if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) &&			    xfs_inherit_nodump)				di_flags |= XFS_DIFLAG_NODUMP;			if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) &&			    xfs_inherit_sync)				di_flags |= XFS_DIFLAG_SYNC;			if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) &&			    xfs_inherit_nosymlinks)				di_flags |= XFS_DIFLAG_NOSYMLINKS;			if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)				di_flags |= XFS_DIFLAG_PROJINHERIT;			if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) &&			    xfs_inherit_nodefrag)				di_flags |= XFS_DIFLAG_NODEFRAG;			if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM)				di_flags |= XFS_DIFLAG_FILESTREAM;			ip->i_d.di_flags |= di_flags;		}		/* FALLTHROUGH */	case S_IFLNK:		ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;		ip->i_df.if_flags = XFS_IFEXTENTS;		ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;		ip->i_df.if_u1.if_extents = NULL;		break;	default:		ASSERT(0);	}	/*	 * Attribute fork settings for new inode.	 */	ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;	ip->i_d.di_anextents = 0;	/*	 * Log the new values stuffed into the inode.	 */	xfs_trans_log_inode(tp, ip, flags);	/* now that we have an i_mode we can setup inode ops and unlock */	xfs_initialize_vnode(tp->t_mountp, vp, ip);	*ipp = ip;	return 0;}/* * Check to make sure that there are no blocks allocated to the * file beyond the size of the file.  We don't check this for * files with fixed size extents or real time extents, but we

⌨️ 快捷键说明

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