diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-29 22:49:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-29 22:49:34 -0400 |
commit | e97e7120eb24800cf8eb62c7da07b161cc2a8c73 (patch) | |
tree | b48bf7a1f1e8192c5e3cb4e1289adc7a378c2d8d | |
parent | fed0a9c644c7872f5bcaeb87a71103aef8e96761 (diff) | |
parent | 9bf729c0af67897ea8498ce17c29b0683f7f2028 (diff) |
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
* 'for-linus' of git://oss.sgi.com/xfs/xfs:
xfs: add a shrinker to background inode reclaim
-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 | /* |