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

📄 xfs_inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		XFS_BMAP_INIT(&free_list, &first_block);		error = XFS_BUNMAPI(mp, ntp, &ip->i_iocore,				    first_unmap_block, unmap_len,				    XFS_BMAPI_AFLAG(fork) |				      (sync ? 0 : XFS_BMAPI_ASYNC),				    XFS_ITRUNC_MAX_EXTENTS,				    &first_block, &free_list,				    NULL, &done);		if (error) {			/*			 * If the bunmapi call encounters an error,			 * return to the caller where the transaction			 * can be properly aborted.  We just need to			 * make sure we're not holding any resources			 * that we were not when we came in.			 */			xfs_bmap_cancel(&free_list);			return error;		}		/*		 * Duplicate the transaction that has the permanent		 * reservation and commit the old transaction.		 */		error = xfs_bmap_finish(tp, &free_list, &committed);		ntp = *tp;		if (error) {			/*			 * If the bmap finish call encounters an error,			 * return to the caller where the transaction			 * can be properly aborted.  We just need to			 * make sure we're not holding any resources			 * that we were not when we came in.			 *			 * Aborting from this point might lose some			 * blocks in the file system, but oh well.			 */			xfs_bmap_cancel(&free_list);			if (committed) {				/*				 * If the passed in transaction committed				 * in xfs_bmap_finish(), then we want to				 * add the inode to this one before returning.				 * This keeps things simple for the higher				 * level code, because it always knows that				 * the inode is locked and held in the				 * transaction that returns to it whether				 * errors occur or not.  We don't mark the				 * inode dirty so that this transaction can				 * be easily aborted if possible.				 */				xfs_trans_ijoin(ntp, ip,					XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);				xfs_trans_ihold(ntp, ip);			}			return error;		}		if (committed) {			/*			 * The first xact was committed,			 * so add the inode to the new one.			 * Mark it dirty so it will be logged			 * and moved forward in the log as			 * part of every commit.			 */			xfs_trans_ijoin(ntp, ip,					XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);			xfs_trans_ihold(ntp, ip);			xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);		}		ntp = xfs_trans_dup(ntp);		(void) xfs_trans_commit(*tp, 0);		*tp = ntp;		error = xfs_trans_reserve(ntp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,					  XFS_TRANS_PERM_LOG_RES,					  XFS_ITRUNCATE_LOG_COUNT);		/*		 * Add the inode being truncated to the next chained		 * transaction.		 */		xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);		xfs_trans_ihold(ntp, ip);		if (error)			return (error);	}	/*	 * Only update the size in the case of the data fork, but	 * always re-log the inode so that our permanent transaction	 * can keep on rolling it forward in the log.	 */	if (fork == XFS_DATA_FORK) {		xfs_isize_check(mp, ip, new_size);		/*		 * If we are not changing the file size then do		 * not update the on-disk file size - we may be		 * called from xfs_inactive_free_eofblocks().  If we		 * update the on-disk file size and then the system		 * crashes before the contents of the file are		 * flushed to disk then the files may be full of		 * holes (ie NULL files bug).		 */		if (ip->i_size != new_size) {			ip->i_d.di_size = new_size;			ip->i_size = new_size;		}	}	xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);	ASSERT((new_size != 0) ||	       (fork == XFS_ATTR_FORK) ||	       (ip->i_delayed_blks == 0));	ASSERT((new_size != 0) ||	       (fork == XFS_ATTR_FORK) ||	       (ip->i_d.di_nextents == 0));	xfs_itrunc_trace(XFS_ITRUNC_FINISH2, ip, 0, new_size, 0, 0);	return 0;}/* * xfs_igrow_start * * Do the first part of growing a file: zero any data in the last * block that is beyond the old EOF.  We need to do this before * the inode is joined to the transaction to modify the i_size. * That way we can drop the inode lock and call into the buffer * cache to get the buffer mapping the EOF. */intxfs_igrow_start(	xfs_inode_t	*ip,	xfs_fsize_t	new_size,	cred_t		*credp){	int		error;	ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);	ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);	ASSERT(new_size > ip->i_size);	/*	 * Zero any pages that may have been created by	 * xfs_write_file() beyond the end of the file	 * and any blocks between the old and new file sizes.	 */	error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size,			     ip->i_size);	return error;}/* * xfs_igrow_finish * * This routine is called to extend the size of a file. * The inode must have both the iolock and the ilock locked * for update and it must be a part of the current transaction. * The xfs_igrow_start() function must have been called previously. * If the change_flag is not zero, the inode change timestamp will * be updated. */voidxfs_igrow_finish(	xfs_trans_t	*tp,	xfs_inode_t	*ip,	xfs_fsize_t	new_size,	int		change_flag){	ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);	ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);	ASSERT(ip->i_transp == tp);	ASSERT(new_size > ip->i_size);	/*	 * Update the file size.  Update the inode change timestamp	 * if change_flag set.	 */	ip->i_d.di_size = new_size;	ip->i_size = new_size;	if (change_flag)		xfs_ichgtime(ip, XFS_ICHGTIME_CHG);	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);}/* * This is called when the inode's link count goes to 0. * We place the on-disk inode on a list in the AGI.  It * will be pulled from this list when the inode is freed. */intxfs_iunlink(	xfs_trans_t	*tp,	xfs_inode_t	*ip){	xfs_mount_t	*mp;	xfs_agi_t	*agi;	xfs_dinode_t	*dip;	xfs_buf_t	*agibp;	xfs_buf_t	*ibp;	xfs_agnumber_t	agno;	xfs_daddr_t	agdaddr;	xfs_agino_t	agino;	short		bucket_index;	int		offset;	int		error;	int		agi_ok;	ASSERT(ip->i_d.di_nlink == 0);	ASSERT(ip->i_d.di_mode != 0);	ASSERT(ip->i_transp == tp);	mp = tp->t_mountp;	agno = XFS_INO_TO_AGNO(mp, ip->i_ino);	agdaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp));	/*	 * Get the agi buffer first.  It ensures lock ordering	 * on the list.	 */	error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr,				   XFS_FSS_TO_BB(mp, 1), 0, &agibp);	if (error)		return error;	/*	 * Validate the magic number of the agi block.	 */	agi = XFS_BUF_TO_AGI(agibp);	agi_ok =		be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC &&		XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum));	if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IUNLINK,			XFS_RANDOM_IUNLINK))) {		XFS_CORRUPTION_ERROR("xfs_iunlink", XFS_ERRLEVEL_LOW, mp, agi);		xfs_trans_brelse(tp, agibp);		return XFS_ERROR(EFSCORRUPTED);	}	/*	 * Get the index into the agi hash table for the	 * list this inode will go on.	 */	agino = XFS_INO_TO_AGINO(mp, ip->i_ino);	ASSERT(agino != 0);	bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;	ASSERT(agi->agi_unlinked[bucket_index]);	ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino);	error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0);	if (error)		return error;	/*	 * Clear the on-disk di_nlink. This is to prevent xfs_bulkstat	 * from picking up this inode when it is reclaimed (its incore state	 * initialzed but not flushed to disk yet). The in-core di_nlink is	 * already cleared in xfs_droplink() and a corresponding transaction	 * logged. The hack here just synchronizes the in-core to on-disk	 * di_nlink value in advance before the actual inode sync to disk.	 * This is OK because the inode is already unlinked and would never	 * change its di_nlink again for this inode generation.	 * This is a temporary hack that would require a proper fix	 * in the future.	 */	dip->di_core.di_nlink = 0;	if (be32_to_cpu(agi->agi_unlinked[bucket_index]) != NULLAGINO) {		/*		 * There is already another inode in the bucket we need		 * to add ourselves to.  Add us at the front of the list.		 * Here we put the head pointer into our next pointer,		 * and then we fall through to point the head at us.		 */		ASSERT(be32_to_cpu(dip->di_next_unlinked) == NULLAGINO);		/* both on-disk, don't endian flip twice */		dip->di_next_unlinked = agi->agi_unlinked[bucket_index];		offset = ip->i_boffset +			offsetof(xfs_dinode_t, di_next_unlinked);		xfs_trans_inode_buf(tp, ibp);		xfs_trans_log_buf(tp, ibp, offset,				  (offset + sizeof(xfs_agino_t) - 1));		xfs_inobp_check(mp, ibp);	}	/*	 * Point the bucket head pointer at the inode being inserted.	 */	ASSERT(agino != 0);	agi->agi_unlinked[bucket_index] = cpu_to_be32(agino);	offset = offsetof(xfs_agi_t, agi_unlinked) +		(sizeof(xfs_agino_t) * bucket_index);	xfs_trans_log_buf(tp, agibp, offset,			  (offset + sizeof(xfs_agino_t) - 1));	return 0;}/* * Pull the on-disk inode from the AGI unlinked list. */STATIC intxfs_iunlink_remove(	xfs_trans_t	*tp,	xfs_inode_t	*ip){	xfs_ino_t	next_ino;	xfs_mount_t	*mp;	xfs_agi_t	*agi;	xfs_dinode_t	*dip;	xfs_buf_t	*agibp;	xfs_buf_t	*ibp;	xfs_agnumber_t	agno;	xfs_daddr_t	agdaddr;	xfs_agino_t	agino;	xfs_agino_t	next_agino;	xfs_buf_t	*last_ibp;	xfs_dinode_t	*last_dip = NULL;	short		bucket_index;	int		offset, last_offset = 0;	int		error;	int		agi_ok;	/*	 * First pull the on-disk inode from the AGI unlinked list.	 */	mp = tp->t_mountp;	agno = XFS_INO_TO_AGNO(mp, ip->i_ino);	agdaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp));	/*	 * Get the agi buffer first.  It ensures lock ordering	 * on the list.	 */	error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr,				   XFS_FSS_TO_BB(mp, 1), 0, &agibp);	if (error) {		cmn_err(CE_WARN,			"xfs_iunlink_remove: xfs_trans_read_buf()  returned an error %d on %s.  Returning error.",			error, mp->m_fsname);		return error;	}	/*	 * Validate the magic number of the agi block.	 */	agi = XFS_BUF_TO_AGI(agibp);	agi_ok =		be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC &&		XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum));	if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IUNLINK_REMOVE,			XFS_RANDOM_IUNLINK_REMOVE))) {		XFS_CORRUPTION_ERROR("xfs_iunlink_remove", XFS_ERRLEVEL_LOW,				     mp, agi);		xfs_trans_brelse(tp, agibp);		cmn_err(CE_WARN,			"xfs_iunlink_remove: XFS_TEST_ERROR()  returned an error on %s.  Returning EFSCORRUPTED.",			 mp->m_fsname);		return XFS_ERROR(EFSCORRUPTED);	}	/*	 * Get the index into the agi hash table for the	 * list this inode will go on.	 */	agino = XFS_INO_TO_AGINO(mp, ip->i_ino);	ASSERT(agino != 0);	bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;	ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != NULLAGINO);	ASSERT(agi->agi_unlinked[bucket_index]);	if (be32_to_cpu(agi->agi_unlinked[bucket_index]) == agino) {		/*		 * We're at the head of the list.  Get the inode's		 * on-disk buffer to see if there is anyone after us		 * on the list.  Only modify our next pointer if it		 * is not already NULLAGINO.  This saves us the overhead		 * of dealing with the buffer when there is no need to		 * change it.		 */		error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0);		if (error) {			cmn_err(CE_WARN,				"xfs_iunlink_remove: xfs_itobp()  returned an error %d on %s.  Returning error.",				error, mp->m_fsname);			return error;		}		next_agino = be32_to_cpu(dip->di_next_unlinked);		ASSERT(next_agino != 0);		if (next_agino != NULLAGINO) {			dip->di_next_unlinked = cpu_to_be32(NULLAGINO);			offset = ip->i_boffset +				offsetof(xfs_dinode_t, di_next_unlinked);			xfs_trans_inode_buf(tp, ibp);			xfs_trans_log_buf(tp, ibp, offset,					  (offset + sizeof(xfs_agino_t) - 1));			xfs_inobp_check(mp, ibp);		} else {			xfs_trans_brelse(tp, ibp);		}		/*		 * Point the bucket head pointer at the next inode.		 */		ASSERT(next_agino != 0);		ASSERT(next_agino != agino);		agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino);		offset = offsetof(xfs_agi_t, agi_unlinked) +			(sizeof(xfs_agino_t) * bucket_index);		xfs_trans_log_buf(tp, agibp, offset,				  (offset + sizeof(xfs_agino_t) - 1));	} else {		/*		 * We need to search the list for the inode being freed.		 */		next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);		last_ibp = NULL;		while (next_agino != agino) {			/*			 * If the last inode wasn't the one pointing to			 * us, then release its buffer since we're not			 * going to do anything with it.			 */			if (last_ibp != NULL) {				xfs_trans_brelse(tp, last_ibp);			}			

⌨️ 快捷键说明

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