diff --git a/fs/internal.h b/fs/internal.h index 6d4ef208ef65..343a537ab809 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -71,3 +71,12 @@ extern void chroot_fs_refs(struct path *, struct path *); * file_table.c */ extern void mark_files_ro(struct super_block *); + +/* + * super.c + */ +#ifdef CONFIG_BLOCK +extern void sync_blockdevs(void); +#else +static inline void sync_blockdevs(void) { } +#endif diff --git a/fs/super.c b/fs/super.c index 3d9f117dd2a3..18d159dc1e40 100644 --- a/fs/super.c +++ b/fs/super.c @@ -293,6 +293,7 @@ void __fsync_super(struct super_block *sb) { sync_inodes_sb(sb, 0); vfs_dq_sync(sb); + sync_inodes_sb(sb, 1); lock_super(sb); if (sb->s_dirt && sb->s_op->write_super) sb->s_op->write_super(sb); @@ -300,7 +301,6 @@ void __fsync_super(struct super_block *sb) if (sb->s_op->sync_fs) sb->s_op->sync_fs(sb, 1); sync_blockdev(sb->s_bdev); - sync_inodes_sb(sb, 1); } /* @@ -522,6 +522,33 @@ void sync_filesystems(int wait) mutex_unlock(&mutex); } +#ifdef CONFIG_BLOCK +/* + * Sync all block devices underlying some superblock + */ +void sync_blockdevs(void) +{ + struct super_block *sb; + + spin_lock(&sb_lock); +restart: + list_for_each_entry(sb, &super_blocks, s_list) { + if (!sb->s_bdev) + continue; + sb->s_count++; + spin_unlock(&sb_lock); + down_read(&sb->s_umount); + if (sb->s_root) + sync_blockdev(sb->s_bdev); + up_read(&sb->s_umount); + spin_lock(&sb_lock); + if (__put_super_and_need_restart(sb)) + goto restart; + } + spin_unlock(&sb_lock); +} +#endif + /** * get_super - get the superblock of a device * @bdev: device to get the superblock for diff --git a/fs/sync.c b/fs/sync.c index 7abc65fbf21d..631fd5aece78 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -13,6 +13,7 @@ #include #include #include +#include "internal.h" #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ SYNC_FILE_RANGE_WAIT_AFTER) @@ -26,10 +27,11 @@ static void do_sync(unsigned long wait) wakeup_pdflush(0); sync_inodes(0); /* All mappings, inodes and their blockdevs */ vfs_dq_sync(NULL); + sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ sync_supers(); /* Write the superblocks */ sync_filesystems(0); /* Start syncing the filesystems */ sync_filesystems(wait); /* Waitingly sync the filesystems */ - sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ + sync_blockdevs(); if (!wait) printk("Emergency Sync complete\n"); if (unlikely(laptop_mode))