diff --git a/fs/super.c b/fs/super.c index 0390461dfca07f..ba99524998f795 100644 --- a/fs/super.c +++ b/fs/super.c @@ -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; diff --git a/fs/sync.c b/fs/sync.c index ad6691bae37000..f3f0a0e1948f0e 100644 --- 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 @@ static void sync_filesystems(int wait) /* 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); } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 62f84d955b83c8..e1c7427802b8f4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -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 */