xfs_vfsops.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,927 行 · 第 1/4 页

C
1,927
字号
#define XFS_PREEMPT_MASK	0x7f	if (bypassed)		*bypassed = 0;	if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)		return 0;	error = 0;	last_error = 0;	preempt = 0;	/* Allocate a reference marker */	ipointer = (xfs_iptr_t *)kmem_zalloc(sizeof(xfs_iptr_t), KM_SLEEP);	fflag = XFS_B_ASYNC;		/* default is don't wait */	if (flags & SYNC_BDFLUSH)		fflag = XFS_B_DELWRI;	if (flags & SYNC_WAIT)		fflag = 0;		/* synchronous overrides all */	base_lock_flags = XFS_ILOCK_SHARED;	if (flags & (SYNC_DELWRI | SYNC_CLOSE)) {		/*		 * We need the I/O lock if we're going to call any of		 * the flush/inval routines.		 */		base_lock_flags |= XFS_IOLOCK_SHARED;	}	XFS_MOUNT_ILOCK(mp);	ip = mp->m_inodes;	mount_locked = B_TRUE;	vnode_refed  = B_FALSE;	IPOINTER_CLR;	do {		ASSERT(ipointer_in == B_FALSE);		ASSERT(vnode_refed == B_FALSE);		lock_flags = base_lock_flags;		/*		 * There were no inodes in the list, just break out		 * of the loop.		 */		if (ip == NULL) {			break;		}		/*		 * We found another sync thread marker - skip it		 */		if (ip->i_mount == NULL) {			ip = ip->i_mnext;			continue;		}		vp = XFS_ITOV_NULL(ip);		/*		 * If the vnode is gone then this is being torn down,		 * call reclaim if it is flushed, else let regular flush		 * code deal with it later in the loop.		 */		if (vp == NULL) {			/* Skip ones already in reclaim */			if (ip->i_flags & XFS_IRECLAIM) {				ip = ip->i_mnext;				continue;			}			if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {				ip = ip->i_mnext;			} else if ((xfs_ipincount(ip) == 0) &&				    xfs_iflock_nowait(ip)) {				IPOINTER_INSERT(ip, mp);				xfs_finish_reclaim(ip, 1,						XFS_IFLUSH_DELWRI_ELSE_ASYNC);				XFS_MOUNT_ILOCK(mp);				mount_locked = B_TRUE;				IPOINTER_REMOVE(ip, mp);			} else {				xfs_iunlock(ip, XFS_ILOCK_EXCL);				ip = ip->i_mnext;			}			continue;		}		if (VN_BAD(vp)) {			ip = ip->i_mnext;			continue;		}		if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) {			XFS_MOUNT_IUNLOCK(mp);			kmem_free(ipointer, sizeof(xfs_iptr_t));			return 0;		}		/*		 * If this is just vfs_sync() or pflushd() calling		 * then we can skip inodes for which it looks like		 * there is nothing to do.  Since we don't have the		 * inode locked this is racey, but these are periodic		 * calls so it doesn't matter.  For the others we want		 * to know for sure, so we at least try to lock them.		 */		if (flags & SYNC_BDFLUSH) {			if (((ip->i_itemp == NULL) ||			     !(ip->i_itemp->ili_format.ilf_fields &			       XFS_ILOG_ALL)) &&			    (ip->i_update_core == 0)) {				ip = ip->i_mnext;				continue;			}		}		/*		 * Try to lock without sleeping.  We're out of order with		 * the inode list lock here, so if we fail we need to drop		 * the mount lock and try again.  If we're called from		 * bdflush() here, then don't bother.		 *		 * The inode lock here actually coordinates with the		 * almost spurious inode lock in xfs_ireclaim() to prevent		 * the vnode we handle here without a reference from		 * being freed while we reference it.  If we lock the inode		 * while it's on the mount list here, then the spurious inode		 * lock in xfs_ireclaim() after the inode is pulled from		 * the mount list will sleep until we release it here.		 * This keeps the vnode from being freed while we reference		 * it.  It is also cheaper and simpler than actually doing		 * a vn_get() for every inode we touch here.		 */		if (xfs_ilock_nowait(ip, lock_flags) == 0) {			if ((flags & SYNC_BDFLUSH) || (vp == NULL)) {				ip = ip->i_mnext;				continue;			}			/*			 * We need to unlock the inode list lock in order			 * to lock the inode. Insert a marker record into			 * the inode list to remember our position, dropping			 * the lock is now done inside the IPOINTER_INSERT			 * macro.			 *			 * We also use the inode list lock to protect us			 * in taking a snapshot of the vnode version number			 * for use in calling vn_get().			 */			VMAP(vp, vmap);			IPOINTER_INSERT(ip, mp);			vp = vn_get(vp, &vmap);			if (vp == NULL) {				/*				 * The vnode was reclaimed once we let go				 * of the inode list lock.  Skip to the				 * next list entry. Remove the marker.				 */				XFS_MOUNT_ILOCK(mp);				mount_locked = B_TRUE;				vnode_refed  = B_FALSE;				IPOINTER_REMOVE(ip, mp);				continue;			}			xfs_ilock(ip, lock_flags);			ASSERT(vp == XFS_ITOV(ip));			ASSERT(ip->i_mount == mp);			vnode_refed = B_TRUE;		}		/* From here on in the loop we may have a marker record		 * in the inode list.		 */		if ((flags & SYNC_CLOSE)  && (vp != NULL)) {			/*			 * This is the shutdown case.  We just need to			 * flush and invalidate all the pages associated			 * with the inode.  Drop the inode lock since			 * we can't hold it across calls to the buffer			 * cache.			 *			 * We don't set the VREMAPPING bit in the vnode			 * here, because we don't hold the vnode lock			 * exclusively.  It doesn't really matter, though,			 * because we only come here when we're shutting			 * down anyway.			 */			xfs_iunlock(ip, XFS_ILOCK_SHARED);			if (XFS_FORCED_SHUTDOWN(mp)) {				VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF);			} else {				VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_REMAPF);			}			xfs_ilock(ip, XFS_ILOCK_SHARED);		} else if ((flags & SYNC_DELWRI) && (vp != NULL)) {			if (VN_DIRTY(vp)) {				/* We need to have dropped the lock here,				 * so insert a marker if we have not already				 * done so.				 */				if (mount_locked) {					IPOINTER_INSERT(ip, mp);				}				/*				 * Drop the inode lock since we can't hold it				 * across calls to the buffer cache.				 */				xfs_iunlock(ip, XFS_ILOCK_SHARED);				VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1,							fflag, FI_NONE, error);				xfs_ilock(ip, XFS_ILOCK_SHARED);			}		}		if (flags & SYNC_BDFLUSH) {			if ((flags & SYNC_ATTR) &&			    ((ip->i_update_core) ||			     ((ip->i_itemp != NULL) &&			      (ip->i_itemp->ili_format.ilf_fields != 0)))) {				/* Insert marker and drop lock if not already				 * done.				 */				if (mount_locked) {					IPOINTER_INSERT(ip, mp);				}				/*				 * We don't want the periodic flushing of the				 * inodes by vfs_sync() to interfere with				 * I/O to the file, especially read I/O				 * where it is only the access time stamp				 * that is being flushed out.  To prevent				 * long periods where we have both inode				 * locks held shared here while reading the				 * inode's buffer in from disk, we drop the				 * inode lock while reading in the inode				 * buffer.  We have to release the buffer				 * and reacquire the inode lock so that they				 * are acquired in the proper order (inode				 * locks first).  The buffer will go at the				 * end of the lru chain, though, so we can				 * expect it to still be there when we go				 * for it again in xfs_iflush().				 */				if ((xfs_ipincount(ip) == 0) &&				    xfs_iflock_nowait(ip)) {					xfs_ifunlock(ip);					xfs_iunlock(ip, XFS_ILOCK_SHARED);					error = xfs_itobp(mp, NULL, ip,							  &dip, &bp, 0);					if (!error) {						xfs_buf_relse(bp);					} else {						/* Bailing out, remove the						 * marker and free it.						 */						XFS_MOUNT_ILOCK(mp);						IPOINTER_REMOVE(ip, mp);						XFS_MOUNT_IUNLOCK(mp);						ASSERT(!(lock_flags &							XFS_IOLOCK_SHARED));						kmem_free(ipointer,							sizeof(xfs_iptr_t));						return (0);					}					/*					 * Since we dropped the inode lock,					 * the inode may have been reclaimed.					 * Therefore, we reacquire the mount					 * lock and check to see if we were the					 * inode reclaimed. If this happened					 * then the ipointer marker will no					 * longer point back at us. In this					 * case, move ip along to the inode					 * after the marker, remove the marker					 * and continue.					 */					XFS_MOUNT_ILOCK(mp);					mount_locked = B_TRUE;					if (ip != ipointer->ip_mprev) {						IPOINTER_REMOVE(ip, mp);						ASSERT(!vnode_refed);						ASSERT(!(lock_flags &							XFS_IOLOCK_SHARED));						continue;					}					ASSERT(ip->i_mount == mp);					if (xfs_ilock_nowait(ip,						    XFS_ILOCK_SHARED) == 0) {						ASSERT(ip->i_mount == mp);						/*						 * We failed to reacquire						 * the inode lock without						 * sleeping, so just skip						 * the inode for now.  We						 * clear the ILOCK bit from						 * the lock_flags so that we						 * won't try to drop a lock						 * we don't hold below.						 */						lock_flags &= ~XFS_ILOCK_SHARED;						IPOINTER_REMOVE(ip_next, mp);					} else if ((xfs_ipincount(ip) == 0) &&						   xfs_iflock_nowait(ip)) {						ASSERT(ip->i_mount == mp);						/*						 * Since this is vfs_sync()						 * calling we only flush the						 * inode out if we can lock						 * it without sleeping and						 * it is not pinned.  Drop						 * the mount lock here so						 * that we don't hold it for						 * too long. We already have						 * a marker in the list here.						 */						XFS_MOUNT_IUNLOCK(mp);						mount_locked = B_FALSE;						error = xfs_iflush(ip,							   XFS_IFLUSH_DELWRI);					} else {						ASSERT(ip->i_mount == mp);						IPOINTER_REMOVE(ip_next, mp);					}				}			}		} else {			if ((flags & SYNC_ATTR) &&			    ((ip->i_update_core) ||			     ((ip->i_itemp != NULL) &&			      (ip->i_itemp->ili_format.ilf_fields != 0)))) {				if (mount_locked) {					IPOINTER_INSERT(ip, mp);				}				if (flags & SYNC_WAIT) {					xfs_iflock(ip);					error = xfs_iflush(ip,							   XFS_IFLUSH_SYNC);				} else {					/*					 * If we can't acquire the flush					 * lock, then the inode is already					 * being flushed so don't bother					 * waiting.  If we can lock it then					 * do a delwri flush so we can					 * combine multiple inode flushes					 * in each disk write.					 */					if (xfs_iflock_nowait(ip)) {						error = xfs_iflush(ip,							   XFS_IFLUSH_DELWRI);					}					else if (bypassed)						(*bypassed)++;				}			}		}		if (lock_flags != 0) {			xfs_iunlock(ip, lock_flags);		}		if (vnode_refed) {			/*			 * If we had to take a reference on the vnode			 * above, then wait until after we've unlocked			 * the inode to release the reference.  This is			 * because we can be already holding the inode			 * lock when VN_RELE() calls xfs_inactive().			 *			 * Make sure to drop the mount lock before calling			 * VN_RELE() so that we don't trip over ourselves if			 * we have to go for the mount lock again in the			 * inactive code.			 */			if (mount_locked) {				IPOINTER_INSERT(ip, mp);			}			VN_RELE(vp);			vnode_refed = B_FALSE;		}		if (error) {			last_error = error;		}		/*		 * bail out if the filesystem is corrupted.		 */		if (error == EFSCORRUPTED)  {			if (!mount_locked) {				XFS_MOUNT_ILOCK(mp);				IPOINTER_REMOVE(ip, mp);			}			XFS_MOUNT_IUNLOCK(mp);			ASSERT(ipointer_in == B_FALSE);			kmem_free(ipointer, sizeof(xfs_iptr_t));			return XFS_ERROR(error);		}		/* Let other threads have a chance at the mount lock		 * if we have looped many times without dropping the		 * lock.		 */		if ((++preempt & XFS_PREEMPT_MASK) == 0) {			if (mount_locked) {				IPOINTER_INSERT(ip, mp);			}		}		if (mount_locked == B_FALSE) {			XFS_MOUNT_ILOCK(mp);			mount_locked = B_TRUE;			IPOINTER_REMOVE(ip, mp);			continue;		}		ASSERT(ipointer_in == B_FALSE);		ip = ip->i_mnext;	} while (ip != mp->m_inodes);	XFS_MOUNT_IUNLOCK(mp);	ASSERT(ipointer_in == B_FALSE);	kmem_free(ipointer, sizeof(xfs_iptr_t));	return XFS_ERROR(last_error);}/* * xfs sync routine for internal use * * This routine supports all of the flags defined for the generic VFS_SYNC * interface as explained above under xfs_sync.  In the interests of not * changing interfaces within the 6.5 family, additional internallly- * required functions are specified within a separate xflags parameter, * only available by calling this routine. * */intxfs_syncsub(	xfs_mount_t	*mp,

⌨️ 快捷键说明

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