diff options
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_super.c | 5 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 112 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.h | 7 | ||||
| -rw-r--r-- | fs/xfs/quota/xfs_qm_syscalls.c | 3 | ||||
| -rw-r--r-- | fs/xfs/xfs_ag.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_mount.h | 1 |
6 files changed, 120 insertions, 9 deletions
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 52e06b487ced..29f1edca76de 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
| @@ -1209,6 +1209,7 @@ xfs_fs_put_super( | |||
| 1209 | 1209 | ||
| 1210 | xfs_unmountfs(mp); | 1210 | xfs_unmountfs(mp); |
| 1211 | xfs_freesb(mp); | 1211 | xfs_freesb(mp); |
| 1212 | xfs_inode_shrinker_unregister(mp); | ||
| 1212 | xfs_icsb_destroy_counters(mp); | 1213 | xfs_icsb_destroy_counters(mp); |
| 1213 | xfs_close_devices(mp); | 1214 | xfs_close_devices(mp); |
| 1214 | xfs_dmops_put(mp); | 1215 | xfs_dmops_put(mp); |
| @@ -1622,6 +1623,8 @@ xfs_fs_fill_super( | |||
| 1622 | if (error) | 1623 | if (error) |
| 1623 | goto fail_vnrele; | 1624 | goto fail_vnrele; |
| 1624 | 1625 | ||
| 1626 | xfs_inode_shrinker_register(mp); | ||
| 1627 | |||
| 1625 | kfree(mtpt); | 1628 | kfree(mtpt); |
| 1626 | return 0; | 1629 | return 0; |
| 1627 | 1630 | ||
| @@ -1867,6 +1870,7 @@ init_xfs_fs(void) | |||
| 1867 | goto out_cleanup_procfs; | 1870 | goto out_cleanup_procfs; |
| 1868 | 1871 | ||
| 1869 | vfs_initquota(); | 1872 | vfs_initquota(); |
| 1873 | xfs_inode_shrinker_init(); | ||
| 1870 | 1874 | ||
| 1871 | error = register_filesystem(&xfs_fs_type); | 1875 | error = register_filesystem(&xfs_fs_type); |
| 1872 | if (error) | 1876 | if (error) |
| @@ -1894,6 +1898,7 @@ exit_xfs_fs(void) | |||
| 1894 | { | 1898 | { |
| 1895 | vfs_exitquota(); | 1899 | vfs_exitquota(); |
| 1896 | unregister_filesystem(&xfs_fs_type); | 1900 | unregister_filesystem(&xfs_fs_type); |
| 1901 | xfs_inode_shrinker_destroy(); | ||
| 1897 | xfs_sysctl_unregister(); | 1902 | xfs_sysctl_unregister(); |
| 1898 | xfs_cleanup_procfs(); | 1903 | xfs_cleanup_procfs(); |
| 1899 | xfs_buf_terminate(); | 1904 | xfs_buf_terminate(); |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index fd9698215759..a427c638d909 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
| @@ -95,7 +95,8 @@ xfs_inode_ag_walk( | |||
| 95 | struct xfs_perag *pag, int flags), | 95 | struct xfs_perag *pag, int flags), |
| 96 | int flags, | 96 | int flags, |
| 97 | int tag, | 97 | int tag, |
| 98 | int exclusive) | 98 | int exclusive, |
| 99 | int *nr_to_scan) | ||
| 99 | { | 100 | { |
| 100 | uint32_t first_index; | 101 | uint32_t first_index; |
| 101 | int last_error = 0; | 102 | int last_error = 0; |
| @@ -134,7 +135,7 @@ restart: | |||
| 134 | if (error == EFSCORRUPTED) | 135 | if (error == EFSCORRUPTED) |
| 135 | break; | 136 | break; |
| 136 | 137 | ||
| 137 | } while (1); | 138 | } while ((*nr_to_scan)--); |
| 138 | 139 | ||
| 139 | if (skipped) { | 140 | if (skipped) { |
| 140 | delay(1); | 141 | delay(1); |
| @@ -150,12 +151,15 @@ xfs_inode_ag_iterator( | |||
| 150 | struct xfs_perag *pag, int flags), | 151 | struct xfs_perag *pag, int flags), |
| 151 | int flags, | 152 | int flags, |
| 152 | int tag, | 153 | int tag, |
| 153 | int exclusive) | 154 | int exclusive, |
| 155 | int *nr_to_scan) | ||
| 154 | { | 156 | { |
| 155 | int error = 0; | 157 | int error = 0; |
| 156 | int last_error = 0; | 158 | int last_error = 0; |
| 157 | xfs_agnumber_t ag; | 159 | xfs_agnumber_t ag; |
| 160 | int nr; | ||
| 158 | 161 | ||
| 162 | nr = nr_to_scan ? *nr_to_scan : INT_MAX; | ||
| 159 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { | 163 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { |
| 160 | struct xfs_perag *pag; | 164 | struct xfs_perag *pag; |
| 161 | 165 | ||
| @@ -165,14 +169,18 @@ xfs_inode_ag_iterator( | |||
| 165 | continue; | 169 | continue; |
| 166 | } | 170 | } |
| 167 | error = xfs_inode_ag_walk(mp, pag, execute, flags, tag, | 171 | error = xfs_inode_ag_walk(mp, pag, execute, flags, tag, |
| 168 | exclusive); | 172 | exclusive, &nr); |
| 169 | xfs_perag_put(pag); | 173 | xfs_perag_put(pag); |
| 170 | if (error) { | 174 | if (error) { |
| 171 | last_error = error; | 175 | last_error = error; |
| 172 | if (error == EFSCORRUPTED) | 176 | if (error == EFSCORRUPTED) |
| 173 | break; | 177 | break; |
| 174 | } | 178 | } |
| 179 | if (nr <= 0) | ||
| 180 | break; | ||
| 175 | } | 181 | } |
| 182 | if (nr_to_scan) | ||
| 183 | *nr_to_scan = nr; | ||
| 176 | return XFS_ERROR(last_error); | 184 | return XFS_ERROR(last_error); |
| 177 | } | 185 | } |
| 178 | 186 | ||
| @@ -291,7 +299,7 @@ xfs_sync_data( | |||
| 291 | ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0); | 299 | ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0); |
| 292 | 300 | ||
| 293 | error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags, | 301 | error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags, |
| 294 | XFS_ICI_NO_TAG, 0); | 302 | XFS_ICI_NO_TAG, 0, NULL); |
| 295 | if (error) | 303 | if (error) |
| 296 | return XFS_ERROR(error); | 304 | return XFS_ERROR(error); |
| 297 | 305 | ||
| @@ -310,7 +318,7 @@ xfs_sync_attr( | |||
| 310 | ASSERT((flags & ~SYNC_WAIT) == 0); | 318 | ASSERT((flags & ~SYNC_WAIT) == 0); |
| 311 | 319 | ||
| 312 | return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags, | 320 | return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags, |
| 313 | XFS_ICI_NO_TAG, 0); | 321 | XFS_ICI_NO_TAG, 0, NULL); |
| 314 | } | 322 | } |
| 315 | 323 | ||
| 316 | STATIC int | 324 | STATIC int |
| @@ -673,6 +681,7 @@ __xfs_inode_set_reclaim_tag( | |||
| 673 | radix_tree_tag_set(&pag->pag_ici_root, | 681 | radix_tree_tag_set(&pag->pag_ici_root, |
| 674 | XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), | 682 | XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), |
| 675 | XFS_ICI_RECLAIM_TAG); | 683 | XFS_ICI_RECLAIM_TAG); |
| 684 | pag->pag_ici_reclaimable++; | ||
| 676 | } | 685 | } |
| 677 | 686 | ||
| 678 | /* | 687 | /* |
| @@ -705,6 +714,7 @@ __xfs_inode_clear_reclaim_tag( | |||
| 705 | { | 714 | { |
| 706 | radix_tree_tag_clear(&pag->pag_ici_root, | 715 | radix_tree_tag_clear(&pag->pag_ici_root, |
| 707 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); | 716 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); |
| 717 | pag->pag_ici_reclaimable--; | ||
| 708 | } | 718 | } |
| 709 | 719 | ||
| 710 | /* | 720 | /* |
| @@ -854,5 +864,93 @@ xfs_reclaim_inodes( | |||
| 854 | int mode) | 864 | int mode) |
| 855 | { | 865 | { |
| 856 | return xfs_inode_ag_iterator(mp, xfs_reclaim_inode, mode, | 866 | 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 | */ | ||
| 877 | static LIST_HEAD(xfs_mount_list); | ||
| 878 | static struct rw_semaphore xfs_mount_list_lock; | ||
| 879 | |||
| 880 | static int | ||
| 881 | xfs_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 | |||
| 921 | static struct shrinker xfs_inode_shrinker = { | ||
| 922 | .shrink = xfs_reclaim_inode_shrink, | ||
| 923 | .seeks = DEFAULT_SEEKS, | ||
| 924 | }; | ||
| 925 | |||
| 926 | void __init | ||
| 927 | xfs_inode_shrinker_init(void) | ||
| 928 | { | ||
| 929 | init_rwsem(&xfs_mount_list_lock); | ||
| 930 | register_shrinker(&xfs_inode_shrinker); | ||
| 931 | } | ||
| 932 | |||
| 933 | void | ||
| 934 | xfs_inode_shrinker_destroy(void) | ||
| 935 | { | ||
| 936 | ASSERT(list_empty(&xfs_mount_list)); | ||
| 937 | unregister_shrinker(&xfs_inode_shrinker); | ||
| 938 | } | ||
| 939 | |||
| 940 | void | ||
| 941 | xfs_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 | |||
| 949 | void | ||
| 950 | xfs_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); | ||
| 858 | } | 956 | } |
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index d480c346cabb..cdcbaaca9880 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h | |||
| @@ -53,6 +53,11 @@ void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag, | |||
| 53 | int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag); | 53 | int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag); |
| 54 | int xfs_inode_ag_iterator(struct xfs_mount *mp, | 54 | int xfs_inode_ag_iterator(struct xfs_mount *mp, |
| 55 | int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), | 55 | 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 | |||
| 58 | void xfs_inode_shrinker_init(void); | ||
| 59 | void xfs_inode_shrinker_destroy(void); | ||
| 60 | void xfs_inode_shrinker_register(struct xfs_mount *mp); | ||
| 61 | void xfs_inode_shrinker_unregister(struct xfs_mount *mp); | ||
| 57 | 62 | ||
| 58 | #endif | 63 | #endif |
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 5d0ee8d492db..50bee07d6b0e 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c | |||
| @@ -891,7 +891,8 @@ xfs_qm_dqrele_all_inodes( | |||
| 891 | uint flags) | 891 | uint flags) |
| 892 | { | 892 | { |
| 893 | ASSERT(mp->m_quotainfo); | 893 | 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); | ||
| 895 | } | 896 | } |
| 896 | 897 | ||
| 897 | /*------------------------------------------------------------------------*/ | 898 | /*------------------------------------------------------------------------*/ |
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index b1a5a1ff88ea..abb8222b88c9 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h | |||
| @@ -223,6 +223,7 @@ typedef struct xfs_perag { | |||
| 223 | int pag_ici_init; /* incore inode cache initialised */ | 223 | int pag_ici_init; /* incore inode cache initialised */ |
| 224 | rwlock_t pag_ici_lock; /* incore inode lock */ | 224 | rwlock_t pag_ici_lock; /* incore inode lock */ |
| 225 | struct radix_tree_root pag_ici_root; /* incore inode cache root */ | 225 | struct radix_tree_root pag_ici_root; /* incore inode cache root */ |
| 226 | int pag_ici_reclaimable; /* reclaimable inodes */ | ||
| 226 | #endif | 227 | #endif |
| 227 | int pagb_count; /* pagb slots in use */ | 228 | int pagb_count; /* pagb slots in use */ |
| 228 | xfs_perag_busy_t pagb_list[XFS_PAGB_NUM_SLOTS]; /* unstable blocks */ | 229 | xfs_perag_busy_t pagb_list[XFS_PAGB_NUM_SLOTS]; /* unstable blocks */ |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 4fa0bc7b983e..9ff48a16a7ee 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
| @@ -259,6 +259,7 @@ typedef struct xfs_mount { | |||
| 259 | wait_queue_head_t m_wait_single_sync_task; | 259 | wait_queue_head_t m_wait_single_sync_task; |
| 260 | __int64_t m_update_flags; /* sb flags we need to update | 260 | __int64_t m_update_flags; /* sb flags we need to update |
| 261 | on the next remount,rw */ | 261 | on the next remount,rw */ |
| 262 | struct list_head m_mplist; /* inode shrinker mount list */ | ||
| 262 | } xfs_mount_t; | 263 | } xfs_mount_t; |
| 263 | 264 | ||
| 264 | /* | 265 | /* |
