xfs: remove SYNC_WAIT from xfs_reclaim_inodes()
Clean up xfs_reclaim_inodes() callers. Most callers want blocking behaviour, so just make the existing SYNC_WAIT behaviour the default. For the xfs_reclaim_worker(), just call xfs_reclaim_inodes_ag() directly because we just want optimistic clean inode reclaim to be done in the background. For xfs_quiesce_attr() we can just remove the inode reclaim calls as they are a historic relic that was required to flush dirty inodes that contained unlogged changes. We now log all changes to the inodes, so the sync AIL push from xfs_log_quiesce() called by xfs_quiesce_attr() will do all the required inode writeback for freeze. Seeing as we now want to loop until all reclaimable inodes have been reclaimed, make xfs_reclaim_inodes() loop on the XFS_ICI_RECLAIM_TAG tag rather than having xfs_reclaim_inodes_ag() tell it that inodes were skipped. This is much more reliable and will always loop until all reclaimable inodes are reclaimed. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
committed by
Darrick J. Wong
parent
50718b8d73
commit
4d0bab3a44
@@ -160,24 +160,6 @@ xfs_reclaim_work_queue(
|
|||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a fast pass over the inode cache to try to get reclaim moving on as
|
|
||||||
* many inodes as possible in a short period of time. It kicks itself every few
|
|
||||||
* seconds, as well as being kicked by the inode cache shrinker when memory
|
|
||||||
* goes low. It scans as quickly as possible avoiding locked inodes or those
|
|
||||||
* already being flushed, and once done schedules a future pass.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
xfs_reclaim_worker(
|
|
||||||
struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct xfs_mount *mp = container_of(to_delayed_work(work),
|
|
||||||
struct xfs_mount, m_reclaim_work);
|
|
||||||
|
|
||||||
xfs_reclaim_inodes(mp, 0);
|
|
||||||
xfs_reclaim_work_queue(mp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xfs_perag_set_reclaim_tag(
|
xfs_perag_set_reclaim_tag(
|
||||||
struct xfs_perag *pag)
|
struct xfs_perag *pag)
|
||||||
@@ -1100,7 +1082,7 @@ xfs_reclaim_inode_grab(
|
|||||||
* dirty, async => requeue
|
* dirty, async => requeue
|
||||||
* dirty, sync => flush, wait and reclaim
|
* dirty, sync => flush, wait and reclaim
|
||||||
*/
|
*/
|
||||||
static bool
|
static void
|
||||||
xfs_reclaim_inode(
|
xfs_reclaim_inode(
|
||||||
struct xfs_inode *ip,
|
struct xfs_inode *ip,
|
||||||
struct xfs_perag *pag)
|
struct xfs_perag *pag)
|
||||||
@@ -1173,7 +1155,7 @@ reclaim:
|
|||||||
ASSERT(xfs_inode_clean(ip));
|
ASSERT(xfs_inode_clean(ip));
|
||||||
|
|
||||||
__xfs_inode_free(ip);
|
__xfs_inode_free(ip);
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
out_ifunlock:
|
out_ifunlock:
|
||||||
xfs_ifunlock(ip);
|
xfs_ifunlock(ip);
|
||||||
@@ -1181,7 +1163,6 @@ out_iunlock:
|
|||||||
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
||||||
out:
|
out:
|
||||||
xfs_iflags_clear(ip, XFS_IRECLAIM);
|
xfs_iflags_clear(ip, XFS_IRECLAIM);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1194,14 +1175,13 @@ out:
|
|||||||
* so that callers that want to block until all dirty inodes are written back
|
* so that callers that want to block until all dirty inodes are written back
|
||||||
* and reclaimed can sanely loop.
|
* and reclaimed can sanely loop.
|
||||||
*/
|
*/
|
||||||
static int
|
static void
|
||||||
xfs_reclaim_inodes_ag(
|
xfs_reclaim_inodes_ag(
|
||||||
struct xfs_mount *mp,
|
struct xfs_mount *mp,
|
||||||
int *nr_to_scan)
|
int *nr_to_scan)
|
||||||
{
|
{
|
||||||
struct xfs_perag *pag;
|
struct xfs_perag *pag;
|
||||||
xfs_agnumber_t ag = 0;
|
xfs_agnumber_t ag = 0;
|
||||||
int skipped = 0;
|
|
||||||
|
|
||||||
while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
|
while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
|
||||||
unsigned long first_index = 0;
|
unsigned long first_index = 0;
|
||||||
@@ -1210,14 +1190,7 @@ xfs_reclaim_inodes_ag(
|
|||||||
|
|
||||||
ag = pag->pag_agno + 1;
|
ag = pag->pag_agno + 1;
|
||||||
|
|
||||||
/*
|
|
||||||
* If the cursor is not zero, we haven't scanned the whole AG
|
|
||||||
* so we might have skipped inodes here.
|
|
||||||
*/
|
|
||||||
first_index = READ_ONCE(pag->pag_ici_reclaim_cursor);
|
first_index = READ_ONCE(pag->pag_ici_reclaim_cursor);
|
||||||
if (first_index)
|
|
||||||
skipped++;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct xfs_inode *batch[XFS_LOOKUP_BATCH];
|
struct xfs_inode *batch[XFS_LOOKUP_BATCH];
|
||||||
int i;
|
int i;
|
||||||
@@ -1270,16 +1243,12 @@ xfs_reclaim_inodes_ag(
|
|||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
for (i = 0; i < nr_found; i++) {
|
for (i = 0; i < nr_found; i++) {
|
||||||
if (!batch[i])
|
if (batch[i])
|
||||||
continue;
|
xfs_reclaim_inode(batch[i], pag);
|
||||||
if (!xfs_reclaim_inode(batch[i], pag))
|
|
||||||
skipped++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*nr_to_scan -= XFS_LOOKUP_BATCH;
|
*nr_to_scan -= XFS_LOOKUP_BATCH;
|
||||||
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
|
||||||
} while (nr_found && !done && *nr_to_scan > 0);
|
} while (nr_found && !done && *nr_to_scan > 0);
|
||||||
|
|
||||||
if (done)
|
if (done)
|
||||||
@@ -1287,27 +1256,18 @@ xfs_reclaim_inodes_ag(
|
|||||||
WRITE_ONCE(pag->pag_ici_reclaim_cursor, first_index);
|
WRITE_ONCE(pag->pag_ici_reclaim_cursor, first_index);
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
}
|
}
|
||||||
return skipped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
xfs_reclaim_inodes(
|
xfs_reclaim_inodes(
|
||||||
xfs_mount_t *mp,
|
struct xfs_mount *mp)
|
||||||
int mode)
|
|
||||||
{
|
{
|
||||||
int nr_to_scan = INT_MAX;
|
int nr_to_scan = INT_MAX;
|
||||||
int skipped;
|
|
||||||
|
|
||||||
xfs_reclaim_inodes_ag(mp, &nr_to_scan);
|
while (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) {
|
||||||
if (!(mode & SYNC_WAIT))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
xfs_ail_push_all_sync(mp->m_ail);
|
xfs_ail_push_all_sync(mp->m_ail);
|
||||||
skipped = xfs_reclaim_inodes_ag(mp, &nr_to_scan);
|
xfs_reclaim_inodes_ag(mp, &nr_to_scan);
|
||||||
} while (skipped > 0);
|
};
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1426,6 +1386,25 @@ xfs_inode_matches_eofb(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a fast pass over the inode cache to try to get reclaim moving on as
|
||||||
|
* many inodes as possible in a short period of time. It kicks itself every few
|
||||||
|
* seconds, as well as being kicked by the inode cache shrinker when memory
|
||||||
|
* goes low. It scans as quickly as possible avoiding locked inodes or those
|
||||||
|
* already being flushed, and once done schedules a future pass.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_reclaim_worker(
|
||||||
|
struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct xfs_mount *mp = container_of(to_delayed_work(work),
|
||||||
|
struct xfs_mount, m_reclaim_work);
|
||||||
|
int nr_to_scan = INT_MAX;
|
||||||
|
|
||||||
|
xfs_reclaim_inodes_ag(mp, &nr_to_scan);
|
||||||
|
xfs_reclaim_work_queue(mp);
|
||||||
|
}
|
||||||
|
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_inode_free_eofblocks(
|
xfs_inode_free_eofblocks(
|
||||||
struct xfs_inode *ip,
|
struct xfs_inode *ip,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ void xfs_inode_free(struct xfs_inode *ip);
|
|||||||
|
|
||||||
void xfs_reclaim_worker(struct work_struct *work);
|
void xfs_reclaim_worker(struct work_struct *work);
|
||||||
|
|
||||||
int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
|
void xfs_reclaim_inodes(struct xfs_mount *mp);
|
||||||
int xfs_reclaim_inodes_count(struct xfs_mount *mp);
|
int xfs_reclaim_inodes_count(struct xfs_mount *mp);
|
||||||
long xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
|
long xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
|
||||||
|
|
||||||
|
|||||||
@@ -1011,7 +1011,7 @@ xfs_mountfs(
|
|||||||
* quota inodes.
|
* quota inodes.
|
||||||
*/
|
*/
|
||||||
cancel_delayed_work_sync(&mp->m_reclaim_work);
|
cancel_delayed_work_sync(&mp->m_reclaim_work);
|
||||||
xfs_reclaim_inodes(mp, SYNC_WAIT);
|
xfs_reclaim_inodes(mp);
|
||||||
xfs_health_unmount(mp);
|
xfs_health_unmount(mp);
|
||||||
out_log_dealloc:
|
out_log_dealloc:
|
||||||
mp->m_flags |= XFS_MOUNT_UNMOUNTING;
|
mp->m_flags |= XFS_MOUNT_UNMOUNTING;
|
||||||
@@ -1088,13 +1088,12 @@ xfs_unmountfs(
|
|||||||
xfs_ail_push_all_sync(mp->m_ail);
|
xfs_ail_push_all_sync(mp->m_ail);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And reclaim all inodes. At this point there should be no dirty
|
* Reclaim all inodes. At this point there should be no dirty inodes and
|
||||||
* inodes and none should be pinned or locked, but use synchronous
|
* none should be pinned or locked. Stop background inode reclaim here
|
||||||
* reclaim just to be sure. We can stop background inode reclaim
|
* if it is still running.
|
||||||
* here as well if it is still running.
|
|
||||||
*/
|
*/
|
||||||
cancel_delayed_work_sync(&mp->m_reclaim_work);
|
cancel_delayed_work_sync(&mp->m_reclaim_work);
|
||||||
xfs_reclaim_inodes(mp, SYNC_WAIT);
|
xfs_reclaim_inodes(mp);
|
||||||
xfs_health_unmount(mp);
|
xfs_health_unmount(mp);
|
||||||
|
|
||||||
xfs_qm_unmount(mp);
|
xfs_qm_unmount(mp);
|
||||||
|
|||||||
@@ -890,9 +890,6 @@ xfs_quiesce_attr(
|
|||||||
/* force the log to unpin objects from the now complete transactions */
|
/* force the log to unpin objects from the now complete transactions */
|
||||||
xfs_log_force(mp, XFS_LOG_SYNC);
|
xfs_log_force(mp, XFS_LOG_SYNC);
|
||||||
|
|
||||||
/* reclaim inodes to do any IO before the freeze completes */
|
|
||||||
xfs_reclaim_inodes(mp, 0);
|
|
||||||
xfs_reclaim_inodes(mp, SYNC_WAIT);
|
|
||||||
|
|
||||||
/* Push the superblock and write an unmount record */
|
/* Push the superblock and write an unmount record */
|
||||||
error = xfs_log_sbcount(mp);
|
error = xfs_log_sbcount(mp);
|
||||||
|
|||||||
Reference in New Issue
Block a user