diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-03-23 00:56:42 +0100 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-05-22 00:31:15 +0200 |
commit | 8edd64bd6089e21f47dcdebb14b598b713213ddc (patch) | |
tree | c356a358c7b823433728869ff430ad205c4b8a5d | |
parent | Leave superblocks on s_list until the end (diff) | |
download | linux-8edd64bd6089e21f47dcdebb14b598b713213ddc.tar.xz linux-8edd64bd6089e21f47dcdebb14b598b713213ddc.zip |
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.c | 2 | ||||
-rw-r--r-- | fs/sync.c | 28 | ||||
-rw-r--r-- | include/linux/fs.h | 2 |
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) * 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 ad6691bae370..f3f0a0e1948f 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 @@ 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); } /* 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 { 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 */ |