aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/linux-2.6/xfs_sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_sync.c')
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c107
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
317STATIC int 325STATIC 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
715STATIC int 725STATIC 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 */
793static LIST_HEAD(xfs_mount_list);
794static struct rw_semaphore xfs_mount_list_lock;
795
796static int
797xfs_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
832static struct shrinker xfs_inode_shrinker = {
833 .shrink = xfs_reclaim_inode_shrink,
834 .seeks = DEFAULT_SEEKS,
835};
836
837void __init
838xfs_inode_shrinker_init(void)
839{
840 init_rwsem(&xfs_mount_list_lock);
841 register_shrinker(&xfs_inode_shrinker);
842}
843
844void
845xfs_inode_shrinker_destroy(void)
846{
847 ASSERT(list_empty(&xfs_mount_list));
848 unregister_shrinker(&xfs_inode_shrinker);
849}
850
851void
852xfs_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
860void
861xfs_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}