diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_sync.c')
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 112 |
1 files changed, 105 insertions, 7 deletions
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 | } |
