From: Jeff Layton <jlayton@xxxxxxxxxx> In later patches, we're going to want allow the sync_fs routine to override the return value of __sync_blockdev in some situations. This call is pointless for filesystems that do not set sb->s_bdev, so we can also make things slightly more efficient for those filesystems by not calling it in them. Export __sync_blockdev and push the calls to __sync_blockdev down into the sync_fs routines. Many older filesystems still rely on flushing out the bd_inode cache to ensure that it's safely written to the backing store, so when sync_fs is not defined, we do still call __sync_blockdev to support them. While we're in here, add a call_sync_fs helper to encapsulate this detail. Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> --- fs/affs/super.c | 2 +- fs/block_dev.c | 1 + fs/ext2/super.c | 2 +- fs/ext4/super.c | 9 +++++---- fs/f2fs/super.c | 15 +++++++++------ fs/gfs2/super.c | 4 +++- fs/hfs/super.c | 2 +- fs/internal.h | 7 ------- fs/jfs/super.c | 3 +-- fs/nilfs2/super.c | 5 +++-- fs/ocfs2/super.c | 2 +- fs/quota/dquot.c | 9 +++------ fs/reiserfs/super.c | 2 +- fs/sync.c | 9 ++++----- fs/sysv/inode.c | 3 +-- fs/xfs/xfs_super.c | 6 +++--- include/linux/fs.h | 18 ++++++++++++++++++ 17 files changed, 56 insertions(+), 43 deletions(-) diff --git a/fs/affs/super.c b/fs/affs/super.c index e602619aed9d..b76af8e3c87d 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -58,7 +58,7 @@ static int affs_sync_fs(struct super_block *sb, int wait) { affs_commit_super(sb, wait); - return 0; + return __sync_blockdev(sb->s_bdev, wait); } static void flush_superblock(struct work_struct *work) diff --git a/fs/block_dev.c b/fs/block_dev.c index 7ec920e27065..8f1d13a3f02b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -447,6 +447,7 @@ int __sync_blockdev(struct block_device *bdev, int wait) return filemap_flush(bdev->bd_inode->i_mapping); return filemap_write_and_wait(bdev->bd_inode->i_mapping); } +EXPORT_SYMBOL(__sync_blockdev); /* * Write out and wait upon all the dirty data associated with a block diff --git a/fs/ext2/super.c b/fs/ext2/super.c index de1694512f1f..fd8536bc13da 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1280,7 +1280,7 @@ static int ext2_sync_fs(struct super_block *sb, int wait) } spin_unlock(&sbi->s_lock); ext2_sync_super(sb, es, wait); - return 0; + return __sync_blockdev(sb->s_bdev, wait); } static int ext2_freeze(struct super_block *sb) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index eb104e8476f0..ac2ffdbf54e6 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4857,13 +4857,13 @@ int ext4_force_commit(struct super_block *sb) static int ext4_sync_fs(struct super_block *sb, int wait) { - int ret = 0; + int ret = 0, ret2; tid_t target; bool needs_barrier = false; struct ext4_sb_info *sbi = EXT4_SB(sb); if (unlikely(ext4_forced_shutdown(sbi))) - return 0; + goto out; trace_ext4_sync_fs(sb, wait); flush_workqueue(sbi->rsv_conversion_wq); @@ -4896,8 +4896,9 @@ static int ext4_sync_fs(struct super_block *sb, int wait) if (!ret) ret = err; } - - return ret; +out: + ret2 = __sync_blockdev(sb->s_bdev, wait); + return ret ? ret : ret2; } /* diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 42d564c5ccd0..70fb16aac0bd 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1058,15 +1058,17 @@ static void f2fs_put_super(struct super_block *sb) int f2fs_sync_fs(struct super_block *sb, int sync) { struct f2fs_sb_info *sbi = F2FS_SB(sb); - int err = 0; + int err = 0, err2; if (unlikely(f2fs_cp_error(sbi))) - return 0; + goto out; trace_f2fs_sync_fs(sb, sync); - if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) - return -EAGAIN; + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) { + err = -EAGAIN; + goto out; + } if (sync) { struct cp_control cpc; @@ -1078,8 +1080,9 @@ int f2fs_sync_fs(struct super_block *sb, int sync) mutex_unlock(&sbi->gc_mutex); } f2fs_trace_ios(NULL, 1); - - return err; +out: + err2 = __sync_blockdev(sb->s_bdev, sync); + return err ? err : err2; } static int f2fs_freeze(struct super_block *sb) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index cf5c7f3080d2..884dd8b7d7b3 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -951,13 +951,15 @@ static void gfs2_put_super(struct super_block *sb) static int gfs2_sync_fs(struct super_block *sb, int wait) { + int bderr; struct gfs2_sbd *sdp = sb->s_fs_info; gfs2_quota_sync(sb, -1); if (wait) gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | GFS2_LFC_SYNC_FS); - return sdp->sd_log_error; + bderr = __sync_blockdev(sb->s_bdev, wait); + return sdp->sd_log_error ? sdp->sd_log_error : bderr; } void gfs2_freeze_func(struct work_struct *work) diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 173876782f73..9cb410ebab7c 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -33,7 +33,7 @@ MODULE_LICENSE("GPL"); static int hfs_sync_fs(struct super_block *sb, int wait) { hfs_mdb_commit(sb); - return 0; + return __sync_blockdev(sb->s_bdev, wait); } /* diff --git a/fs/internal.h b/fs/internal.h index e08972db0303..148b74293dfe 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -24,17 +24,10 @@ struct shrink_control; #ifdef CONFIG_BLOCK extern void __init bdev_cache_init(void); -extern int __sync_blockdev(struct block_device *bdev, int wait); - #else static inline void bdev_cache_init(void) { } - -static inline int __sync_blockdev(struct block_device *bdev, int wait) -{ - return 0; -} #endif /* diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 1b9264fd54b6..c4b99ad53f9c 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -717,8 +717,7 @@ static int jfs_sync_fs(struct super_block *sb, int wait) jfs_flush_journal(log, wait); jfs_syncpt(log, 0); } - - return 0; + return __sync_blockdev(sb->s_bdev, wait); } static int jfs_show_options(struct seq_file *seq, struct dentry *root) diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 6ffeca84d7c3..280a28b62d13 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -495,7 +495,7 @@ static int nilfs_sync_fs(struct super_block *sb, int wait) { struct the_nilfs *nilfs = sb->s_fs_info; struct nilfs_super_block **sbp; - int err = 0; + int err = 0, bderr; /* This function is called when super block should be written back */ if (wait) @@ -514,7 +514,8 @@ static int nilfs_sync_fs(struct super_block *sb, int wait) if (!err) err = nilfs_flush_device(nilfs); - return err; + bderr = __sync_blockdev(sb->s_bdev, wait); + return err ? err : bderr; } int nilfs_attach_checkpoint(struct super_block *sb, __u64 cno, int curr_mnt, diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 3415e0b09398..07a1a297c2ed 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -429,7 +429,7 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait) jbd2_log_wait_commit(osb->journal->j_journal, target); } - return 0; + return __sync_blockdev(sb->s_bdev, wait); } static int ocfs2_need_system_inode(struct ocfs2_super *osb, int ino) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index d88231e3b2be..96522760826c 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -686,9 +686,7 @@ int dquot_quota_sync(struct super_block *sb, int type) /* This is not very clever (and fast) but currently I don't know about * any other simple way of getting quota data to disk and we must get * them there for userspace to be visible... */ - if (sb->s_op->sync_fs) - sb->s_op->sync_fs(sb, 1); - sync_blockdev(sb->s_bdev); + call_sync_fs(sb, 1); /* * Now when everything is written we can discard the pagecache so @@ -2245,9 +2243,8 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags) /* Sync the superblock so that buffers with quota data are written to * disk (and so userspace sees correct data afterwards). */ - if (sb->s_op->sync_fs) - sb->s_op->sync_fs(sb, 1); - sync_blockdev(sb->s_bdev); + call_sync_fs(sb, 1); + /* Now the quota files are just ordinary files and we can set the * inode flags back. Moreover we discard the pagecache so that * userspace sees the writes we did bypassing the pagecache. We diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 1fc934d24459..b3a390eab9b7 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -78,7 +78,7 @@ static int reiserfs_sync_fs(struct super_block *s, int wait) if (!journal_end_sync(&th)) reiserfs_flush_old_commits(s); reiserfs_write_unlock(s); - return 0; + return __sync_blockdev(s->s_bdev, wait); } static void flush_old_commits(struct work_struct *work) diff --git a/fs/sync.c b/fs/sync.c index a863cd2490ce..44cdb38a8b67 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -35,9 +35,7 @@ static int __sync_filesystem(struct super_block *sb, int wait) else writeback_inodes_sb(sb, WB_REASON_SYNC); - if (sb->s_op->sync_fs) - sb->s_op->sync_fs(sb, wait); - return __sync_blockdev(sb->s_bdev, wait); + return call_sync_fs(sb, wait); } /* @@ -78,8 +76,9 @@ static void sync_fs_one_sb(struct super_block *sb, void *arg) { int wait = arg ? 1 : 0; - if (!sb_rdonly(sb) && sb->s_op->sync_fs) - sb->s_op->sync_fs(sb, wait); + if (sb_rdonly(sb)) + return; + call_sync_fs(sb, wait); } static void fdatawrite_one_bdev(struct block_device *bdev, void *arg) diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index bec9f79adb25..2232cf97840b 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -53,8 +53,7 @@ static int sysv_sync_fs(struct super_block *sb, int wait) } mutex_unlock(&sbi->s_lock); - - return 0; + return __sync_blockdev(sb->s_bdev, wait); } static int sysv_remount(struct super_block *sb, int *flags, char *data) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index d71424052917..8683f8f2666f 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1097,7 +1097,7 @@ xfs_fs_sync_fs( * Doing anything during the async pass would be counterproductive. */ if (!wait) - return 0; + goto out; xfs_log_force(mp, XFS_LOG_SYNC); if (laptop_mode) { @@ -1108,8 +1108,8 @@ xfs_fs_sync_fs( */ flush_delayed_work(&mp->m_log->l_work); } - - return 0; +out: + return __sync_blockdev(sb->s_bdev, wait); } STATIC int diff --git a/include/linux/fs.h b/include/linux/fs.h index 6bccf323c01e..69b76f394954 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2441,6 +2441,7 @@ extern void bd_forget(struct inode *inode); extern void bdput(struct block_device *); extern void invalidate_bdev(struct block_device *); extern void iterate_bdevs(void (*)(struct block_device *, void *), void *); +extern int __sync_blockdev(struct block_device *bdev, int wait); extern int sync_blockdev(struct block_device *bdev); extern void kill_bdev(struct block_device *); extern struct super_block *freeze_bdev(struct block_device *); @@ -2461,6 +2462,11 @@ static inline int sync_blockdev(struct block_device *bdev) { return 0; } static inline void kill_bdev(struct block_device *bdev) {} static inline void invalidate_bdev(struct block_device *bdev) {} +static inline int __sync_blockdev(struct block_device *bdev, int wait) +{ + return 0; +} + static inline struct super_block *freeze_bdev(struct block_device *sb) { return NULL; @@ -2488,6 +2494,18 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) extern int sync_filesystem(struct super_block *); extern const struct file_operations def_blk_fops; extern const struct file_operations def_chr_fops; + +/* + * Many legacy filesystems don't have a sync_fs op. For them, we just flush + * the block device (if there is one). + */ +static inline int call_sync_fs(struct super_block *sb, int wait) +{ + if (sb->s_op->sync_fs) + return sb->s_op->sync_fs(sb, wait); + return __sync_blockdev(sb->s_bdev, wait); +} + #ifdef CONFIG_BLOCK extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); -- 2.17.0