Date:2010-04-29 01:55:50 (12 years 5 months ago)
Author:Dave Chinner
Commit:9bf729c0af67897ea8498ce17c29b0683f7f2028
Message:xfs: add a shrinker to background inode reclaim

On low memory boxes or those with highmem, kernel can OOM before the
background reclaims inodes via xfssyncd. Add a shrinker to run inode
reclaim so that it inode reclaim is expedited when memory is low.

This is more complex than it needs to be because the VM folk don't
want a context added to the shrinker infrastructure. Hence we need
to add a global list of XFS mount structures so the shrinker can
traverse them.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Files: fs/xfs/linux-2.6/xfs_super.c (4 diffs)
fs/xfs/linux-2.6/xfs_sync.c (9 diffs)
fs/xfs/linux-2.6/xfs_sync.h (1 diff)
fs/xfs/quota/xfs_qm_syscalls.c (1 diff)
fs/xfs/xfs_ag.h (1 diff)
fs/xfs/xfs_mount.h (1 diff)

Change Details

fs/xfs/linux-2.6/xfs_super.c
12091209
12101210    xfs_unmountfs(mp);
12111211    xfs_freesb(mp);
1212    xfs_inode_shrinker_unregister(mp);
12121213    xfs_icsb_destroy_counters(mp);
12131214    xfs_close_devices(mp);
12141215    xfs_dmops_put(mp);
...... 
16221623    if (error)
16231624        goto fail_vnrele;
16241625
1626    xfs_inode_shrinker_register(mp);
1627
16251628    kfree(mtpt);
16261629    return 0;
16271630
...... 
18671870        goto out_cleanup_procfs;
18681871
18691872    vfs_initquota();
1873    xfs_inode_shrinker_init();
18701874
18711875    error = register_filesystem(&xfs_fs_type);
18721876    if (error)
...... 
18941898{
18951899    vfs_exitquota();
18961900    unregister_filesystem(&xfs_fs_type);
1901    xfs_inode_shrinker_destroy();
18971902    xfs_sysctl_unregister();
18981903    xfs_cleanup_procfs();
18991904    xfs_buf_terminate();
fs/xfs/linux-2.6/xfs_sync.c
9595                       struct xfs_perag *pag, int flags),
9696    int flags,
9797    int tag,
98    int exclusive)
98    int exclusive,
99    int *nr_to_scan)
99100{
100101    uint32_t first_index;
101102    int last_error = 0;
...... 
134135        if (error == EFSCORRUPTED)
135136            break;
136137
137    } while (1);
138    } while ((*nr_to_scan)--);
138139
139140    if (skipped) {
140141        delay(1);
...... 
150151                       struct xfs_perag *pag, int flags),
151152    int flags,
152153    int tag,
153    int exclusive)
154    int exclusive,
155    int *nr_to_scan)
154156{
155157    int error = 0;
156158    int last_error = 0;
157159    xfs_agnumber_t ag;
160    int nr;
158161
162    nr = nr_to_scan ? *nr_to_scan : INT_MAX;
159163    for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
160164        struct xfs_perag *pag;
161165
...... 
165169            continue;
166170        }
167171        error = xfs_inode_ag_walk(mp, pag, execute, flags, tag,
168                        exclusive);
172                        exclusive, &nr);
169173        xfs_perag_put(pag);
170174        if (error) {
171175            last_error = error;
172176            if (error == EFSCORRUPTED)
173177                break;
174178        }
179        if (nr <= 0)
180            break;
175181    }
182    if (nr_to_scan)
183        *nr_to_scan = nr;
176184    return XFS_ERROR(last_error);
177185}
178186
...... 
291299    ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0);
292300
293301    error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags,
294                      XFS_ICI_NO_TAG, 0);
302                      XFS_ICI_NO_TAG, 0, NULL);
295303    if (error)
296304        return XFS_ERROR(error);
297305
...... 
310318    ASSERT((flags & ~SYNC_WAIT) == 0);
311319
312320    return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags,
313                     XFS_ICI_NO_TAG, 0);
321                     XFS_ICI_NO_TAG, 0, NULL);
314322}
315323
316324STATIC int
...... 
673681    radix_tree_tag_set(&pag->pag_ici_root,
674682               XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),
675683               XFS_ICI_RECLAIM_TAG);
684    pag->pag_ici_reclaimable++;
676685}
677686
678687/*
...... 
705714{
706715    radix_tree_tag_clear(&pag->pag_ici_root,
707716            XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
717    pag->pag_ici_reclaimable--;
708718}
709719
710720/*
...... 
854864    int mode)
855865{
856866    return xfs_inode_ag_iterator(mp, xfs_reclaim_inode, mode,
857                    XFS_ICI_RECLAIM_TAG, 1);
867                    XFS_ICI_RECLAIM_TAG, 1, NULL);
868}
869
870/*
871 * Shrinker infrastructure.
872 *
873 * This is all far more complex than it needs to be. It adds a global list of
874 * mounts because the shrinkers can only call a global context. We need to make
875 * the shrinkers pass a context to avoid the need for global state.
876 */
877static LIST_HEAD(xfs_mount_list);
878static struct rw_semaphore xfs_mount_list_lock;
879
880static int
881xfs_reclaim_inode_shrink(
882    int nr_to_scan,
883    gfp_t gfp_mask)
884{
885    struct xfs_mount *mp;
886    struct xfs_perag *pag;
887    xfs_agnumber_t ag;
888    int reclaimable = 0;
889
890    if (nr_to_scan) {
891        if (!(gfp_mask & __GFP_FS))
892            return -1;
893
894        down_read(&xfs_mount_list_lock);
895        list_for_each_entry(mp, &xfs_mount_list, m_mplist) {
896            xfs_inode_ag_iterator(mp, xfs_reclaim_inode, 0,
897                    XFS_ICI_RECLAIM_TAG, 1, &nr_to_scan);
898            if (nr_to_scan <= 0)
899                break;
900        }
901        up_read(&xfs_mount_list_lock);
902    }
903
904    down_read(&xfs_mount_list_lock);
905    list_for_each_entry(mp, &xfs_mount_list, m_mplist) {
906        for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
907
908            pag = xfs_perag_get(mp, ag);
909            if (!pag->pag_ici_init) {
910                xfs_perag_put(pag);
911                continue;
912            }
913            reclaimable += pag->pag_ici_reclaimable;
914            xfs_perag_put(pag);
915        }
916    }
917    up_read(&xfs_mount_list_lock);
918    return reclaimable;
919}
920
921static struct shrinker xfs_inode_shrinker = {
922    .shrink = xfs_reclaim_inode_shrink,
923    .seeks = DEFAULT_SEEKS,
924};
925
926void __init
927xfs_inode_shrinker_init(void)
928{
929    init_rwsem(&xfs_mount_list_lock);
930    register_shrinker(&xfs_inode_shrinker);
931}
932
933void
934xfs_inode_shrinker_destroy(void)
935{
936    ASSERT(list_empty(&xfs_mount_list));
937    unregister_shrinker(&xfs_inode_shrinker);
938}
939
940void
941xfs_inode_shrinker_register(
942    struct xfs_mount *mp)
943{
944    down_write(&xfs_mount_list_lock);
945    list_add_tail(&mp->m_mplist, &xfs_mount_list);
946    up_write(&xfs_mount_list_lock);
947}
948
949void
950xfs_inode_shrinker_unregister(
951    struct xfs_mount *mp)
952{
953    down_write(&xfs_mount_list_lock);
954    list_del(&mp->m_mplist);
955    up_write(&xfs_mount_list_lock);
858956}
fs/xfs/linux-2.6/xfs_sync.h
5353int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag);
5454int xfs_inode_ag_iterator(struct xfs_mount *mp,
5555    int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
56    int flags, int tag, int write_lock);
56    int flags, int tag, int write_lock, int *nr_to_scan);
57
58void xfs_inode_shrinker_init(void);
59void xfs_inode_shrinker_destroy(void);
60void xfs_inode_shrinker_register(struct xfs_mount *mp);
61void xfs_inode_shrinker_unregister(struct xfs_mount *mp);
5762
5863#endif
fs/xfs/quota/xfs_qm_syscalls.c
891891    uint flags)
892892{
893893    ASSERT(mp->m_quotainfo);
894    xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags, XFS_ICI_NO_TAG, 0);
894    xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags,
895                XFS_ICI_NO_TAG, 0, NULL);
895896}
896897
897898/*------------------------------------------------------------------------*/
fs/xfs/xfs_ag.h
223223    int pag_ici_init; /* incore inode cache initialised */
224224    rwlock_t pag_ici_lock; /* incore inode lock */
225225    struct radix_tree_root pag_ici_root; /* incore inode cache root */
226    int pag_ici_reclaimable; /* reclaimable inodes */
226227#endif
227228    int pagb_count; /* pagb slots in use */
228229    xfs_perag_busy_t pagb_list[XFS_PAGB_NUM_SLOTS]; /* unstable blocks */
fs/xfs/xfs_mount.h
259259    wait_queue_head_t m_wait_single_sync_task;
260260    __int64_t m_update_flags; /* sb flags we need to update
261261                           on the next remount,rw */
262    struct list_head m_mplist; /* inode shrinker mount list */
262263} xfs_mount_t;
263264
264265/*

Archive Download the corresponding diff file



interactive