aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2016-05-19 20:34:00 -0400
committerDave Chinner <david@fromorbit.com>2016-05-19 20:34:00 -0400
commit555b67e4e729ca544bb4028ab12e532c68b70ddb (patch)
tree8bfb59ccca39cebe0210366bebfeddd8bd3ab3a3
parent544ad71fc8e20fb3a6f50f00d487751492cd8409 (diff)
parentad438c4038968e5ca5248f851212634e474983e8 (diff)
Merge branch 'xfs-4.7-inode-reclaim' into for-next
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c27
-rw-r--r--fs/xfs/xfs_icache.c290
-rw-r--r--fs/xfs/xfs_inode.c104
-rw-r--r--fs/xfs/xfs_super.c28
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 */
1524STATIC void
1525xfs_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 */
1524void 1542void
@@ -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
40STATIC 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
100void
101xfs_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
114static 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
126void
127xfs_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 */
151static void
152xfs_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 */
171void
172xfs_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
182static void
183xfs_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
204static void
205xfs_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 */
228void
229xfs_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));