xfs: make use of new shrinker callout for the inode cache

Convert the inode reclaim shrinker to use the new per-sb shrinker
operations. This allows much bigger reclaim batches to be used, and
allows the XFS inode cache to be shrunk in proportion with the VFS
dentry and inode caches. This avoids the problem of the VFS caches
being shrunk significantly before the XFS inode cache is shrunk
resulting in imbalances in the caches during reclaim.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Dave Chinner 2011-07-08 14:14:46 +10:00 committed by Al Viro
parent 8ab47664d5
commit 8daaa83145
3 changed files with 46 additions and 56 deletions

View file

@ -1025,11 +1025,6 @@ xfs_fs_put_super(
{
struct xfs_mount *mp = XFS_M(sb);
/*
* Unregister the memory shrinker before we tear down the mount
* structure so we don't have memory reclaim racing with us here.
*/
xfs_inode_shrinker_unregister(mp);
xfs_syncd_stop(mp);
/*
@ -1416,8 +1411,6 @@ xfs_fs_fill_super(
if (error)
goto out_filestream_unmount;
xfs_inode_shrinker_register(mp);
error = xfs_mountfs(mp);
if (error)
goto out_syncd_stop;
@ -1440,7 +1433,6 @@ xfs_fs_fill_super(
return 0;
out_syncd_stop:
xfs_inode_shrinker_unregister(mp);
xfs_syncd_stop(mp);
out_filestream_unmount:
xfs_filestream_unmount(mp);
@ -1465,7 +1457,6 @@ xfs_fs_fill_super(
}
fail_unmount:
xfs_inode_shrinker_unregister(mp);
xfs_syncd_stop(mp);
/*
@ -1491,6 +1482,21 @@ xfs_fs_mount(
return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
}
static int
xfs_fs_nr_cached_objects(
struct super_block *sb)
{
return xfs_reclaim_inodes_count(XFS_M(sb));
}
static void
xfs_fs_free_cached_objects(
struct super_block *sb,
int nr_to_scan)
{
xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan);
}
static const struct super_operations xfs_super_operations = {
.alloc_inode = xfs_fs_alloc_inode,
.destroy_inode = xfs_fs_destroy_inode,
@ -1504,6 +1510,8 @@ static const struct super_operations xfs_super_operations = {
.statfs = xfs_fs_statfs,
.remount_fs = xfs_fs_remount,
.show_options = xfs_fs_show_options,
.nr_cached_objects = xfs_fs_nr_cached_objects,
.free_cached_objects = xfs_fs_free_cached_objects,
};
static struct file_system_type xfs_fs_type = {

View file

@ -179,6 +179,8 @@ restart:
if (error == EFSCORRUPTED)
break;
cond_resched();
} while (nr_found && !done);
if (skipped) {
@ -986,6 +988,8 @@ restart:
*nr_to_scan -= XFS_LOOKUP_BATCH;
cond_resched();
} while (nr_found && !done && *nr_to_scan > 0);
if (trylock && !done)
@ -1003,7 +1007,7 @@ restart:
* ensure that when we get more reclaimers than AGs we block rather
* than spin trying to execute reclaim.
*/
if (trylock && skipped && *nr_to_scan > 0) {
if (skipped && (flags & SYNC_WAIT) && *nr_to_scan > 0) {
trylock = 0;
goto restart;
}
@ -1021,44 +1025,38 @@ xfs_reclaim_inodes(
}
/*
* Inode cache shrinker.
* Scan a certain number of inodes for reclaim.
*
* When called we make sure that there is a background (fast) inode reclaim in
* progress, while we will throttle the speed of reclaim via doiing synchronous
* progress, while we will throttle the speed of reclaim via doing synchronous
* reclaim of inodes. That means if we come across dirty inodes, we wait for
* them to be cleaned, which we hope will not be very long due to the
* background walker having already kicked the IO off on those dirty inodes.
*/
static int
xfs_reclaim_inode_shrink(
struct shrinker *shrink,
struct shrink_control *sc)
void
xfs_reclaim_inodes_nr(
struct xfs_mount *mp,
int nr_to_scan)
{
struct xfs_mount *mp;
struct xfs_perag *pag;
xfs_agnumber_t ag;
int reclaimable;
int nr_to_scan = sc->nr_to_scan;
gfp_t gfp_mask = sc->gfp_mask;
/* kick background reclaimer and push the AIL */
xfs_syncd_queue_reclaim(mp);
xfs_ail_push_all(mp->m_ail);
mp = container_of(shrink, struct xfs_mount, m_inode_shrink);
if (nr_to_scan) {
/* kick background reclaimer and push the AIL */
xfs_syncd_queue_reclaim(mp);
xfs_ail_push_all(mp->m_ail);
xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan);
}
if (!(gfp_mask & __GFP_FS))
return -1;
/*
* Return the number of reclaimable inodes in the filesystem for
* the shrinker to determine how much to reclaim.
*/
int
xfs_reclaim_inodes_count(
struct xfs_mount *mp)
{
struct xfs_perag *pag;
xfs_agnumber_t ag = 0;
int reclaimable = 0;
xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT,
&nr_to_scan);
/* terminate if we don't exhaust the scan */
if (nr_to_scan > 0)
return -1;
}
reclaimable = 0;
ag = 0;
while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
ag = pag->pag_agno + 1;
reclaimable += pag->pag_ici_reclaimable;
@ -1067,18 +1065,3 @@ xfs_reclaim_inode_shrink(
return reclaimable;
}
void
xfs_inode_shrinker_register(
struct xfs_mount *mp)
{
mp->m_inode_shrink.shrink = xfs_reclaim_inode_shrink;
mp->m_inode_shrink.seeks = DEFAULT_SEEKS;
register_shrinker(&mp->m_inode_shrink);
}
void
xfs_inode_shrinker_unregister(
struct xfs_mount *mp)
{
unregister_shrinker(&mp->m_inode_shrink);
}

View file

@ -43,6 +43,8 @@ void xfs_quiesce_attr(struct xfs_mount *mp);
void xfs_flush_inodes(struct xfs_inode *ip);
int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
int xfs_reclaim_inodes_count(struct xfs_mount *mp);
void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip);
@ -54,7 +56,4 @@ int xfs_inode_ag_iterator(struct xfs_mount *mp,
int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
int flags);
void xfs_inode_shrinker_register(struct xfs_mount *mp);
void xfs_inode_shrinker_unregister(struct xfs_mount *mp);
#endif