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

📄 xfs_vfsops.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 racy, 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.		 */		if (xfs_ilock_nowait(ip, lock_flags) == 0) {			if ((flags & SYNC_BDFLUSH) || (vp == NULL)) {				ip = ip->i_mnext;				continue;			}			vp = vn_grab(vp);			if (vp == NULL) {				ip = ip->i_mnext;				continue;			}			IPOINTER_INSERT(ip, mp);			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 we have to flush data or wait for I/O completion		 * we need to drop the ilock that we currently hold.		 * If we need to drop the lock, insert a marker if we		 * have not already done so.		 */		if ((flags & (SYNC_CLOSE|SYNC_IOWAIT)) ||		    ((flags & SYNC_DELWRI) && VN_DIRTY(vp))) {			if (mount_locked) {				IPOINTER_INSERT(ip, mp);			}			xfs_iunlock(ip, XFS_ILOCK_SHARED);			if (flags & SYNC_CLOSE) {				/* Shutdown case. Flush and invalidate. */				if (XFS_FORCED_SHUTDOWN(mp))					xfs_tosspages(ip, 0, -1,							     FI_REMAPF);				else					error = xfs_flushinval_pages(ip,							0, -1, FI_REMAPF);			} else if ((flags & SYNC_DELWRI) && VN_DIRTY(vp)) {				error = xfs_flush_pages(ip, 0,							-1, fflag, FI_NONE);			}			/*			 * When freezing, we need to wait ensure all I/O (including direct			 * I/O) is complete to ensure no further data modification can take			 * place after this point			 */			if (flags & SYNC_IOWAIT)				vn_iowait(ip);			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, 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. * */intxfs_syncsub(	xfs_mount_t	*mp,	int		flags,	int             *bypassed){	int		error = 0;	int		last_error = 0;	uint		log_flags = XFS_LOG_FORCE;	xfs_buf_t	*bp;	xfs_buf_log_item_t	*bip;	/*	 * Sync out the log.  This ensures that the log is periodically	 * flushed even if there is not enough activity to fill it up.	 */	if (flags & SYNC_WAIT)		log_flags |= XFS_LOG_SYNC;	xfs_log_force(mp, (xfs_lsn_t)0, log_flags);	if (flags & (SYNC_ATTR|SYNC_DELWRI)) {		if (flags & SYNC_BDFLUSH)			xfs_finish_reclaim_all(mp, 1);		else			error = xfs_sync_inodes(mp, flags, bypassed);	}	/*	 * Flushing out dirty data above probably generated more	 * log activity, so if this isn't vfs_sync() then flush	 * the log again.	 */	if (flags & SYNC_DELWRI) {		xfs_log_force(mp, (xfs_lsn_t)0, log_flags);	}	if (flags & SYNC_FSDATA) {		/*		 * If this is vfs_sync() then only sync the superblock		 * if we can lock it without sleeping and it is not pinned.		 */		if (flags & SYNC_BDFLUSH) {			bp = xfs_getsb(mp, XFS_BUF_TRYLOCK);			if (bp != NULL) {				bip = XFS_BUF_FSPRIVATE(bp,xfs_buf_log_item_t*);				if ((bip != NULL) &&				    xfs_buf_item_dirty(bip)) {					if (!(XFS_BUF_ISPINNED(bp))) {						XFS_BUF_ASYNC(bp);						error = xfs_bwrite(mp, bp);					} else {						xfs_buf_relse(bp);					}				} else {					xfs_buf_relse(bp);				}			}		} else {			bp = xfs_getsb(mp, 0);			/*			 * If the buffer is pinned then push on the log so			 * we won't get stuck waiting in the write for			 * someone, maybe ourselves, to flush the log.			 * Even though we just pushed the log above, we			 * did not have the superblock buffer locked at			 * that point so it can become pinned in between			 * there and here.			 */			if (XFS_BUF_ISPINNED(bp))				xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);			if (flags & SYNC_WAIT)				XFS_BUF_UNASYNC(bp);			else				XFS_BUF_ASYNC(bp);			error = xfs_bwrite(mp, bp);		}		if (error) {			last_error = error;		}	}	/*	 * If this is the periodic sync, then kick some entries out of	 * the reference cache.  This ensures that idle entries are	 * eventually kicked out of the cache.	 */	if (flags & SYNC_REFCACHE) {		if (flags & SYNC_WAIT)			xfs_refcache_purge_mp(mp);		else			xfs_refcache_purge_some(mp);	}	/*	 * If asked, update the disk superblock with incore counter values if we	 * are using non-persistent counters so that they don't get too far out	 * of sync if we crash or get a forced shutdown. We don't want to force	 * this to disk, just get a transaction into the iclogs....	 */	if (flags & SYNC_SUPER)		xfs_log_sbcount(mp, 0);	/*	 * Now check to see if the log needs a "dummy" transaction.	 */	if (!(flags & SYNC_REMOUNT) && xfs_log_need_covered(mp)) {		xfs_trans_t *tp;		xfs_inode_t *ip;		/*		 * Put a dummy transaction in the log to tell		 * recovery that all others are OK.

⌨️ 快捷键说明

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