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

📄 xfs_vnodeops.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	*tpp = tp;	return 0;}intxfs_release(	xfs_inode_t	*ip){	bhv_vnode_t	*vp = XFS_ITOV(ip);	xfs_mount_t	*mp = ip->i_mount;	int		error;	if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0))		return 0;	/* If this is a read-only mount, don't do this (would generate I/O) */	if (mp->m_flags & XFS_MOUNT_RDONLY)		return 0;	if (!XFS_FORCED_SHUTDOWN(mp)) {		int truncated;		/*		 * If we are using filestreams, and we have an unlinked		 * file that we are processing the last close on, then nothing		 * will be able to reopen and write to this file. Purge this		 * inode from the filestreams cache so that it doesn't delay		 * teardown of the inode.		 */		if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))			xfs_filestream_deassociate(ip);		/*		 * If we previously truncated this file and removed old data		 * in the process, we want to initiate "early" writeout on		 * the last close.  This is an attempt to combat the notorious		 * NULL files problem which is particularly noticable from a		 * truncate down, buffered (re-)write (delalloc), followed by		 * a crash.  What we are effectively doing here is		 * significantly reducing the time window where we'd otherwise		 * be exposed to that problem.		 */		truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);		if (truncated && VN_DIRTY(vp) && ip->i_delayed_blks > 0)			xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE);	}#ifdef HAVE_REFCACHE	/* If we are in the NFS reference cache then don't do this now */	if (ip->i_refcache)		return 0;#endif	if (ip->i_d.di_nlink != 0) {		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&		     ((ip->i_size > 0) || (VN_CACHED(vp) > 0 ||		       ip->i_delayed_blks > 0)) &&		     (ip->i_df.if_flags & XFS_IFEXTENTS))  &&		    (!(ip->i_d.di_flags &				(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {			error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);			if (error)				return error;			/* Update linux inode block count after free above */			vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,				ip->i_d.di_nblocks + ip->i_delayed_blks);		}	}	return 0;}/* * xfs_inactive * * This is called when the vnode reference count for the vnode * goes to zero.  If the file has been unlinked, then it must * now be truncated.  Also, we clear all of the read-ahead state * kept for the inode here since the file is now closed. */intxfs_inactive(	xfs_inode_t	*ip){	bhv_vnode_t	*vp = XFS_ITOV(ip);	xfs_bmap_free_t	free_list;	xfs_fsblock_t	first_block;	int		committed;	xfs_trans_t	*tp;	xfs_mount_t	*mp;	int		error;	int		truncate;	vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address);	/*	 * If the inode is already free, then there can be nothing	 * to clean up here.	 */	if (ip->i_d.di_mode == 0 || VN_BAD(vp)) {		ASSERT(ip->i_df.if_real_bytes == 0);		ASSERT(ip->i_df.if_broot_bytes == 0);		return VN_INACTIVE_CACHE;	}	/*	 * Only do a truncate if it's a regular file with	 * some actual space in it.  It's OK to look at the	 * inode's fields without the lock because we're the	 * only one with a reference to the inode.	 */	truncate = ((ip->i_d.di_nlink == 0) &&	    ((ip->i_d.di_size != 0) || (ip->i_size != 0) ||	     (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&	    ((ip->i_d.di_mode & S_IFMT) == S_IFREG));	mp = ip->i_mount;	if (ip->i_d.di_nlink == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_DESTROY)) {		(void) XFS_SEND_DESTROY(mp, vp, DM_RIGHT_NULL);	}	error = 0;	/* If this is a read-only mount, don't do this (would generate I/O) */	if (mp->m_flags & XFS_MOUNT_RDONLY)		goto out;	if (ip->i_d.di_nlink != 0) {		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&                     ((ip->i_size > 0) || (VN_CACHED(vp) > 0 ||                       ip->i_delayed_blks > 0)) &&		      (ip->i_df.if_flags & XFS_IFEXTENTS) &&		     (!(ip->i_d.di_flags &				(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||		      (ip->i_delayed_blks != 0)))) {			error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);			if (error)				return VN_INACTIVE_CACHE;			/* Update linux inode block count after free above */			vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,				ip->i_d.di_nblocks + ip->i_delayed_blks);		}		goto out;	}	ASSERT(ip->i_d.di_nlink == 0);	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))		return VN_INACTIVE_CACHE;	tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);	if (truncate) {		/*		 * Do the xfs_itruncate_start() call before		 * reserving any log space because itruncate_start		 * will call into the buffer cache and we can't		 * do that within a transaction.		 */		xfs_ilock(ip, XFS_IOLOCK_EXCL);		error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);		if (error) {			xfs_trans_cancel(tp, 0);			xfs_iunlock(ip, XFS_IOLOCK_EXCL);			return VN_INACTIVE_CACHE;		}		error = xfs_trans_reserve(tp, 0,					  XFS_ITRUNCATE_LOG_RES(mp),					  0, XFS_TRANS_PERM_LOG_RES,					  XFS_ITRUNCATE_LOG_COUNT);		if (error) {			/* Don't call itruncate_cleanup */			ASSERT(XFS_FORCED_SHUTDOWN(mp));			xfs_trans_cancel(tp, 0);			xfs_iunlock(ip, XFS_IOLOCK_EXCL);			return VN_INACTIVE_CACHE;		}		xfs_ilock(ip, XFS_ILOCK_EXCL);		xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);		xfs_trans_ihold(tp, ip);		/*		 * normally, we have to run xfs_itruncate_finish sync.		 * But if filesystem is wsync and we're in the inactive		 * path, then we know that nlink == 0, and that the		 * xaction that made nlink == 0 is permanently committed		 * since xfs_remove runs as a synchronous transaction.		 */		error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK,				(!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0));		if (error) {			xfs_trans_cancel(tp,				XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);			xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);			return VN_INACTIVE_CACHE;		}	} else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) {		/*		 * If we get an error while cleaning up a		 * symlink we bail out.		 */		error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ?			xfs_inactive_symlink_rmt(ip, &tp) :			xfs_inactive_symlink_local(ip, &tp);		if (error) {			ASSERT(tp == NULL);			return VN_INACTIVE_CACHE;		}		xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);		xfs_trans_ihold(tp, ip);	} else {		error = xfs_trans_reserve(tp, 0,					  XFS_IFREE_LOG_RES(mp),					  0, XFS_TRANS_PERM_LOG_RES,					  XFS_INACTIVE_LOG_COUNT);		if (error) {			ASSERT(XFS_FORCED_SHUTDOWN(mp));			xfs_trans_cancel(tp, 0);			return VN_INACTIVE_CACHE;		}		xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);		xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);		xfs_trans_ihold(tp, ip);	}	/*	 * If there are attributes associated with the file	 * then blow them away now.  The code calls a routine	 * that recursively deconstructs the attribute fork.	 * We need to just commit the current transaction	 * because we can't use it for xfs_attr_inactive().	 */	if (ip->i_d.di_anextents > 0) {		error = xfs_inactive_attrs(ip, &tp);		/*		 * If we got an error, the transaction is already		 * cancelled, and the inode is unlocked. Just get out.		 */		 if (error)			 return VN_INACTIVE_CACHE;	} else if (ip->i_afp) {		xfs_idestroy_fork(ip, XFS_ATTR_FORK);	}	/*	 * Free the inode.	 */	XFS_BMAP_INIT(&free_list, &first_block);	error = xfs_ifree(tp, ip, &free_list);	if (error) {		/*		 * If we fail to free the inode, shut down.  The cancel		 * might do that, we need to make sure.  Otherwise the		 * inode might be lost for a long time or forever.		 */		if (!XFS_FORCED_SHUTDOWN(mp)) {			cmn_err(CE_NOTE,		"xfs_inactive:	xfs_ifree() returned an error = %d on %s",				error, mp->m_fsname);			xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);		}		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);	} else {		/*		 * Credit the quota account(s). The inode is gone.		 */		XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1);		/*		 * Just ignore errors at this point.  There is		 * nothing we can do except to try to keep going.		 */		(void) xfs_bmap_finish(&tp,  &free_list, &committed);		(void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);	}	/*	 * Release the dquots held by inode, if any.	 */	XFS_QM_DQDETACH(mp, ip);	xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); out:	return VN_INACTIVE_CACHE;}intxfs_lookup(	xfs_inode_t		*dp,	bhv_vname_t		*dentry,	bhv_vnode_t		**vpp){	xfs_inode_t		*ip;	xfs_ino_t		e_inum;	int			error;	uint			lock_mode;	vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address);	if (XFS_FORCED_SHUTDOWN(dp->i_mount))		return XFS_ERROR(EIO);	lock_mode = xfs_ilock_map_shared(dp);	error = xfs_dir_lookup_int(dp, lock_mode, dentry, &e_inum, &ip);	if (!error) {		*vpp = XFS_ITOV(ip);		ITRACE(ip);	}	xfs_iunlock_map_shared(dp, lock_mode);	return error;}intxfs_create(	xfs_inode_t		*dp,	bhv_vname_t		*dentry,	mode_t			mode,	xfs_dev_t		rdev,	bhv_vnode_t		**vpp,	cred_t			*credp){	char			*name = VNAME(dentry);	xfs_mount_t	        *mp = dp->i_mount;	bhv_vnode_t		*dir_vp = XFS_ITOV(dp);	xfs_inode_t		*ip;	bhv_vnode_t	        *vp = NULL;	xfs_trans_t		*tp;	int                     error;	xfs_bmap_free_t		free_list;	xfs_fsblock_t		first_block;	boolean_t		unlock_dp_on_error = B_FALSE;	int			dm_event_sent = 0;	uint			cancel_flags;	int			committed;	xfs_prid_t		prid;	struct xfs_dquot	*udqp, *gdqp;	uint			resblks;	int			namelen;	ASSERT(!*vpp);	vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address);	namelen = VNAMELEN(dentry);	if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {		error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,				dir_vp, DM_RIGHT_NULL, NULL,				DM_RIGHT_NULL, name, NULL,				mode, 0, 0);		if (error)			return error;		dm_event_sent = 1;	}	if (XFS_FORCED_SHUTDOWN(mp))		return XFS_ERROR(EIO);	/* Return through std_return after this point. */	udqp = gdqp = NULL;	if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)		prid = dp->i_d.di_projid;	else		prid = (xfs_prid_t)dfltprid;	/*	 * Make sure that we have allocated dquot(s) on disk.	 */	error = XFS_QM_DQVOPALLOC(mp, dp,			current_fsuid(credp), current_fsgid(credp), prid,			XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);	if (error)		goto std_return;	ip = NULL;	tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;	resblks = XFS_CREATE_SPACE_RES(mp, namelen);	/*	 * Initially assume that the file does not exist and	 * reserve the resources for that case.  If that is not	 * the case we'll drop the one we have and get a more	 * appropriate transaction later.	 */	error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0,			XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);	if (error == ENOSPC) {		resblks = 0;		error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0,				XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);	}	if (error) {		cancel_flags = 0;		goto error_return;	}	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);	unlock_dp_on_error = B_TRUE;	XFS_BMAP_INIT(&free_list, &first_block);	ASSERT(ip == NULL);	/*	 * Reserve disk quota and the inode.	 */	error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);	if (error)		goto error_return;	if (resblks == 0 && (error = xfs_dir_canenter(tp, dp, name, namelen)))		goto error_return;	error = xfs_dir_ialloc(&tp, dp, mode, 1,			rdev, credp, prid, resblks > 0,			&ip, &committed);	if (error) {		if (error == ENOSPC)			goto error_return;		goto abort_return;	}	ITRACE(ip);	/*	 * At this point, we've gotten a newly allocated inode.	 * It is locked (and joined to the transaction).	 */	ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE));	/*	 * Now we join the directory inode to the transaction.  We do not do it	 * earlier because xfs_dir_ialloc might commit the previous transaction	 * (and release all the locks).  An error from here on will result in	 * the transaction cancel unlocking dp so don't do it explicitly in the	 * error path.	 */	VN_HOLD(dir_vp);	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);	unlock_dp_on_error = B_FALSE;	error = xfs_dir_createname(tp, dp, name, namelen, ip->i_ino,					&first_block, &free_list, resblks ?					resblks - XFS_IALLOC_SPACE_RES(mp) : 0);	if (error) {		ASSERT(error != ENOSPC);		goto abort_return;	}	xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);	/*	 * If this is a synchronous mount, make sure that the	 * create transaction goes to disk before returning to	 * the user.	 */	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {		xfs_trans_set_sync(tp);	}	dp->i_gen++;	/*	 * Attach the dquot(s) to the inodes and modify them incore.	 * These ids of the inode couldn't have changed since the new	 * inode has been locked ever since it was created.	 */	XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);	/*	 * xfs_trans_commit normally decrements the vnode ref count	 * when it unlocks the inode. Since we want to return the	 * vnode to the caller, we bump the vnode ref count now.	 */	IHOLD(ip);	vp = XFS_ITOV(ip);	error = xfs_bmap_finish(&tp, &free_list, &committed);	if (error) {		xfs_bmap_cancel(&free_list);		goto abort_rele;	}	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);	if (error) {		IRELE(ip);		tp = NULL;		goto error_return;	}

⌨️ 快捷键说明

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