aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2009-06-08 09:35:14 -0400
committerChristoph Hellwig <hch@brick.lst.de>2009-06-08 09:35:14 -0400
commit75f3cb1393133682958db6f157e1b6473e5a366b (patch)
treee2e22c20c20e7d37e64b8f7fa4148253be01364a
parentabc1064742604e60a47a65fa3214dc1a84db093d (diff)
xfs: introduce a per-ag inode iterator
Given that we walk across the per-ag inode lists so often, it makes sense to introduce an iterator for this. Convert the sync and reclaim code to use this new iterator, quota code will follow in the next patch. Also change xfs_reclaim_inode to return -EGAIN instead of 1 for an inode already under reclaim. This simplifies the AG iterator and doesn't matter for the only other caller. [hch: merged the lookup and execute callbacks back into one to get the pag_ici_lock locking correct and simplify the code flow] Signed-off-by: Dave Chinner <david@fromorbit.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Eric Sandeen <sandeen@sandeen.net>
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c316
-rw-r--r--fs/xfs/xfs_ag.h2
2 files changed, 152 insertions, 166 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 7eb9d9cca52a..9798643feb3b 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -49,6 +49,123 @@
49#include <linux/freezer.h> 49#include <linux/freezer.h>
50 50
51 51
52STATIC xfs_inode_t *
53xfs_inode_ag_lookup(
54 struct xfs_mount *mp,
55 struct xfs_perag *pag,
56 uint32_t *first_index,
57 int tag)
58{
59 int nr_found;
60 struct xfs_inode *ip;
61
62 /*
63 * use a gang lookup to find the next inode in the tree
64 * as the tree is sparse and a gang lookup walks to find
65 * the number of objects requested.
66 */
67 read_lock(&pag->pag_ici_lock);
68 if (tag == XFS_ICI_NO_TAG) {
69 nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
70 (void **)&ip, *first_index, 1);
71 } else {
72 nr_found = radix_tree_gang_lookup_tag(&pag->pag_ici_root,
73 (void **)&ip, *first_index, 1, tag);
74 }
75 if (!nr_found)
76 goto unlock;
77
78 /*
79 * Update the index for the next lookup. Catch overflows
80 * into the next AG range which can occur if we have inodes
81 * in the last block of the AG and we are currently
82 * pointing to the last inode.
83 */
84 *first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
85 if (*first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
86 goto unlock;
87
88 return ip;
89
90unlock:
91 read_unlock(&pag->pag_ici_lock);
92 return NULL;
93}
94
95STATIC int
96xfs_inode_ag_walk(
97 struct xfs_mount *mp,
98 xfs_agnumber_t ag,
99 int (*execute)(struct xfs_inode *ip,
100 struct xfs_perag *pag, int flags),
101 int flags,
102 int tag)
103{
104 struct xfs_perag *pag = &mp->m_perag[ag];
105 uint32_t first_index;
106 int last_error = 0;
107 int skipped;
108
109restart:
110 skipped = 0;
111 first_index = 0;
112 do {
113 int error = 0;
114 xfs_inode_t *ip;
115
116 ip = xfs_inode_ag_lookup(mp, pag, &first_index, tag);
117 if (!ip)
118 break;
119
120 error = execute(ip, pag, flags);
121 if (error == EAGAIN) {
122 skipped++;
123 continue;
124 }
125 if (error)
126 last_error = error;
127 /*
128 * bail out if the filesystem is corrupted.
129 */
130 if (error == EFSCORRUPTED)
131 break;
132
133 } while (1);
134
135 if (skipped) {
136 delay(1);
137 goto restart;
138 }
139
140 xfs_put_perag(mp, pag);
141 return last_error;
142}
143
144STATIC int
145xfs_inode_ag_iterator(
146 struct xfs_mount *mp,
147 int (*execute)(struct xfs_inode *ip,
148 struct xfs_perag *pag, int flags),
149 int flags,
150 int tag)
151{
152 int error = 0;
153 int last_error = 0;
154 xfs_agnumber_t ag;
155
156 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
157 if (!mp->m_perag[ag].pag_ici_init)
158 continue;
159 error = xfs_inode_ag_walk(mp, ag, execute, flags, tag);
160 if (error) {
161 last_error = error;
162 if (error == EFSCORRUPTED)
163 break;
164 }
165 }
166 return XFS_ERROR(last_error);
167}
168
52/* must be called with pag_ici_lock held and releases it */ 169/* must be called with pag_ici_lock held and releases it */
53STATIC int 170STATIC int
54xfs_sync_inode_valid( 171xfs_sync_inode_valid(
@@ -85,12 +202,17 @@ xfs_sync_inode_valid(
85STATIC int 202STATIC int
86xfs_sync_inode_data( 203xfs_sync_inode_data(
87 struct xfs_inode *ip, 204 struct xfs_inode *ip,
205 struct xfs_perag *pag,
88 int flags) 206 int flags)
89{ 207{
90 struct inode *inode = VFS_I(ip); 208 struct inode *inode = VFS_I(ip);
91 struct address_space *mapping = inode->i_mapping; 209 struct address_space *mapping = inode->i_mapping;
92 int error = 0; 210 int error = 0;
93 211
212 error = xfs_sync_inode_valid(ip, pag);
213 if (error)
214 return error;
215
94 if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) 216 if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
95 goto out_wait; 217 goto out_wait;
96 218
@@ -107,16 +229,22 @@ xfs_sync_inode_data(
107 out_wait: 229 out_wait:
108 if (flags & SYNC_IOWAIT) 230 if (flags & SYNC_IOWAIT)
109 xfs_ioend_wait(ip); 231 xfs_ioend_wait(ip);
232 IRELE(ip);
110 return error; 233 return error;
111} 234}
112 235
113STATIC int 236STATIC int
114xfs_sync_inode_attr( 237xfs_sync_inode_attr(
115 struct xfs_inode *ip, 238 struct xfs_inode *ip,
239 struct xfs_perag *pag,
116 int flags) 240 int flags)
117{ 241{
118 int error = 0; 242 int error = 0;
119 243
244 error = xfs_sync_inode_valid(ip, pag);
245 if (error)
246 return error;
247
120 xfs_ilock(ip, XFS_ILOCK_SHARED); 248 xfs_ilock(ip, XFS_ILOCK_SHARED);
121 if (xfs_inode_clean(ip)) 249 if (xfs_inode_clean(ip))
122 goto out_unlock; 250 goto out_unlock;
@@ -136,117 +264,33 @@ xfs_sync_inode_attr(
136 264
137 out_unlock: 265 out_unlock:
138 xfs_iunlock(ip, XFS_ILOCK_SHARED); 266 xfs_iunlock(ip, XFS_ILOCK_SHARED);
267 IRELE(ip);
139 return error; 268 return error;
140} 269}
141 270
142/*
143 * Sync all the inodes in the given AG according to the
144 * direction given by the flags.
145 */
146STATIC int
147xfs_sync_inodes_ag(
148 xfs_mount_t *mp,
149 int ag,
150 int flags)
151{
152 xfs_perag_t *pag = &mp->m_perag[ag];
153 int nr_found;
154 uint32_t first_index = 0;
155 int error = 0;
156 int last_error = 0;
157
158 do {
159 xfs_inode_t *ip = NULL;
160
161 /*
162 * use a gang lookup to find the next inode in the tree
163 * as the tree is sparse and a gang lookup walks to find
164 * the number of objects requested.
165 */
166 read_lock(&pag->pag_ici_lock);
167 nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
168 (void**)&ip, first_index, 1);
169
170 if (!nr_found) {
171 read_unlock(&pag->pag_ici_lock);
172 break;
173 }
174
175 /*
176 * Update the index for the next lookup. Catch overflows
177 * into the next AG range which can occur if we have inodes
178 * in the last block of the AG and we are currently
179 * pointing to the last inode.
180 */
181 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
182 if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
183 read_unlock(&pag->pag_ici_lock);
184 break;
185 }
186
187 error = xfs_sync_inode_valid(ip, pag);
188 if (error) {
189 if (error == EFSCORRUPTED)
190 return 0;
191 continue;
192 }
193
194 /*
195 * If we have to flush data or wait for I/O completion
196 * we need to hold the iolock.
197 */
198 if (flags & SYNC_DELWRI)
199 error = xfs_sync_inode_data(ip, flags);
200
201 if (flags & SYNC_ATTR)
202 error = xfs_sync_inode_attr(ip, flags);
203
204 IRELE(ip);
205
206 if (error)
207 last_error = error;
208 /*
209 * bail out if the filesystem is corrupted.
210 */
211 if (error == EFSCORRUPTED)
212 return XFS_ERROR(error);
213
214 } while (nr_found);
215
216 return last_error;
217}
218
219int 271int
220xfs_sync_inodes( 272xfs_sync_inodes(
221 xfs_mount_t *mp, 273 xfs_mount_t *mp,
222 int flags) 274 int flags)
223{ 275{
224 int error; 276 int error = 0;
225 int last_error;
226 int i;
227 int lflags = XFS_LOG_FORCE; 277 int lflags = XFS_LOG_FORCE;
228 278
229 if (mp->m_flags & XFS_MOUNT_RDONLY) 279 if (mp->m_flags & XFS_MOUNT_RDONLY)
230 return 0; 280 return 0;
231 error = 0;
232 last_error = 0;
233 281
234 if (flags & SYNC_WAIT) 282 if (flags & SYNC_WAIT)
235 lflags |= XFS_LOG_SYNC; 283 lflags |= XFS_LOG_SYNC;
236 284
237 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
238 if (!mp->m_perag[i].pag_ici_init)
239 continue;
240 error = xfs_sync_inodes_ag(mp, i, flags);
241 if (error)
242 last_error = error;
243 if (error == EFSCORRUPTED)
244 break;
245 }
246 if (flags & SYNC_DELWRI) 285 if (flags & SYNC_DELWRI)
247 xfs_log_force(mp, 0, lflags); 286 error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags, XFS_ICI_NO_TAG);
248 287
249 return XFS_ERROR(last_error); 288 if (flags & SYNC_ATTR)
289 error = xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags, XFS_ICI_NO_TAG);
290
291 if (!error && (flags & SYNC_DELWRI))
292 xfs_log_force(mp, 0, lflags);
293 return XFS_ERROR(error);
250} 294}
251 295
252STATIC int 296STATIC int
@@ -613,7 +657,7 @@ xfs_reclaim_inode(
613 xfs_ifunlock(ip); 657 xfs_ifunlock(ip);
614 xfs_iunlock(ip, XFS_ILOCK_EXCL); 658 xfs_iunlock(ip, XFS_ILOCK_EXCL);
615 } 659 }
616 return 1; 660 return -EAGAIN;
617 } 661 }
618 __xfs_iflags_set(ip, XFS_IRECLAIM); 662 __xfs_iflags_set(ip, XFS_IRECLAIM);
619 spin_unlock(&ip->i_flags_lock); 663 spin_unlock(&ip->i_flags_lock);
@@ -698,72 +742,20 @@ xfs_inode_clear_reclaim_tag(
698 xfs_put_perag(mp, pag); 742 xfs_put_perag(mp, pag);
699} 743}
700 744
701 745STATIC int
702STATIC void 746xfs_reclaim_inode_now(
703xfs_reclaim_inodes_ag( 747 struct xfs_inode *ip,
704 xfs_mount_t *mp, 748 struct xfs_perag *pag,
705 int ag, 749 int flags)
706 int mode)
707{ 750{
708 xfs_inode_t *ip = NULL; 751 /* ignore if already under reclaim */
709 xfs_perag_t *pag = &mp->m_perag[ag]; 752 if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
710 int nr_found;
711 uint32_t first_index;
712 int skipped;
713
714restart:
715 first_index = 0;
716 skipped = 0;
717 do {
718 /*
719 * use a gang lookup to find the next inode in the tree
720 * as the tree is sparse and a gang lookup walks to find
721 * the number of objects requested.
722 */
723 read_lock(&pag->pag_ici_lock);
724 nr_found = radix_tree_gang_lookup_tag(&pag->pag_ici_root,
725 (void**)&ip, first_index, 1,
726 XFS_ICI_RECLAIM_TAG);
727
728 if (!nr_found) {
729 read_unlock(&pag->pag_ici_lock);
730 break;
731 }
732
733 /*
734 * Update the index for the next lookup. Catch overflows
735 * into the next AG range which can occur if we have inodes
736 * in the last block of the AG and we are currently
737 * pointing to the last inode.
738 */
739 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
740 if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
741 read_unlock(&pag->pag_ici_lock);
742 break;
743 }
744
745 /* ignore if already under reclaim */
746 if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
747 read_unlock(&pag->pag_ici_lock);
748 continue;
749 }
750
751 read_unlock(&pag->pag_ici_lock); 753 read_unlock(&pag->pag_ici_lock);
752 754 return 0;
753 /*
754 * hmmm - this is an inode already in reclaim. Do
755 * we even bother catching it here?
756 */
757 if (xfs_reclaim_inode(ip, 0, mode))
758 skipped++;
759 } while (nr_found);
760
761 if (skipped) {
762 delay(1);
763 goto restart;
764 } 755 }
765 return; 756 read_unlock(&pag->pag_ici_lock);
766 757
758 return xfs_reclaim_inode(ip, 0, flags);
767} 759}
768 760
769int 761int
@@ -771,14 +763,6 @@ xfs_reclaim_inodes(
771 xfs_mount_t *mp, 763 xfs_mount_t *mp,
772 int mode) 764 int mode)
773{ 765{
774 int i; 766 return xfs_inode_ag_iterator(mp, xfs_reclaim_inode_now, mode,
775 767 XFS_ICI_RECLAIM_TAG);
776 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
777 if (!mp->m_perag[i].pag_ici_init)
778 continue;
779 xfs_reclaim_inodes_ag(mp, i, mode);
780 }
781 return 0;
782} 768}
783
784
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index c8641f713caa..f24b50b68d03 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -212,6 +212,8 @@ typedef struct xfs_perag
212/* 212/*
213 * tags for inode radix tree 213 * tags for inode radix tree
214 */ 214 */
215#define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup
216 in xfs_inode_ag_iterator */
215#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */ 217#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */
216 218
217#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels) 219#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)