diff options
| author | Dave Chinner <david@fromorbit.com> | 2016-05-19 20:34:00 -0400 |
|---|---|---|
| committer | Dave Chinner <david@fromorbit.com> | 2016-05-19 20:34:00 -0400 |
| commit | 555b67e4e729ca544bb4028ab12e532c68b70ddb (patch) | |
| tree | 8bfb59ccca39cebe0210366bebfeddd8bd3ab3a3 | |
| parent | 544ad71fc8e20fb3a6f50f00d487751492cd8409 (diff) | |
| parent | ad438c4038968e5ca5248f851212634e474983e8 (diff) | |
Merge branch 'xfs-4.7-inode-reclaim' into for-next
| -rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.c | 27 | ||||
| -rw-r--r-- | fs/xfs/xfs_icache.c | 290 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 104 | ||||
| -rw-r--r-- | fs/xfs/xfs_super.c | 28 |
4 files changed, 250 insertions, 199 deletions
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index d3d1477bfb9e..bbcc8c7a44b3 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c | |||
| @@ -1519,6 +1519,24 @@ xfs_iext_indirect_to_direct( | |||
| 1519 | } | 1519 | } |
| 1520 | 1520 | ||
| 1521 | /* | 1521 | /* |
| 1522 | * Remove all records from the indirection array. | ||
| 1523 | */ | ||
| 1524 | STATIC void | ||
| 1525 | xfs_iext_irec_remove_all( | ||
| 1526 | struct xfs_ifork *ifp) | ||
| 1527 | { | ||
| 1528 | int nlists; | ||
| 1529 | int i; | ||
| 1530 | |||
| 1531 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | ||
| 1532 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | ||
| 1533 | for (i = 0; i < nlists; i++) | ||
| 1534 | kmem_free(ifp->if_u1.if_ext_irec[i].er_extbuf); | ||
| 1535 | kmem_free(ifp->if_u1.if_ext_irec); | ||
| 1536 | ifp->if_flags &= ~XFS_IFEXTIREC; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | /* | ||
| 1522 | * Free incore file extents. | 1540 | * Free incore file extents. |
| 1523 | */ | 1541 | */ |
| 1524 | void | 1542 | void |
| @@ -1526,14 +1544,7 @@ xfs_iext_destroy( | |||
| 1526 | xfs_ifork_t *ifp) /* inode fork pointer */ | 1544 | xfs_ifork_t *ifp) /* inode fork pointer */ |
| 1527 | { | 1545 | { |
| 1528 | if (ifp->if_flags & XFS_IFEXTIREC) { | 1546 | if (ifp->if_flags & XFS_IFEXTIREC) { |
| 1529 | int erp_idx; | 1547 | xfs_iext_irec_remove_all(ifp); |
| 1530 | int nlists; | ||
| 1531 | |||
| 1532 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | ||
| 1533 | for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) { | ||
| 1534 | xfs_iext_irec_remove(ifp, erp_idx); | ||
| 1535 | } | ||
| 1536 | ifp->if_flags &= ~XFS_IFEXTIREC; | ||
| 1537 | } else if (ifp->if_real_bytes) { | 1548 | } else if (ifp->if_real_bytes) { |
| 1538 | kmem_free(ifp->if_u1.if_extents); | 1549 | kmem_free(ifp->if_u1.if_extents); |
| 1539 | } else if (ifp->if_bytes) { | 1550 | } else if (ifp->if_bytes) { |
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index bf2d60749278..99ee6eee5e0b 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c | |||
| @@ -37,9 +37,6 @@ | |||
| 37 | #include <linux/kthread.h> | 37 | #include <linux/kthread.h> |
| 38 | #include <linux/freezer.h> | 38 | #include <linux/freezer.h> |
| 39 | 39 | ||
| 40 | STATIC void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, | ||
| 41 | struct xfs_perag *pag, struct xfs_inode *ip); | ||
| 42 | |||
| 43 | /* | 40 | /* |
| 44 | * Allocate and initialise an xfs_inode. | 41 | * Allocate and initialise an xfs_inode. |
| 45 | */ | 42 | */ |
| @@ -94,13 +91,6 @@ xfs_inode_free_callback( | |||
| 94 | struct inode *inode = container_of(head, struct inode, i_rcu); | 91 | struct inode *inode = container_of(head, struct inode, i_rcu); |
| 95 | struct xfs_inode *ip = XFS_I(inode); | 92 | struct xfs_inode *ip = XFS_I(inode); |
| 96 | 93 | ||
| 97 | kmem_zone_free(xfs_inode_zone, ip); | ||
| 98 | } | ||
| 99 | |||
| 100 | void | ||
| 101 | xfs_inode_free( | ||
| 102 | struct xfs_inode *ip) | ||
| 103 | { | ||
| 104 | switch (VFS_I(ip)->i_mode & S_IFMT) { | 94 | switch (VFS_I(ip)->i_mode & S_IFMT) { |
| 105 | case S_IFREG: | 95 | case S_IFREG: |
| 106 | case S_IFDIR: | 96 | case S_IFDIR: |
| @@ -118,6 +108,25 @@ xfs_inode_free( | |||
| 118 | ip->i_itemp = NULL; | 108 | ip->i_itemp = NULL; |
| 119 | } | 109 | } |
| 120 | 110 | ||
| 111 | kmem_zone_free(xfs_inode_zone, ip); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void | ||
| 115 | __xfs_inode_free( | ||
| 116 | struct xfs_inode *ip) | ||
| 117 | { | ||
| 118 | /* asserts to verify all state is correct here */ | ||
| 119 | ASSERT(atomic_read(&ip->i_pincount) == 0); | ||
| 120 | ASSERT(!xfs_isiflocked(ip)); | ||
| 121 | XFS_STATS_DEC(ip->i_mount, vn_active); | ||
| 122 | |||
| 123 | call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback); | ||
| 124 | } | ||
| 125 | |||
| 126 | void | ||
| 127 | xfs_inode_free( | ||
| 128 | struct xfs_inode *ip) | ||
| 129 | { | ||
| 121 | /* | 130 | /* |
| 122 | * Because we use RCU freeing we need to ensure the inode always | 131 | * Because we use RCU freeing we need to ensure the inode always |
| 123 | * appears to be reclaimed with an invalid inode number when in the | 132 | * appears to be reclaimed with an invalid inode number when in the |
| @@ -129,12 +138,123 @@ xfs_inode_free( | |||
| 129 | ip->i_ino = 0; | 138 | ip->i_ino = 0; |
| 130 | spin_unlock(&ip->i_flags_lock); | 139 | spin_unlock(&ip->i_flags_lock); |
| 131 | 140 | ||
| 132 | /* asserts to verify all state is correct here */ | 141 | __xfs_inode_free(ip); |
| 133 | ASSERT(atomic_read(&ip->i_pincount) == 0); | 142 | } |
| 134 | ASSERT(!xfs_isiflocked(ip)); | ||
| 135 | XFS_STATS_DEC(ip->i_mount, vn_active); | ||
| 136 | 143 | ||
| 137 | call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback); | 144 | /* |
| 145 | * Queue a new inode reclaim pass if there are reclaimable inodes and there | ||
| 146 | * isn't a reclaim pass already in progress. By default it runs every 5s based | ||
| 147 | * on the xfs periodic sync default of 30s. Perhaps this should have it's own | ||
| 148 | * tunable, but that can be done if this method proves to be ineffective or too | ||
| 149 | * aggressive. | ||
| 150 | */ | ||
| 151 | static void | ||
| 152 | xfs_reclaim_work_queue( | ||
| 153 | struct xfs_mount *mp) | ||
| 154 | { | ||
| 155 | |||
| 156 | rcu_read_lock(); | ||
| 157 | if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) { | ||
| 158 | queue_delayed_work(mp->m_reclaim_workqueue, &mp->m_reclaim_work, | ||
| 159 | msecs_to_jiffies(xfs_syncd_centisecs / 6 * 10)); | ||
| 160 | } | ||
| 161 | rcu_read_unlock(); | ||
| 162 | } | ||
| 163 | |||
| 164 | /* | ||
| 165 | * This is a fast pass over the inode cache to try to get reclaim moving on as | ||
| 166 | * many inodes as possible in a short period of time. It kicks itself every few | ||
| 167 | * seconds, as well as being kicked by the inode cache shrinker when memory | ||
| 168 | * goes low. It scans as quickly as possible avoiding locked inodes or those | ||
| 169 | * already being flushed, and once done schedules a future pass. | ||
| 170 | */ | ||
| 171 | void | ||
| 172 | xfs_reclaim_worker( | ||
| 173 | struct work_struct *work) | ||
| 174 | { | ||
| 175 | struct xfs_mount *mp = container_of(to_delayed_work(work), | ||
| 176 | struct xfs_mount, m_reclaim_work); | ||
| 177 | |||
| 178 | xfs_reclaim_inodes(mp, SYNC_TRYLOCK); | ||
| 179 | xfs_reclaim_work_queue(mp); | ||
| 180 | } | ||
| 181 | |||
| 182 | static void | ||
| 183 | xfs_perag_set_reclaim_tag( | ||
| 184 | struct xfs_perag *pag) | ||
| 185 | { | ||
| 186 | struct xfs_mount *mp = pag->pag_mount; | ||
| 187 | |||
| 188 | ASSERT(spin_is_locked(&pag->pag_ici_lock)); | ||
| 189 | if (pag->pag_ici_reclaimable++) | ||
| 190 | return; | ||
| 191 | |||
| 192 | /* propagate the reclaim tag up into the perag radix tree */ | ||
| 193 | spin_lock(&mp->m_perag_lock); | ||
| 194 | radix_tree_tag_set(&mp->m_perag_tree, pag->pag_agno, | ||
| 195 | XFS_ICI_RECLAIM_TAG); | ||
| 196 | spin_unlock(&mp->m_perag_lock); | ||
| 197 | |||
| 198 | /* schedule periodic background inode reclaim */ | ||
| 199 | xfs_reclaim_work_queue(mp); | ||
| 200 | |||
| 201 | trace_xfs_perag_set_reclaim(mp, pag->pag_agno, -1, _RET_IP_); | ||
| 202 | } | ||
| 203 | |||
| 204 | static void | ||
| 205 | xfs_perag_clear_reclaim_tag( | ||
| 206 | struct xfs_perag *pag) | ||
| 207 | { | ||
| 208 | struct xfs_mount *mp = pag->pag_mount; | ||
| 209 | |||
| 210 | ASSERT(spin_is_locked(&pag->pag_ici_lock)); | ||
| 211 | if (--pag->pag_ici_reclaimable) | ||
| 212 | return; | ||
| 213 | |||
| 214 | /* clear the reclaim tag from the perag radix tree */ | ||
| 215 | spin_lock(&mp->m_perag_lock); | ||
| 216 | radix_tree_tag_clear(&mp->m_perag_tree, pag->pag_agno, | ||
| 217 | XFS_ICI_RECLAIM_TAG); | ||
| 218 | spin_unlock(&mp->m_perag_lock); | ||
| 219 | trace_xfs_perag_clear_reclaim(mp, pag->pag_agno, -1, _RET_IP_); | ||
| 220 | } | ||
| 221 | |||
| 222 | |||
| 223 | /* | ||
| 224 | * We set the inode flag atomically with the radix tree tag. | ||
| 225 | * Once we get tag lookups on the radix tree, this inode flag | ||
| 226 | * can go away. | ||
| 227 | */ | ||
| 228 | void | ||
| 229 | xfs_inode_set_reclaim_tag( | ||
| 230 | struct xfs_inode *ip) | ||
| 231 | { | ||
| 232 | struct xfs_mount *mp = ip->i_mount; | ||
| 233 | struct xfs_perag *pag; | ||
| 234 | |||
| 235 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); | ||
