Commit 295abff2 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

Merge tag 'fix-inode-health-reports-5.14_2021-06-08' of...

Merge tag 'fix-inode-health-reports-5.14_2021-06-08' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-5.14-merge2

xfs: preserve inode health reports for longer

This is a quick series to make sure that inode sickness reports stick
around in memory for some amount of time.

v2: rebase to 5.13-rc4
v3: require explicit request to reclaim sick inodes, drop weird icache
    miss interaction with DONTCACHE

* tag 'fix-inode-health-reports-5.14_2021-06-08' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: selectively keep sick inodes in memory
  xfs: drop IDONTCACHE on inodes when we mark them sick
  xfs: only reset incore inode health state flags when reclaiming an inode
parents ffc18582 9492750a
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -229,6 +229,15 @@ xfs_inode_mark_sick(
	ip->i_sick |= mask;
	ip->i_checked |= mask;
	spin_unlock(&ip->i_flags_lock);

	/*
	 * Keep this inode around so we don't lose the sickness report.  Scrub
	 * grabs inodes with DONTCACHE assuming that most inode are ok, which
	 * is not the case here.
	 */
	spin_lock(&VFS_I(ip)->i_lock);
	VFS_I(ip)->i_state &= ~I_DONTCACHE;
	spin_unlock(&VFS_I(ip)->i_lock);
}

/* Mark parts of an inode healed. */
+41 −9
Original line number Diff line number Diff line
@@ -71,10 +71,13 @@ static int xfs_icwalk_ag(struct xfs_perag *pag,
/* Stop scanning after icw_scan_limit inodes. */
#define XFS_ICWALK_FLAG_SCAN_LIMIT	(1U << 28)

#define XFS_ICWALK_FLAG_RECLAIM_SICK	(1U << 27)

#define XFS_ICWALK_PRIVATE_FLAGS	(XFS_ICWALK_FLAG_DROP_UDQUOT | \
					 XFS_ICWALK_FLAG_DROP_GDQUOT | \
					 XFS_ICWALK_FLAG_DROP_PDQUOT | \
					 XFS_ICWALK_FLAG_SCAN_LIMIT)
					 XFS_ICWALK_FLAG_SCAN_LIMIT | \
					 XFS_ICWALK_FLAG_RECLAIM_SICK)

/*
 * Allocate and initialise an xfs_inode.
@@ -523,9 +526,6 @@ xfs_iget_cache_hit(
				XFS_INO_TO_AGINO(pag->pag_mount, ino),
				XFS_ICI_RECLAIM_TAG);
		inode->i_state = I_NEW;
		ip->i_sick = 0;
		ip->i_checked = 0;

		spin_unlock(&ip->i_flags_lock);
		spin_unlock(&pag->pag_ici_lock);
	} else {
@@ -913,7 +913,8 @@ xfs_dqrele_all_inodes(
 */
static bool
xfs_reclaim_igrab(
	struct xfs_inode	*ip)
	struct xfs_inode	*ip,
	struct xfs_eofblocks	*eofb)
{
	ASSERT(rcu_read_lock_held());

@@ -924,6 +925,14 @@ xfs_reclaim_igrab(
		spin_unlock(&ip->i_flags_lock);
		return false;
	}

	/* Don't reclaim a sick inode unless the caller asked for it. */
	if (ip->i_sick &&
	    (!eofb || !(eofb->eof_flags & XFS_ICWALK_FLAG_RECLAIM_SICK))) {
		spin_unlock(&ip->i_flags_lock);
		return false;
	}

	__xfs_iflags_set(ip, XFS_IRECLAIM);
	spin_unlock(&ip->i_flags_lock);
	return true;
@@ -979,6 +988,8 @@ xfs_reclaim_inode(
	spin_lock(&ip->i_flags_lock);
	ip->i_flags = XFS_IRECLAIM;
	ip->i_ino = 0;
	ip->i_sick = 0;
	ip->i_checked = 0;
	spin_unlock(&ip->i_flags_lock);

	xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -1022,13 +1033,30 @@ xfs_reclaim_inode(
	xfs_iflags_clear(ip, XFS_IRECLAIM);
}

/* Reclaim sick inodes if we're unmounting or the fs went down. */
static inline bool
xfs_want_reclaim_sick(
	struct xfs_mount	*mp)
{
	return (mp->m_flags & XFS_MOUNT_UNMOUNTING) ||
	       (mp->m_flags & XFS_MOUNT_NORECOVERY) ||
	       XFS_FORCED_SHUTDOWN(mp);
}

void
xfs_reclaim_inodes(
	struct xfs_mount	*mp)
{
	struct xfs_eofblocks	eofb = {
		.eof_flags	= 0,
	};

	if (xfs_want_reclaim_sick(mp))
		eofb.eof_flags |= XFS_ICWALK_FLAG_RECLAIM_SICK;

	while (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) {
		xfs_ail_push_all_sync(mp->m_ail);
		xfs_icwalk(mp, XFS_ICWALK_RECLAIM, NULL);
		xfs_icwalk(mp, XFS_ICWALK_RECLAIM, &eofb);
	}
}

@@ -1049,6 +1077,9 @@ xfs_reclaim_inodes_nr(
		.icw_scan_limit	= nr_to_scan,
	};

	if (xfs_want_reclaim_sick(mp))
		eofb.eof_flags |= XFS_ICWALK_FLAG_RECLAIM_SICK;

	/* kick background reclaimer and push the AIL */
	xfs_reclaim_work_queue(mp);
	xfs_ail_push_all(mp->m_ail);
@@ -1598,7 +1629,8 @@ xfs_blockgc_free_quota(
static inline bool
xfs_icwalk_igrab(
	enum xfs_icwalk_goal	goal,
	struct xfs_inode	*ip)
	struct xfs_inode	*ip,
	struct xfs_eofblocks	*eofb)
{
	switch (goal) {
	case XFS_ICWALK_DQRELE:
@@ -1606,7 +1638,7 @@ xfs_icwalk_igrab(
	case XFS_ICWALK_BLOCKGC:
		return xfs_blockgc_igrab(ip);
	case XFS_ICWALK_RECLAIM:
		return xfs_reclaim_igrab(ip);
		return xfs_reclaim_igrab(ip, eofb);
	default:
		return false;
	}
@@ -1695,7 +1727,7 @@ xfs_icwalk_ag(
		for (i = 0; i < nr_found; i++) {
			struct xfs_inode *ip = batch[i];

			if (done || !xfs_icwalk_igrab(goal, ip))
			if (done || !xfs_icwalk_igrab(goal, ip, eofb))
				batch[i] = NULL;

			/*