From: Jan Kara <jack@xxxxxxxx> Currently we directly call filemap_fdatawrite() to issue IO when syncing block devices. This works however especially for devices without mounted filesystem it frequently happens that we race with flusher thread issuing IO in parallel and thus generate interleaved IO streams. This hurts especially for shingled drives. Fix the problem by using sync_inode() instead. That "locks" inode via I_SYNC flag and thus gets exclusion against flusher working on the same inode. Signed-off-by: Jan Kara <jack@xxxxxxxx> --- fs/sync.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/fs/sync.c b/fs/sync.c index fbc98ee62044..85bce626aaf7 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -79,9 +79,20 @@ static void sync_fs_one_sb(struct super_block *sb, void *arg) sb->s_op->sync_fs(sb, *(int *)arg); } -static void fdatawrite_one_bdev(struct block_device *bdev, void *arg) +static void write_one_bdev(struct block_device *bdev, void *arg) { - filemap_fdatawrite(bdev->bd_inode->i_mapping); + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .range_start = 0, + .range_end = LLONG_MAX, + .nr_to_write = LONG_MAX, + .for_sync = 1, + }; + /* + * We use sync_inode() to get exclusion from flusher thread (via I_SYNC + * flag) and thus avoid generating interleaved IO. + */ + sync_inode(bdev->bd_inode, &wbc); } static void fdatawait_one_bdev(struct block_device *bdev, void *arg) @@ -107,7 +118,7 @@ SYSCALL_DEFINE0(sync) iterate_supers(sync_inodes_one_sb, NULL); iterate_supers(sync_fs_one_sb, &nowait); iterate_supers(sync_fs_one_sb, &wait); - iterate_bdevs(fdatawrite_one_bdev, NULL); + iterate_bdevs(write_one_bdev, NULL); iterate_bdevs(fdatawait_one_bdev, NULL); if (unlikely(laptop_mode)) laptop_sync_completion(); @@ -124,10 +135,10 @@ static void do_sync_work(struct work_struct *work) */ iterate_supers(sync_inodes_one_sb, &nowait); iterate_supers(sync_fs_one_sb, &nowait); - iterate_bdevs(fdatawrite_one_bdev, NULL); + iterate_bdevs(write_one_bdev, NULL); iterate_supers(sync_inodes_one_sb, &nowait); iterate_supers(sync_fs_one_sb, &nowait); - iterate_bdevs(fdatawrite_one_bdev, NULL); + iterate_bdevs(write_one_bdev, NULL); printk("Emergency Sync complete\n"); kfree(work); } -- 2.6.2 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html