get rid of restarts in sync_filesystems()
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 22 Mar 2010 23:56:42 +0000 (19:56 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 21 May 2010 22:31:15 +0000 (18:31 -0400)
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>
fs/super.c
fs/sync.c
include/linux/fs.h

index 0390461..ba99524 100644 (file)
@@ -130,7 +130,7 @@ static inline void destroy_super(struct super_block *s)
  * Drop a superblock's refcount.  Returns non-zero if the superblock was
  * destroyed.  The caller must hold sb_lock.
  */
-static int __put_super(struct super_block *sb)
+int __put_super(struct super_block *sb)
 {
        int ret = 0;
 
index ad6691b..f3f0a0e 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -80,35 +80,15 @@ EXPORT_SYMBOL_GPL(sync_filesystem);
 /*
  * Sync all the data for all the filesystems (called by sys_sync() and
  * emergency sync)
- *
- * This operation is careful to avoid the livelock which could easily happen
- * if two or more filesystems are being continuously dirtied.  s_need_sync
- * is used only here.  We set it against all filesystems and then clear it as
- * we sync them.  So redirtied filesystems are skipped.
- *
- * But if process A is currently running sync_filesystems and then process B
- * calls sync_filesystems as well, process B will set all the s_need_sync
- * flags again, which will cause process A to resync everything.  Fix that with
- * a local mutex.
  */
 static void sync_filesystems(int wait)
 {
-       struct super_block *sb;
-       static DEFINE_MUTEX(mutex);
+       struct super_block *sb, *n;
 
-       mutex_lock(&mutex);             /* Could be down_interruptible */
        spin_lock(&sb_lock);
-       list_for_each_entry(sb, &super_blocks, s_list)
-               if (!list_empty(&sb->s_instances))
-                       sb->s_need_sync = 1;
-
-restart:
-       list_for_each_entry(sb, &super_blocks, s_list) {
+       list_for_each_entry_safe(sb, n, &super_blocks, s_list) {
                if (list_empty(&sb->s_instances))
                        continue;
-               if (!sb->s_need_sync)
-                       continue;
-               sb->s_need_sync = 0;
                sb->s_count++;
                spin_unlock(&sb_lock);
 
@@ -119,11 +99,9 @@ restart:
 
                /* restart only when sb is no longer on the list */
                spin_lock(&sb_lock);
-               if (__put_super_and_need_restart(sb))
-                       goto restart;
+               __put_super(sb);
        }
        spin_unlock(&sb_lock);
-       mutex_unlock(&mutex);
 }
 
 /*
index 62f84d9..e1c7427 100644 (file)
@@ -1332,7 +1332,6 @@ struct super_block {
        struct rw_semaphore     s_umount;
        struct mutex            s_lock;
        int                     s_count;
-       int                     s_need_sync;
        atomic_t                s_active;
 #ifdef CONFIG_SECURITY
        void                    *s_security;
@@ -1780,6 +1779,7 @@ extern int get_sb_pseudo(struct file_system_type *, char *,
        struct vfsmount *mnt);
 extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
 int __put_super_and_need_restart(struct super_block *sb);
+int __put_super(struct super_block *sb);
 void put_super(struct super_block *sb);
 
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */