diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_sync.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 107 |
1 files changed, 100 insertions, 7 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 6b6b39416ad3..57adf2d60dfc 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 | struct xfs_perag *pag = &mp->m_perag[ag]; | 101 | struct xfs_perag *pag = &mp->m_perag[ag]; |
101 | uint32_t first_index; | 102 | uint32_t first_index; |
@@ -135,7 +136,7 @@ restart: | |||
135 | if (error == EFSCORRUPTED) | 136 | if (error == EFSCORRUPTED) |
136 | break; | 137 | break; |
137 | 138 | ||
138 | } while (1); | 139 | } while ((*nr_to_scan)--); |
139 | 140 | ||
140 | if (skipped) { | 141 | if (skipped) { |
141 | delay(1); | 142 | delay(1); |
@@ -153,23 +154,30 @@ xfs_inode_ag_iterator( | |||
153 | struct xfs_perag *pag, int flags), | 154 | struct xfs_perag *pag, int flags), |
154 | int flags, | 155 | int flags, |
155 | int tag, | 156 | int tag, |
156 | int exclusive) | 157 | int exclusive, |
158 | int *nr_to_scan) | ||
157 | { | 159 | { |
158 | int error = 0; | 160 | int error = 0; |
159 | int last_error = 0; | 161 | int last_error = 0; |
160 | xfs_agnumber_t ag; | 162 | xfs_agnumber_t ag; |
163 | int nr; | ||
161 | 164 | ||
165 | nr = nr_to_scan ? *nr_to_scan : INT_MAX; | ||
162 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { | 166 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { |
163 | if (!mp->m_perag[ag].pag_ici_init) | 167 | if (!mp->m_perag[ag].pag_ici_init) |
164 | continue; | 168 | continue; |
165 | error = xfs_inode_ag_walk(mp, ag, execute, flags, tag, | 169 | error = xfs_inode_ag_walk(mp, ag, execute, flags, tag, |
166 | exclusive); | 170 | exclusive, &nr); |
167 | if (error) { | 171 | if (error) { |
168 | last_error = error; | 172 | last_error = error; |
169 | if (error == EFSCORRUPTED) | 173 | if (error == EFSCORRUPTED) |
170 | break; | 174 | break; |
171 | } | 175 | } |
176 | if (nr <= 0) | ||
177 | break; | ||
172 | } | 178 | } |
179 | if (nr_to_scan) | ||
180 | *nr_to_scan = nr; | ||
173 | return XFS_ERROR(last_error); | 181 | return XFS_ERROR(last_error); |
174 | } | 182 | } |
175 | 183 | ||
@@ -289,7 +297,7 @@ xfs_sync_data( | |||
289 | ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0); | 297 | ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0); |
290 | 298 | ||
291 | error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags, | 299 | error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags, |
292 | XFS_ICI_NO_TAG, 0); | 300 | XFS_ICI_NO_TAG, 0, NULL); |
293 | if (error) | 301 | if (error) |
294 | return XFS_ERROR(error); | 302 | return XFS_ERROR(error); |
295 | 303 | ||
@@ -311,7 +319,7 @@ xfs_sync_attr( | |||
311 | ASSERT((flags & ~SYNC_WAIT) == 0); | 319 | ASSERT((flags & ~SYNC_WAIT) == 0); |
312 | 320 | ||
313 | return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags, | 321 | return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags, |
314 | XFS_ICI_NO_TAG, 0); | 322 | XFS_ICI_NO_TAG, 0, NULL); |
315 | } | 323 | } |
316 | 324 | ||
317 | STATIC int | 325 | STATIC int |
@@ -679,6 +687,7 @@ __xfs_inode_set_reclaim_tag( | |||
679 | radix_tree_tag_set(&pag->pag_ici_root, | 687 | radix_tree_tag_set(&pag->pag_ici_root, |
680 | XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), | 688 | XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), |
681 | XFS_ICI_RECLAIM_TAG); | 689 | XFS_ICI_RECLAIM_TAG); |
690 | pag->pag_ici_reclaimable++; | ||
682 | } | 691 | } |
683 | 692 | ||
684 | /* | 693 | /* |
@@ -710,6 +719,7 @@ __xfs_inode_clear_reclaim_tag( | |||
710 | { | 719 | { |
711 | radix_tree_tag_clear(&pag->pag_ici_root, | 720 | radix_tree_tag_clear(&pag->pag_ici_root, |
712 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); | 721 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); |
722 | pag->pag_ici_reclaimable--; | ||
713 | } | 723 | } |
714 | 724 | ||
715 | STATIC int | 725 | STATIC int |
@@ -770,5 +780,88 @@ xfs_reclaim_inodes( | |||
770 | int mode) | 780 | int mode) |
771 | { | 781 | { |
772 | return xfs_inode_ag_iterator(mp, xfs_reclaim_inode, mode, | 782 | return xfs_inode_ag_iterator(mp, xfs_reclaim_inode, mode, |
773 | XFS_ICI_RECLAIM_TAG, 1); | 783 | XFS_ICI_RECLAIM_TAG, 1, NULL); |
784 | } | ||
785 | |||
786 | /* | ||
787 | * Shrinker infrastructure. | ||
788 | * | ||
789 | * This is all far more complex than it needs to be. It adds a global list of | ||
790 | * mounts because the shrinkers can only call a global context. We need to make | ||
791 | * the shrinkers pass a context to avoid the need for global state. | ||
792 | */ | ||
793 | static LIST_HEAD(xfs_mount_list); | ||
794 | static struct rw_semaphore xfs_mount_list_lock; | ||
795 | |||
796 | static int | ||
797 | xfs_reclaim_inode_shrink( | ||
798 | int nr_to_scan, | ||
799 | gfp_t gfp_mask) | ||
800 | { | ||
801 | struct xfs_mount *mp; | ||
802 | xfs_agnumber_t ag; | ||
803 | int reclaimable = 0; | ||
804 | |||
805 | if (nr_to_scan) { | ||
806 | if (!(gfp_mask & __GFP_FS)) | ||
807 | return -1; | ||
808 | |||
809 | down_read(&xfs_mount_list_lock); | ||
810 | list_for_each_entry(mp, &xfs_mount_list, m_mplist) { | ||
811 | xfs_inode_ag_iterator(mp, xfs_reclaim_inode, 0, | ||
812 | XFS_ICI_RECLAIM_TAG, 1, &nr_to_scan); | ||
813 | if (nr_to_scan <= 0) | ||
814 | break; | ||
815 | } | ||
816 | up_read(&xfs_mount_list_lock); | ||
817 | } | ||
818 | |||
819 | down_read(&xfs_mount_list_lock); | ||
820 | list_for_each_entry(mp, &xfs_mount_list, m_mplist) { | ||
821 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { | ||
822 | |||
823 | if (!mp->m_perag[ag].pag_ici_init) | ||
824 | continue; | ||
825 | reclaimable += mp->m_perag[ag].pag_ici_reclaimable; | ||
826 | } | ||
827 | } | ||
828 | up_read(&xfs_mount_list_lock); | ||
829 | return reclaimable; | ||
830 | } | ||
831 | |||
832 | static struct shrinker xfs_inode_shrinker = { | ||
833 | .shrink = xfs_reclaim_inode_shrink, | ||
834 | .seeks = DEFAULT_SEEKS, | ||
835 | }; | ||
836 | |||
837 | void __init | ||
838 | xfs_inode_shrinker_init(void) | ||
839 | { | ||
840 | init_rwsem(&xfs_mount_list_lock); | ||
841 | register_shrinker(&xfs_inode_shrinker); | ||
842 | } | ||
843 | |||
844 | void | ||
845 | xfs_inode_shrinker_destroy(void) | ||
846 | { | ||
847 | ASSERT(list_empty(&xfs_mount_list)); | ||
848 | unregister_shrinker(&xfs_inode_shrinker); | ||
849 | } | ||
850 | |||
851 | void | ||
852 | xfs_inode_shrinker_register( | ||
853 | struct xfs_mount *mp) | ||
854 | { | ||
855 | down_write(&xfs_mount_list_lock); | ||
856 | list_add_tail(&mp->m_mplist, &xfs_mount_list); | ||
857 | up_write(&xfs_mount_list_lock); | ||
858 | } | ||
859 | |||
860 | void | ||
861 | xfs_inode_shrinker_unregister( | ||
862 | struct xfs_mount *mp) | ||
863 | { | ||
864 | down_write(&xfs_mount_list_lock); | ||
865 | list_del(&mp->m_mplist); | ||
866 | up_write(&xfs_mount_list_lock); | ||
774 | } | 867 | } |