aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/super.c2
-rw-r--r--fs/sync.c28
2 files changed, 4 insertions, 26 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/*