aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-03-22 19:56:42 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-05-21 18:31:15 -0400
commit8edd64bd6089e21f47dcdebb14b598b713213ddc (patch)
treec356a358c7b823433728869ff430ad205c4b8a5d
parent551de6f34dfeefbeeadb32909c387d393114ecc8 (diff)
get rid of restarts in sync_filesystems()
At the same time we can kill s_need_restart and local mutex in there. __put_super() made public for a while; will be gone later. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/super.c2
-rw-r--r--fs/sync.c28
-rw-r--r--include/linux/fs.h2
3 files changed, 5 insertions, 27 deletions
diff --git a/fs/super.c b/fs/super.c
index 0390461dfca0..ba99524998f7 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -130,7 +130,7 @@ static inline void destroy_super(struct super_block *s)
130 * Drop a superblock's refcount. Returns non-zero if the superblock was 130 * Drop a superblock's refcount. Returns non-zero if the superblock was
131 * destroyed. The caller must hold sb_lock. 131 * destroyed. The caller must hold sb_lock.
132 */ 132 */
133static int __put_super(struct super_block *sb) 133int __put_super(struct super_block *sb)
134{ 134{
135 int ret = 0; 135 int ret = 0;
136 136
diff --git a/fs/sync.c b/fs/sync.c
index ad6691bae370..f3f0a0e1948f 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -80,35 +80,15 @@ EXPORT_SYMBOL_GPL(sync_filesystem);
80/* 80/*
81 * Sync all the data for all the filesystems (called by sys_sync() and 81 * Sync all the data for all the filesystems (called by sys_sync() and
82 * emergency sync) 82 * emergency sync)
83 *
84 * This operation is careful to avoid the livelock which could easily happen
85 * if two or more filesystems are being continuously dirtied. s_need_sync
86 * is used only here. We set it against all filesystems and then clear it as
87 * we sync them. So redirtied filesystems are skipped.
88 *
89 * But if process A is currently running sync_filesystems and then process B
90 * calls sync_filesystems as well, process B will set all the s_need_sync
91 * flags again, which will cause process A to resync everything. Fix that with
92 * a local mutex.
93 */ 83 */
94static void sync_filesystems(int wait) 84static void sync_filesystems(int wait)
95{ 85{
96 struct super_block *sb; 86 struct super_block *sb, *n;
97 static DEFINE_MUTEX(mutex);
98 87
99 mutex_lock(&mutex); /* Could be down_interruptible */
100 spin_lock(&sb_lock); 88 spin_lock(&sb_lock);
101 list_for_each_entry(sb, &super_blocks, s_list) 89 list_for_each_entry_safe(sb, n, &super_blocks, s_list) {
102 if (!list_empty(&sb->s_instances))
103 sb->s_need_sync = 1;
104
105restart:
106 list_for_each_entry(sb, &super_blocks, s_list) {
107 if (list_empty(&sb->s_instances)) 90 if (list_empty(&sb->s_instances))
108 continue; 91 continue;
109 if (!sb->s_need_sync)
110 continue;
111 sb->s_need_sync = 0;
112 sb->s_count++; 92 sb->s_count++;
113 spin_unlock(&sb_lock); 93 spin_unlock(&sb_lock);
114 94
@@ -119,11 +99,9 @@ restart:
119 99
120 /* restart only when sb is no longer on the list */ 100 /* restart only when sb is no longer on the list */
121 spin_lock(&sb_lock); 101 spin_lock(&sb_lock);
122 if (__put_super_and_need_restart(sb)) 102 __put_super(sb);
123 goto restart;
124 } 103 }
125 spin_unlock(&sb_lock); 104 spin_unlock(&sb_lock);
126 mutex_unlock(&mutex);
127} 105}
128 106
129/* 107/*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 62f84d955b83..e1c7427802b8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1332,7 +1332,6 @@ struct super_block {
1332 struct rw_semaphore s_umount; 1332 struct rw_semaphore s_umount;
1333 struct mutex s_lock; 1333 struct mutex s_lock;
1334 int s_count; 1334 int s_count;
1335 int s_need_sync;
1336 atomic_t s_active; 1335 atomic_t s_active;
1337#ifdef CONFIG_SECURITY 1336#ifdef CONFIG_SECURITY
1338 void *s_security; 1337 void *s_security;
@@ -1780,6 +1779,7 @@ extern int get_sb_pseudo(struct file_system_type *, char *,
1780 struct vfsmount *mnt); 1779 struct vfsmount *mnt);
1781extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb); 1780extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
1782int __put_super_and_need_restart(struct super_block *sb); 1781int __put_super_and_need_restart(struct super_block *sb);
1782int __put_super(struct super_block *sb);
1783void put_super(struct super_block *sb); 1783void put_super(struct super_block *sb);
1784 1784
1785/* Alas, no aliases. Too much hassle with bringing module.h everywhere */ 1785/* Alas, no aliases. Too much hassle with bringing module.h everywhere */