From: Jeff Layton <jlayton@kernel.org>
To: viro@ZenIV.linux.org.uk
Cc: willy@infradead.org, andres@anarazel.de,
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
cmaiolino@redhat.com
Subject: [PATCH v2 1/5] vfs: push __sync_blockdev calls down into sync_fs routines
Date: Thu, 31 May 2018 07:29:41 -0400 [thread overview]
Message-ID: <20180531112945.8629-2-jlayton@kernel.org> (raw)
In-Reply-To: <20180531112945.8629-1-jlayton@kernel.org>
From: Jeff Layton <jlayton@redhat.com>
Currently, we always call __sync_blockdev after sync_fs, though very
few filesystems actually need it these days.
Note that 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.
Export __sync_blockdev and push the calls to __sync_blockdev down into
the sync_fs routines. Push those calls down into the filesystem
->sync_fs routines that actually need it, rather than calling it
unconditionally.
This also means that we need to return the error from the ->sync_fs op
to the caller as well, so add a vfs_sync_fs helper to encapsulate these
details.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
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 | 21 ++++++++++++++++-----
fs/sysv/inode.c | 3 +--
include/linux/fs.h | 8 ++++++++
16 files changed, 55 insertions(+), 40 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..92e695385875 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);
+ vfs_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);
+ vfs_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..5fc211d16a00 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -21,6 +21,18 @@
#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
SYNC_FILE_RANGE_WAIT_AFTER)
+/*
+ * Many legacy filesystems don't have a sync_fs op. For them, we just flush
+ * the block device (if there is one).
+ */
+int vfs_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);
+}
+EXPORT_SYMBOL(vfs_sync_fs);
+
/*
* Do the filesystem syncing work. For simple filesystems
* writeback_inodes_sb(sb) just dirties buffers with inodes so we have to
@@ -35,9 +47,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 vfs_sync_fs(sb, wait);
}
/*
@@ -78,8 +88,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;
+ vfs_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/include/linux/fs.h b/include/linux/fs.h
index 6bccf323c01e..eee017c5a821 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;
@@ -2485,9 +2491,11 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb)
return false;
}
#endif
+int vfs_sync_fs(struct super_block *sb, int wait);
extern int sync_filesystem(struct super_block *);
extern const struct file_operations def_blk_fops;
extern const struct file_operations def_chr_fops;
+
#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
next prev parent reply other threads:[~2018-05-31 11:29 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-31 11:29 [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails Jeff Layton
2018-05-31 11:29 ` Jeff Layton [this message]
2018-05-31 11:29 ` [PATCH v2 2/5] vfs: add an errseq_t pointer arg to sync_filesystem and __sync_filesystem Jeff Layton
2018-05-31 11:29 ` [PATCH v2 3/5] vfs: track per-sb writeback errors and report them to syncfs Jeff Layton
2018-05-31 11:29 ` [PATCH v2 4/5] buffer: record blockdev write errors in super_block that backs them Jeff Layton
2018-05-31 11:29 ` [PATCH v2 5/5] vfs: add a new ioctl for fetching the superblock's errseq_t Jeff Layton
2018-05-31 15:02 ` [fstests PATCH] generic: test reporting of wb errors via syncfs Jeff Layton
2018-06-01 16:16 ` [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails Jeff Layton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180531112945.8629-2-jlayton@kernel.org \
--to=jlayton@kernel.org \
--cc=andres@anarazel.de \
--cc=cmaiolino@redhat.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=viro@ZenIV.linux.org.uk \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.