diff options
author | Kirill Korotaev <dev@sw.ru> | 2005-06-23 03:09:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-23 12:45:27 -0400 |
commit | 618f06362ae3f60f95d7b0e666de25ee6ae35679 (patch) | |
tree | 4415b4e590913e16535704168ea74c6af5a93c48 /fs/quota.c | |
parent | 4fea2838aa00b9e59efde974dcdb455608192811 (diff) |
[PATCH] O(1) sb list traversing on syncs
This patch removes O(n^2) super block loops in sync_inodes(),
sync_filesystems() etc. in favour of using __put_super_and_need_restart()
which I introduced earlier. We faced a noticably long freezes on sb
syncing when there are thousands of super blocks in the system.
Signed-Off-By: Kirill Korotaev <dev@sw.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/quota.c')
-rw-r--r-- | fs/quota.c | 60 |
1 files changed, 24 insertions, 36 deletions
diff --git a/fs/quota.c b/fs/quota.c index 3f0333a51a23..f5d1cff55196 100644 --- a/fs/quota.c +++ b/fs/quota.c | |||
@@ -149,36 +149,6 @@ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t | |||
149 | return error; | 149 | return error; |
150 | } | 150 | } |
151 | 151 | ||
152 | static struct super_block *get_super_to_sync(int type) | ||
153 | { | ||
154 | struct list_head *head; | ||
155 | int cnt, dirty; | ||
156 | |||
157 | restart: | ||
158 | spin_lock(&sb_lock); | ||
159 | list_for_each(head, &super_blocks) { | ||
160 | struct super_block *sb = list_entry(head, struct super_block, s_list); | ||
161 | |||
162 | /* This test just improves performance so it needn't be reliable... */ | ||
163 | for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) | ||
164 | if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) | ||
165 | && info_any_dirty(&sb_dqopt(sb)->info[cnt])) | ||
166 | dirty = 1; | ||
167 | if (!dirty) | ||
168 | continue; | ||
169 | sb->s_count++; | ||
170 | spin_unlock(&sb_lock); | ||
171 | down_read(&sb->s_umount); | ||
172 | if (!sb->s_root) { | ||
173 | drop_super(sb); | ||
174 | goto restart; | ||
175 | } | ||
176 | return sb; | ||
177 | } | ||
178 | spin_unlock(&sb_lock); | ||
179 | return NULL; | ||
180 | } | ||
181 | |||
182 | static void quota_sync_sb(struct super_block *sb, int type) | 152 | static void quota_sync_sb(struct super_block *sb, int type) |
183 | { | 153 | { |
184 | int cnt; | 154 | int cnt; |
@@ -219,17 +189,35 @@ static void quota_sync_sb(struct super_block *sb, int type) | |||
219 | 189 | ||
220 | void sync_dquots(struct super_block *sb, int type) | 190 | void sync_dquots(struct super_block *sb, int type) |
221 | { | 191 | { |
192 | int cnt, dirty; | ||
193 | |||
222 | if (sb) { | 194 | if (sb) { |
223 | if (sb->s_qcop->quota_sync) | 195 | if (sb->s_qcop->quota_sync) |
224 | quota_sync_sb(sb, type); | 196 | quota_sync_sb(sb, type); |
197 | return; | ||
225 | } | 198 | } |
226 | else { | 199 | |
227 | while ((sb = get_super_to_sync(type)) != NULL) { | 200 | spin_lock(&sb_lock); |
228 | if (sb->s_qcop->quota_sync) | 201 | restart: |
229 | quota_sync_sb(sb, type); | 202 | list_for_each_entry(sb, &super_blocks, s_list) { |
230 | drop_super(sb); | 203 | /* This test just improves performance so it needn't be reliable... */ |
231 | } | 204 | for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) |
205 | if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) | ||
206 | && info_any_dirty(&sb_dqopt(sb)->info[cnt])) | ||
207 | dirty = 1; | ||
208 | if (!dirty) | ||
209 | continue; | ||
210 | sb->s_count++; | ||
211 | spin_unlock(&sb_lock); | ||
212 | down_read(&sb->s_umount); | ||
213 | if (sb->s_root && sb->s_qcop->quota_sync) | ||
214 | quota_sync_sb(sb, type); | ||
215 | up_read(&sb->s_umount); | ||
216 | spin_lock(&sb_lock); | ||
217 | if (__put_super_and_need_restart(sb)) | ||
218 | goto restart; | ||
232 | } | 219 | } |
220 | spin_unlock(&sb_lock); | ||
233 | } | 221 | } |
234 | 222 | ||
235 | /* Copy parameters and call proper function */ | 223 | /* Copy parameters and call proper function */ |