linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails
@ 2018-05-31 11:29 Jeff Layton
  2018-05-31 11:29 ` [PATCH v2 1/5] vfs: push __sync_blockdev calls down into sync_fs routines Jeff Layton
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Jeff Layton @ 2018-05-31 11:29 UTC (permalink / raw)
  To: viro; +Cc: willy, andres, linux-fsdevel, linux-kernel, cmaiolino

From: Jeff Layton <jlayton@redhat.com>

v2: don't modify sync_fs op prototype, handle errors at vfs layer

The syncfs system call returns an int error code, but in general it does
not return errors when an inode fails writeback. It will return an error
if __sync_blockdev fails, but that's not useful on non-block based
filesystems and is generally not useful on more modern filesystems that
don't rely on that call.

This patchset aims to remedy that by adding some infrastructure to allow
syncfs to return an error when an inode fails writeback. The basic idea
is to add a new errseq_t to the super_block to record writeback errors.

Because we don't want to grow struct file for this purpose, this new
behavior is only activated when the fd passed to syncfs is opened with
O_PATH.

One of the items on the wishlist from the PostgreSQL developers at this
year's LSF/MM was a way to tell whether there has been any writeback
failure on a filesystem without forcing everything to be synced out.

The final patch in this series adds a new generic vfs ioctl that
presents the new sb->s_wb_err field to userland applications that wish
to see it.

Comments and suggestions welcome.

Jeff Layton (5):
  vfs: push __sync_blockdev calls down into sync_fs routines
  vfs: add an errseq_t pointer arg to sync_filesystem and
    __sync_filesystem
  vfs: track per-sb writeback errors and report them to syncfs
  buffer: record blockdev write errors in super_block that backs them
  vfs: add a new ioctl for fetching the superblock's errseq_t

 drivers/staging/ncpfs/inode.c |  2 +-
 fs/adfs/super.c               |  2 +-
 fs/affs/super.c               |  4 +--
 fs/befs/linuxvfs.c            |  2 +-
 fs/block_dev.c                |  3 ++-
 fs/btrfs/super.c              |  4 +--
 fs/buffer.c                   |  2 ++
 fs/cachefiles/interface.c     |  2 +-
 fs/cifs/cifsfs.c              |  2 +-
 fs/coda/inode.c               |  2 +-
 fs/cramfs/inode.c             |  2 +-
 fs/debugfs/inode.c            |  2 +-
 fs/efs/super.c                |  2 +-
 fs/ext2/super.c               |  4 +--
 fs/ext4/super.c               | 13 +++++-----
 fs/f2fs/super.c               | 15 ++++++-----
 fs/fat/inode.c                |  2 +-
 fs/freevxfs/vxfs_super.c      |  2 +-
 fs/fuse/inode.c               |  2 +-
 fs/gfs2/super.c               |  6 +++--
 fs/hfs/super.c                |  4 +--
 fs/hfsplus/super.c            |  2 +-
 fs/hpfs/super.c               |  2 +-
 fs/internal.h                 |  7 ------
 fs/ioctl.c                    |  3 +++
 fs/isofs/inode.c              |  2 +-
 fs/jffs2/super.c              |  2 +-
 fs/jfs/super.c                |  5 ++--
 fs/minix/inode.c              |  2 +-
 fs/nfs/super.c                |  2 +-
 fs/nilfs2/super.c             |  7 +++---
 fs/ntfs/super.c               |  2 +-
 fs/ocfs2/super.c              |  4 +--
 fs/open.c                     |  6 ++---
 fs/openpromfs/inode.c         |  2 +-
 fs/overlayfs/super.c          |  2 +-
 fs/proc/root.c                |  2 +-
 fs/pstore/inode.c             |  2 +-
 fs/qnx4/inode.c               |  2 +-
 fs/qnx6/inode.c               |  2 +-
 fs/quota/dquot.c              | 11 +++-----
 fs/reiserfs/super.c           |  4 +--
 fs/romfs/super.c              |  2 +-
 fs/squashfs/super.c           |  2 +-
 fs/super.c                    |  4 +--
 fs/sync.c                     | 47 +++++++++++++++++++++++++++--------
 fs/sysv/inode.c               |  5 ++--
 fs/tracefs/inode.c            |  2 +-
 fs/ubifs/super.c              |  2 +-
 fs/udf/super.c                |  2 +-
 fs/ufs/super.c                |  2 +-
 fs/xfs/xfs_super.c            |  2 +-
 include/linux/errseq.h        |  1 +
 include/linux/fs.h            | 13 +++++++++-
 include/linux/pagemap.h       |  5 +++-
 include/uapi/linux/fs.h       |  1 +
 lib/errseq.c                  | 33 ++++++++++++++++++++++--
 57 files changed, 173 insertions(+), 102 deletions(-)

-- 
2.17.0

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/5] vfs: push __sync_blockdev calls down into sync_fs routines
  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
  2018-05-31 11:29 ` [PATCH v2 2/5] vfs: add an errseq_t pointer arg to sync_filesystem and __sync_filesystem Jeff Layton
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jeff Layton @ 2018-05-31 11:29 UTC (permalink / raw)
  To: viro; +Cc: willy, andres, linux-fsdevel, linux-kernel, cmaiolino

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

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/5] vfs: add an errseq_t pointer arg to sync_filesystem and __sync_filesystem
  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 ` [PATCH v2 1/5] vfs: push __sync_blockdev calls down into sync_fs routines Jeff Layton
@ 2018-05-31 11:29 ` Jeff Layton
  2018-05-31 11:29 ` [PATCH v2 3/5] vfs: track per-sb writeback errors and report them to syncfs Jeff Layton
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jeff Layton @ 2018-05-31 11:29 UTC (permalink / raw)
  To: viro; +Cc: willy, andres, linux-fsdevel, linux-kernel, cmaiolino

From: Jeff Layton <jlayton@redhat.com>

Allow sync_filesystem and __sync_filesystem to take an errseq_t pointer
for the purposes of error reporting. For now, everything passes in NULL
and the field is ignored, but a later patch will change that.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 drivers/staging/ncpfs/inode.c |  2 +-
 fs/adfs/super.c               |  2 +-
 fs/affs/super.c               |  2 +-
 fs/befs/linuxvfs.c            |  2 +-
 fs/block_dev.c                |  2 +-
 fs/btrfs/super.c              |  4 ++--
 fs/cachefiles/interface.c     |  2 +-
 fs/cifs/cifsfs.c              |  2 +-
 fs/coda/inode.c               |  2 +-
 fs/cramfs/inode.c             |  2 +-
 fs/debugfs/inode.c            |  2 +-
 fs/efs/super.c                |  2 +-
 fs/ext2/super.c               |  2 +-
 fs/ext4/super.c               |  4 ++--
 fs/fat/inode.c                |  2 +-
 fs/freevxfs/vxfs_super.c      |  2 +-
 fs/fuse/inode.c               |  2 +-
 fs/gfs2/super.c               |  2 +-
 fs/hfs/super.c                |  2 +-
 fs/hfsplus/super.c            |  2 +-
 fs/hpfs/super.c               |  2 +-
 fs/isofs/inode.c              |  2 +-
 fs/jffs2/super.c              |  2 +-
 fs/jfs/super.c                |  2 +-
 fs/minix/inode.c              |  2 +-
 fs/nfs/super.c                |  2 +-
 fs/nilfs2/super.c             |  2 +-
 fs/ntfs/super.c               |  2 +-
 fs/ocfs2/super.c              |  2 +-
 fs/openpromfs/inode.c         |  2 +-
 fs/overlayfs/super.c          |  2 +-
 fs/proc/root.c                |  2 +-
 fs/pstore/inode.c             |  2 +-
 fs/qnx4/inode.c               |  2 +-
 fs/qnx6/inode.c               |  2 +-
 fs/quota/dquot.c              |  2 +-
 fs/reiserfs/super.c           |  2 +-
 fs/romfs/super.c              |  2 +-
 fs/squashfs/super.c           |  2 +-
 fs/super.c                    |  4 ++--
 fs/sync.c                     | 10 +++++-----
 fs/sysv/inode.c               |  2 +-
 fs/tracefs/inode.c            |  2 +-
 fs/ubifs/super.c              |  2 +-
 fs/udf/super.c                |  2 +-
 fs/ufs/super.c                |  2 +-
 fs/xfs/xfs_super.c            |  2 +-
 include/linux/fs.h            |  2 +-
 48 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/drivers/staging/ncpfs/inode.c b/drivers/staging/ncpfs/inode.c
index bb411610a071..1ba23c4b8ddd 100644
--- a/drivers/staging/ncpfs/inode.c
+++ b/drivers/staging/ncpfs/inode.c
@@ -103,7 +103,7 @@ static void destroy_inodecache(void)
 
 static int ncp_remount(struct super_block *sb, int *flags, char* data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_NODIRATIME;
 	return 0;
 }
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index cfda2c7caedc..695cf6413612 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -212,7 +212,7 @@ static int parse_options(struct super_block *sb, char *options)
 
 static int adfs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_NODIRATIME;
 	return parse_options(sb, data);
 }
diff --git a/fs/affs/super.c b/fs/affs/super.c
index b76af8e3c87d..07eec0e97303 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -570,7 +570,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
 
 	pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data);
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_NODIRATIME;
 
 	memcpy(volume, sbi->s_volume, 32);
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 4700b4534439..1c4922e78646 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -944,7 +944,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
 static int
 befs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	if (!(*flags & SB_RDONLY))
 		return -EINVAL;
 	return 0;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 8f1d13a3f02b..46fd96344d08 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -468,7 +468,7 @@ int fsync_bdev(struct block_device *bdev)
 {
 	struct super_block *sb = get_super(bdev);
 	if (sb) {
-		int res = sync_filesystem(sb);
+		int res = sync_filesystem(sb, NULL);
 		drop_super(sb);
 		return res;
 	}
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 0628092b0b1b..45bdc2b27b70 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1732,7 +1732,7 @@ static inline void btrfs_remount_begin(struct btrfs_fs_info *fs_info,
 		wait_event(fs_info->transaction_wait,
 			   (atomic_read(&fs_info->defrag_running) == 0));
 		if (flags & SB_RDONLY)
-			sync_filesystem(fs_info->sb);
+			sync_filesystem(fs_info->sb, NULL);
 	}
 }
 
@@ -1763,7 +1763,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 	u32 old_metadata_ratio = fs_info->metadata_ratio;
 	int ret;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	btrfs_remount_prepare(fs_info);
 
 	if (data) {
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
index 222bc5d8b62c..777468fe8afd 100644
--- a/fs/cachefiles/interface.c
+++ b/fs/cachefiles/interface.c
@@ -391,7 +391,7 @@ static void cachefiles_sync_cache(struct fscache_cache *_cache)
 	 * written to disc */
 	cachefiles_begin_secure(cache, &saved_cred);
 	down_read(&cache->mnt->mnt_sb->s_umount);
-	ret = sync_filesystem(cache->mnt->mnt_sb);
+	ret = sync_filesystem(cache->mnt->mnt_sb, NULL);
 	up_read(&cache->mnt->mnt_sb->s_umount);
 	cachefiles_end_secure(cache, saved_cred);
 
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 5a5a0158cc8f..82a4d2f5f4ed 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -574,7 +574,7 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root)
 
 static int cifs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_NODIRATIME;
 	return 0;
 }
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 97424cf206c0..4c5a87b1ac05 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -95,7 +95,7 @@ void coda_destroy_inodecache(void)
 
 static int coda_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_NOATIME;
 	return 0;
 }
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 124b093d14e5..9c13149c6729 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -504,7 +504,7 @@ static void cramfs_kill_sb(struct super_block *sb)
 
 static int cramfs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_RDONLY;
 	return 0;
 }
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 13b01351dd1c..129af6748d94 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -135,7 +135,7 @@ static int debugfs_remount(struct super_block *sb, int *flags, char *data)
 	int err;
 	struct debugfs_fs_info *fsi = sb->s_fs_info;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	err = debugfs_parse_options(data, &fsi->mount_opts);
 	if (err)
 		goto fail;
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 6ffb7ba1547a..d558914da832 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -115,7 +115,7 @@ static void destroy_inodecache(void)
 
 static int efs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_RDONLY;
 	return 0;
 }
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index fd8536bc13da..29a2490e3dac 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -1326,7 +1326,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
 	struct ext2_mount_options new_opts;
 	int err;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 
 	spin_lock(&sbi->s_lock);
 	new_opts.s_mount_opt = sbi->s_mount_opt;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index ac2ffdbf54e6..b222f68fae67 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -5094,7 +5094,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 		}
 
 		if (*flags & SB_RDONLY) {
-			err = sync_filesystem(sb);
+			err = sync_filesystem(sb, NULL);
 			if (err < 0)
 				goto restore_opts;
 			err = dquot_suspend(sb, -1);
@@ -5590,7 +5590,7 @@ static int ext4_quota_off(struct super_block *sb, int type)
 	/* Force all delayed allocation blocks to be allocated.
 	 * Caller already holds s_umount sem */
 	if (test_opt(sb, DELALLOC))
-		sync_filesystem(sb);
+		sync_filesystem(sb, NULL);
 
 	if (!inode || !igrab(inode))
 		goto out;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index ffbbf0520d9e..1fd6b8516523 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -784,7 +784,7 @@ static int fat_remount(struct super_block *sb, int *flags, char *data)
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	*flags |= SB_NODIRATIME | (sbi->options.isvfat ? 0 : SB_NOATIME);
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 
 	/* make sure we update state on remount. */
 	new_rdonly = *flags & SB_RDONLY;
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 48b24bb50d02..11362c61408a 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -115,7 +115,7 @@ vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
 
 static int vxfs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_RDONLY;
 	return 0;
 }
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index ef309958e060..44c391b74008 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -140,7 +140,7 @@ static void fuse_evict_inode(struct inode *inode)
 
 static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	if (*flags & SB_MANDLOCK)
 		return -EINVAL;
 
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 884dd8b7d7b3..a18267610eba 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1241,7 +1241,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
 	struct gfs2_tune *gt = &sdp->sd_tune;
 	int error;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 
 	spin_lock(&gt->gt_spin);
 	args.ar_commit = gt->gt_logd_secs;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 9cb410ebab7c..de12fc340e86 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -113,7 +113,7 @@ static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static int hfs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_NODIRATIME;
 	if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
 		return 0;
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index a6c0f54c48c3..4088af4e4e27 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -328,7 +328,7 @@ static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
 		return 0;
 	if (!(*flags & SB_RDONLY)) {
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index f2c3ebcd309c..0db5184a5635 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -454,7 +454,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
 	int o;
 	struct hpfs_sb_info *sbi = hpfs_sb(s);
 
-	sync_filesystem(s);
+	sync_filesystem(s, NULL);
 
 	*flags |= SB_NOATIME;
 
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index ec3fba7d492f..941f481aeb13 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -113,7 +113,7 @@ static void destroy_inodecache(void)
 
 static int isofs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	if (!(*flags & SB_RDONLY))
 		return -EROFS;
 	return 0;
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 87bdf0f4cba1..2eaa32b551b4 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -243,7 +243,7 @@ static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
 	int err;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	err = jffs2_parse_options(c, data);
 	if (err)
 		return -EINVAL;
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index c4b99ad53f9c..1a45e0408ecc 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -463,7 +463,7 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
 	int flag = JFS_SBI(sb)->flag;
 	int ret;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	if (!parse_options(data, sb, &newLVSize, &flag))
 		return -EINVAL;
 
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 72e308c3e66b..286022e07afd 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -123,7 +123,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
 	struct minix_sb_info * sbi = minix_sb(sb);
 	struct minix_super_block * ms;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	ms = sbi->s_ms;
 	if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
 		return 0;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 5e470e233c83..02985cde5ff9 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2252,7 +2252,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 	struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
 	u32 nfsvers = nfss->nfs_client->rpc_ops->version;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 
 	/*
 	 * Userspace mount programs that send binary options generally send
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 280a28b62d13..5eb24cc5936e 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1126,7 +1126,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
 	unsigned long old_mount_opt;
 	int err;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	old_sb_flags = sb->s_flags;
 	old_mount_opt = nilfs->ns_mount_opt;
 
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index bb7159f697f2..64ce51f19aa2 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -469,7 +469,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
 
 	ntfs_debug("Entering with remount options string: %s", opt);
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 
 #ifndef NTFS_RW
 	/* For read-only compiled driver, enforce read-only flag. */
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 07a1a297c2ed..d64994d25281 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -641,7 +641,7 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 	u32 tmp;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 
 	if (!ocfs2_parse_options(sb, data, &parsed_options, 1) ||
 	    !ocfs2_check_set_options(sb, &parsed_options)) {
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 2200662a9bf1..e9ec9d24535a 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -368,7 +368,7 @@ static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
 
 static int openprom_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_NOATIME;
 	return 0;
 }
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index e8551c97de51..0720efaf80bc 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -289,7 +289,7 @@ static int ovl_sync_fs(struct super_block *sb, int wait)
 	upper_sb = ofs->upper_mnt->mnt_sb;
 
 	down_read(&upper_sb->s_umount);
-	ret = sync_filesystem(upper_sb);
+	ret = sync_filesystem(upper_sb, NULL);
 	up_read(&upper_sb->s_umount);
 
 	return ret;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 61b7340b357a..e9f7608d9b9b 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -82,7 +82,7 @@ int proc_remount(struct super_block *sb, int *flags, char *data)
 {
 	struct pid_namespace *pid = sb->s_fs_info;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	return !proc_parse_options(data, pid);
 }
 
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 5fcb845b9fec..617562d45614 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -273,7 +273,7 @@ static int pstore_show_options(struct seq_file *m, struct dentry *root)
 
 static int pstore_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	parse_options(data);
 
 	return 0;
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 3d46fe302fcb..94028eccaa15 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -44,7 +44,7 @@ static int qnx4_remount(struct super_block *sb, int *flags, char *data)
 {
 	struct qnx4_sb_info *qs;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	qs = qnx4_sb(sb);
 	qs->Version = QNX4_VERSION;
 	*flags |= SB_RDONLY;
diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
index 4aeb26bcb4d0..1c1c31d780c6 100644
--- a/fs/qnx6/inode.c
+++ b/fs/qnx6/inode.c
@@ -55,7 +55,7 @@ static int qnx6_show_options(struct seq_file *seq, struct dentry *root)
 
 static int qnx6_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_RDONLY;
 	return 0;
 }
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 92e695385875..1894f6ca9dc8 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2340,7 +2340,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
 		 * the quota file since if blocksize < pagesize, invalidation
 		 * of the cache could fail because of other unrelated dirty
 		 * data */
-		sync_filesystem(sb);
+		sync_filesystem(sb, NULL);
 		invalidate_bdev(sb->s_bdev);
 	}
 
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index b3a390eab9b7..0406ad05a2af 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -1454,7 +1454,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
 	if (arg && !new_opts)
 		return -ENOMEM;
 
-	sync_filesystem(s);
+	sync_filesystem(s, NULL);
 	reiserfs_write_lock(s);
 
 #ifdef CONFIG_QUOTA
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index 8f06fd1f3d69..afe6d8fbd4bf 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -450,7 +450,7 @@ static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
  */
 static int romfs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_RDONLY;
 	return 0;
 }
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index 8a73b97217c8..074734c26006 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -372,7 +372,7 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static int squashfs_remount(struct super_block *sb, int *flags, char *data)
 {
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	*flags |= SB_RDONLY;
 	return 0;
 }
diff --git a/fs/super.c b/fs/super.c
index 653397e56e80..8570a599d8f9 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -436,7 +436,7 @@ void generic_shutdown_super(struct super_block *sb)
 
 	if (sb->s_root) {
 		shrink_dcache_for_umount(sb);
-		sync_filesystem(sb);
+		sync_filesystem(sb, NULL);
 		sb->s_flags &= ~SB_ACTIVE;
 
 		fsnotify_unmount_inodes(sb);
@@ -1484,7 +1484,7 @@ int freeze_super(struct super_block *sb)
 	sb_wait_write(sb, SB_FREEZE_PAGEFAULT);
 
 	/* All writers are done so after syncing there won't be dirty data */
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 
 	/* Now wait for internal filesystem counter */
 	sb->s_writers.frozen = SB_FREEZE_FS;
diff --git a/fs/sync.c b/fs/sync.c
index 5fc211d16a00..dc395426a2c8 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -40,7 +40,7 @@ EXPORT_SYMBOL(vfs_sync_fs);
  * wait == 1 case since in that case write_inode() functions do
  * sync_dirty_buffer() and thus effectively write one block at a time.
  */
-static int __sync_filesystem(struct super_block *sb, int wait)
+static int __sync_filesystem(struct super_block *sb, int wait, errseq_t *since)
 {
 	if (wait)
 		sync_inodes_sb(sb);
@@ -55,7 +55,7 @@ static int __sync_filesystem(struct super_block *sb, int wait)
  * superblock.  Filesystem data as well as the underlying block
  * device.  Takes the superblock lock.
  */
-int sync_filesystem(struct super_block *sb)
+int sync_filesystem(struct super_block *sb, errseq_t *since)
 {
 	int ret;
 
@@ -71,10 +71,10 @@ int sync_filesystem(struct super_block *sb)
 	if (sb_rdonly(sb))
 		return 0;
 
-	ret = __sync_filesystem(sb, 0);
+	ret = __sync_filesystem(sb, 0, since);
 	if (ret < 0)
 		return ret;
-	return __sync_filesystem(sb, 1);
+	return __sync_filesystem(sb, 1, since);
 }
 EXPORT_SYMBOL(sync_filesystem);
 
@@ -181,7 +181,7 @@ SYSCALL_DEFINE1(syncfs, int, fd)
 	sb = f.file->f_path.dentry->d_sb;
 
 	down_read(&sb->s_umount);
-	ret = sync_filesystem(sb);
+	ret = sync_filesystem(sb, NULL);
 	up_read(&sb->s_umount);
 
 	fdput(f);
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 2232cf97840b..d0a45e05b4cc 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -60,7 +60,7 @@ static int sysv_remount(struct super_block *sb, int *flags, char *data)
 {
 	struct sysv_sb_info *sbi = SYSV_SB(sb);
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	if (sbi->s_forced_ro)
 		*flags |= SB_RDONLY;
 	return 0;
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index bea8ad876bf9..d70303524079 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -230,7 +230,7 @@ static int tracefs_remount(struct super_block *sb, int *flags, char *data)
 	int err;
 	struct tracefs_fs_info *fsi = sb->s_fs_info;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	err = tracefs_parse_options(data, &fsi->mount_opts);
 	if (err)
 		goto fail;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 6c397a389105..701184bcdbb9 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1847,7 +1847,7 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
 	int err;
 	struct ubifs_info *c = sb->s_fs_info;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	dbg_gen("old flags %#lx, new flags %#x", sb->s_flags, *flags);
 
 	err = ubifs_parse_options(c, data, 1);
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 7949c338efa5..25bb0ea13674 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -617,7 +617,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
 	int error = 0;
 	struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	if (lvidiu) {
 		int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev);
 		if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & SB_RDONLY))
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 8254b8b3690f..bfa3015da935 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -1303,7 +1303,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
 	unsigned new_mount_opt, ufstype;
 	unsigned flags;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	mutex_lock(&UFS_SB(sb)->s_lock);
 	uspi = UFS_SB(sb)->s_uspi;
 	flags = UFS_SB(sb)->s_flags;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index d71424052917..3bd0ff52b7d8 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1281,7 +1281,7 @@ xfs_fs_remount(
 	if (error)
 		return error;
 
-	sync_filesystem(sb);
+	sync_filesystem(sb, NULL);
 	while ((p = strsep(&options, ",")) != NULL) {
 		int token;
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index eee017c5a821..91be22f83ebd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2492,7 +2492,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb)
 }
 #endif
 int vfs_sync_fs(struct super_block *sb, int wait);
-extern int sync_filesystem(struct super_block *);
+extern int sync_filesystem(struct super_block *, errseq_t *);
 extern const struct file_operations def_blk_fops;
 extern const struct file_operations def_chr_fops;
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/5] vfs: track per-sb writeback errors and report them to syncfs
  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 ` [PATCH v2 1/5] vfs: push __sync_blockdev calls down into sync_fs routines Jeff Layton
  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 ` Jeff Layton
  2018-05-31 11:29 ` [PATCH v2 4/5] buffer: record blockdev write errors in super_block that backs them Jeff Layton
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jeff Layton @ 2018-05-31 11:29 UTC (permalink / raw)
  To: viro; +Cc: willy, andres, linux-fsdevel, linux-kernel, cmaiolino

From: Jeff Layton <jlayton@redhat.com>

Usually we suggest that applications call fsync when they want to
ensure that all data written to the file has made it to the backing
store, but that can be inefficient when there are a lot of open
files.

Calling syncfs on the filesystem can be more efficient in some
situations, but the error reporting doesn't currently work the way most
people expect. If a single inode on a filesystem reports a writeback
error, syncfs won't necessarily return an error. syncfs only returns an
error if __sync_blockdev fails, and on some filesystems that's a no-op.

It would be better if syncfs reported an error if there were any writeback
failures. Then applications could call syncfs to see if there are any
errors on any open files, and could then call fsync on all of the other
descriptors to figure out which one failed.

This patch adds a new errseq_t to struct super_block, and has
mapping_set_error also record writeback errors there.

To report those errors, we also need to keep an errseq_t for in struct
file to act as a cursor, but growing struct file for this purpose is
undesirable. We could just reuse f_wb_err, but someone could mix calls
to fsync and syncfs and that would break things.

This patch implements an alternative suggested by Willy. When the file
is opened with O_PATH, then we repurpose the f_wb_err cursor to track
s_wb_err. Any file opened with O_PATH will not have an fsync
file_operation, and attempts to fsync such a fd will return -EBADF.

Note that calling syncfs on an O_PATH descriptor today will also return
-EBADF, so this scheme gives userland a way to tell whether this
mechanism will work at runtime.

Cc: Andres Freund <andres@anarazel.de>
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/open.c               |  6 +++---
 fs/quota/dquot.c        |  4 ++--
 fs/sync.c               | 28 +++++++++++++++++++++-------
 include/linux/fs.h      |  5 ++++-
 include/linux/pagemap.h |  5 ++++-
 5 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index c5ee7cd60424..3e8c7b16abb8 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -739,15 +739,15 @@ static int do_dentry_open(struct file *f,
 	f->f_inode = inode;
 	f->f_mapping = inode->i_mapping;
 
-	/* Ensure that we skip any errors that predate opening of the file */
-	f->f_wb_err = filemap_sample_wb_err(f->f_mapping);
-
 	if (unlikely(f->f_flags & O_PATH)) {
 		f->f_mode = FMODE_PATH;
 		f->f_op = &empty_fops;
+		f->f_wb_err = errseq_sample(&f->f_path.dentry->d_sb->s_wb_err);
 		goto done;
 	}
 
+	f->f_wb_err = filemap_sample_wb_err(f->f_mapping);
+
 	if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) {
 		error = get_write_access(inode);
 		if (unlikely(error))
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 1894f6ca9dc8..b788678f0f03 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -686,7 +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... */
-	vfs_sync_fs(sb, 1);
+	vfs_sync_fs(sb, 1, NULL);
 
 	/*
 	 * Now when everything is written we can discard the pagecache so
@@ -2243,7 +2243,7 @@ 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). */
-	vfs_sync_fs(sb, 1);
+	vfs_sync_fs(sb, 1, NULL);
 
 	/* Now the quota files are just ordinary files and we can set the
 	 * inode flags back. Moreover we discard the pagecache so that
diff --git a/fs/sync.c b/fs/sync.c
index dc395426a2c8..be547c82e9d8 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -25,11 +25,20 @@
  * 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)
+int vfs_sync_fs(struct super_block *sb, int wait, errseq_t *since)
 {
+	int ret;
+
 	if (sb->s_op->sync_fs)
-		return sb->s_op->sync_fs(sb, wait);
-	return __sync_blockdev(sb->s_bdev, wait);
+		ret = sb->s_op->sync_fs(sb, wait);
+	ret = __sync_blockdev(sb->s_bdev, wait);
+
+	if (since) {
+		int ret2 = errseq_check_and_advance(&sb->s_wb_err, since);
+		if (ret == 0)
+			ret = ret2;
+	}
+	return ret;
 }
 EXPORT_SYMBOL(vfs_sync_fs);
 
@@ -47,7 +56,7 @@ static int __sync_filesystem(struct super_block *sb, int wait, errseq_t *since)
 	else
 		writeback_inodes_sb(sb, WB_REASON_SYNC);
 
-	return vfs_sync_fs(sb, wait);
+	return vfs_sync_fs(sb, wait, since);
 }
 
 /*
@@ -90,7 +99,7 @@ static void sync_fs_one_sb(struct super_block *sb, void *arg)
 
 	if (sb_rdonly(sb))
 		return;
-	vfs_sync_fs(sb, wait);
+	vfs_sync_fs(sb, wait, NULL);
 }
 
 static void fdatawrite_one_bdev(struct block_device *bdev, void *arg)
@@ -172,16 +181,21 @@ void emergency_sync(void)
  */
 SYSCALL_DEFINE1(syncfs, int, fd)
 {
-	struct fd f = fdget(fd);
+	struct fd f = fdget_raw(fd);
 	struct super_block *sb;
+	errseq_t *wberr = NULL;
 	int ret;
 
 	if (!f.file)
 		return -EBADF;
+
 	sb = f.file->f_path.dentry->d_sb;
 
+	if (f.file->f_flags & O_PATH)
+		wberr = &f.file->f_wb_err;
+
 	down_read(&sb->s_umount);
-	ret = sync_filesystem(sb, NULL);
+	ret = sync_filesystem(sb, wberr);
 	up_read(&sb->s_umount);
 
 	fdput(f);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 91be22f83ebd..a9ab2be0123f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1416,6 +1416,9 @@ struct super_block {
 	/* Being remounted read-only */
 	int s_readonly_remount;
 
+	/* per-sb errseq_t for reporting writeback errors via syncfs */
+	errseq_t s_wb_err;
+
 	/* AIO completions deferred from interrupt context */
 	struct workqueue_struct *s_dio_done_wq;
 	struct hlist_head s_pins;
@@ -2491,7 +2494,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb)
 	return false;
 }
 #endif
-int vfs_sync_fs(struct super_block *sb, int wait);
+int vfs_sync_fs(struct super_block *sb, int wait, errseq_t *since);
 extern int sync_filesystem(struct super_block *, errseq_t *);
 extern const struct file_operations def_blk_fops;
 extern const struct file_operations def_chr_fops;
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index b1bd2186e6d2..2de87c5a2718 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -51,7 +51,10 @@ static inline void mapping_set_error(struct address_space *mapping, int error)
 		return;
 
 	/* Record in wb_err for checkers using errseq_t based tracking */
-	filemap_set_wb_err(mapping, error);
+	__filemap_set_wb_err(mapping, error);
+
+	/* Record it in superblock */
+	errseq_set(&mapping->host->i_sb->s_wb_err, error);
 
 	/* Record it in flags for now, for legacy callers */
 	if (error == -ENOSPC)
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/5] buffer: record blockdev write errors in super_block that backs them
  2018-05-31 11:29 [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails Jeff Layton
                   ` (2 preceding siblings ...)
  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 ` 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
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jeff Layton @ 2018-05-31 11:29 UTC (permalink / raw)
  To: viro; +Cc: willy, andres, linux-fsdevel, linux-kernel, cmaiolino

From: Jeff Layton <jlayton@redhat.com>

When syncing out a block device (a'la __sync_blockdev), any error
encountered will only be recorded in the bd_inode's mapping. When the
blockdev contains a filesystem however, we'd like to also record the
error in the super_block that's stored there.

Make mark_buffer_write_io_error also record the error in the
corresponding super_block when a writeback error occurs and the block
device contains a mounted superblock.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/buffer.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/buffer.c b/fs/buffer.c
index 249b83fafe48..dae2a857d5bc 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1117,6 +1117,8 @@ void mark_buffer_write_io_error(struct buffer_head *bh)
 		mapping_set_error(bh->b_page->mapping, -EIO);
 	if (bh->b_assoc_map)
 		mapping_set_error(bh->b_assoc_map, -EIO);
+	if (bh->b_bdev->bd_super)
+		errseq_set(&bh->b_bdev->bd_super->s_wb_err, -EIO);
 }
 EXPORT_SYMBOL(mark_buffer_write_io_error);
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 5/5] vfs: add a new ioctl for fetching the superblock's errseq_t
  2018-05-31 11:29 [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails Jeff Layton
                   ` (3 preceding siblings ...)
  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 ` 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
  6 siblings, 0 replies; 8+ messages in thread
From: Jeff Layton @ 2018-05-31 11:29 UTC (permalink / raw)
  To: viro; +Cc: willy, andres, linux-fsdevel, linux-kernel, cmaiolino

From: Jeff Layton <jlayton@redhat.com>

The postgres developers recently mentioned that they'd like a way to
tell whether there have been any writeback errors on a given filesystem
without having to forcibly sync out all buffered writes.

Now that we have a per-sb errseq_t that tracks whether any inode on the
filesystem might have failed writeback, we can present that to userland
applications via a new interface. Add a new generic fs ioctl for that
purpose. This just reports the current state of the errseq_t counter
with the SEEN bit masked off.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/ioctl.c              |  3 +++
 include/linux/errseq.h  |  1 +
 include/uapi/linux/fs.h |  1 +
 lib/errseq.c            | 33 +++++++++++++++++++++++++++++++--
 4 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/fs/ioctl.c b/fs/ioctl.c
index 4823431d1c9d..fd5e6b7f395c 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -667,6 +667,9 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
 	case FS_IOC_FIEMAP:
 		return ioctl_fiemap(filp, arg);
 
+	case FS_IOC_GETFSERR:
+		return put_user(errseq_scrape(&inode->i_sb->s_wb_err), argp);
+
 	case FIGETBSZ:
 		return put_user(inode->i_sb->s_blocksize, argp);
 
diff --git a/include/linux/errseq.h b/include/linux/errseq.h
index fc2777770768..de165623fa86 100644
--- a/include/linux/errseq.h
+++ b/include/linux/errseq.h
@@ -9,6 +9,7 @@ typedef u32	errseq_t;
 
 errseq_t errseq_set(errseq_t *eseq, int err);
 errseq_t errseq_sample(errseq_t *eseq);
+errseq_t errseq_scrape(errseq_t *eseq);
 int errseq_check(errseq_t *eseq, errseq_t since);
 int errseq_check_and_advance(errseq_t *eseq, errseq_t *since);
 #endif
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index d2a8313fabd7..6dedb35c5a96 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -253,6 +253,7 @@ struct fsxattr {
 #define FS_IOC32_SETVERSION		_IOW('v', 2, int)
 #define FS_IOC_FSGETXATTR		_IOR ('X', 31, struct fsxattr)
 #define FS_IOC_FSSETXATTR		_IOW ('X', 32, struct fsxattr)
+#define FS_IOC_GETFSERR			_IOR('e', 1, unsigned int)
 
 /*
  * File system encryption support
diff --git a/lib/errseq.c b/lib/errseq.c
index 81f9e33aa7e7..8ded0920eed3 100644
--- a/lib/errseq.c
+++ b/lib/errseq.c
@@ -108,7 +108,7 @@ errseq_t errseq_set(errseq_t *eseq, int err)
 EXPORT_SYMBOL(errseq_set);
 
 /**
- * errseq_sample() - Grab current errseq_t value.
+ * errseq_sample() - Grab current errseq_t value (or 0 if it hasn't been seen)
  * @eseq: Pointer to errseq_t to be sampled.
  *
  * This function allows callers to initialise their errseq_t variable.
@@ -117,7 +117,7 @@ EXPORT_SYMBOL(errseq_set);
  * see it the next time it checks for an error.
  *
  * Context: Any context.
- * Return: The current errseq value.
+ * Return: The current errseq value or 0 if it wasn't previously seen
  */
 errseq_t errseq_sample(errseq_t *eseq)
 {
@@ -130,6 +130,35 @@ errseq_t errseq_sample(errseq_t *eseq)
 }
 EXPORT_SYMBOL(errseq_sample);
 
+/**
+ * errseq_scrape() - Grab current errseq_t value
+ * @eseq: Pointer to errseq_t to be sampled.
+ *
+ * This function allows callers to scrape the current value of an errseq_t.
+ * Unlike errseq_sample, this will always return the current value with
+ * the SEEN flag unset, even when the value has not yet been seen.
+ *
+ * Context: Any context.
+ * Return: The current errseq value with ERRSEQ_SEEN masked off
+ */
+errseq_t errseq_scrape(errseq_t *eseq)
+{
+	errseq_t old = READ_ONCE(*eseq);
+
+	/*
+	 * For the common case of no errors ever having been set, we can skip
+	 * marking the SEEN bit. Once an error has been set, the value will
+	 * never go back to zero.
+	 */
+	if (old != 0) {
+		errseq_t new = old | ERRSEQ_SEEN;
+		if (old != new)
+			cmpxchg(eseq, old, new);
+	}
+	return old & ~ERRSEQ_SEEN;
+}
+EXPORT_SYMBOL(errseq_scrape);
+
 /**
  * errseq_check() - Has an error occurred since a particular sample point?
  * @eseq: Pointer to errseq_t value to be checked.
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [fstests PATCH] generic: test reporting of wb errors via syncfs
  2018-05-31 11:29 [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails Jeff Layton
                   ` (4 preceding siblings ...)
  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 ` Jeff Layton
  2018-06-01 16:16 ` [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails Jeff Layton
  6 siblings, 0 replies; 8+ messages in thread
From: Jeff Layton @ 2018-05-31 15:02 UTC (permalink / raw)
  To: fstests; +Cc: linux-fsdevel, willy, andres, cmaiolino, linux-kernel, viro

From: Jeff Layton <jlayton@redhat.com>

Add a test for new syncfs error reporting behavior. When an inode fails
to be written back, ensure that we report an error to a subsequent call
to syncfs().

Because we don't want to grow struct file in order to support this, we
only do this if the file was opened with O_PATH flag.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 tests/generic/999     | 99 +++++++++++++++++++++++++++++++++++++++++++
 tests/generic/999.out |  8 ++++
 tests/generic/group   |  1 +
 3 files changed, 108 insertions(+)
 create mode 100755 tests/generic/999
 create mode 100644 tests/generic/999.out

This is the companion testcase patch to this series:

    [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails

We probably don't want to merge this until it's clear that treating
syncfs differently on an O_PATH open is OK.

diff --git a/tests/generic/999 b/tests/generic/999
new file mode 100755
index 000000000000..e468d0108ce5
--- /dev/null
+++ b/tests/generic/999
@@ -0,0 +1,99 @@
+#! /bin/bash
+# FS QA Test No. 999
+#
+# Open a file and write to it and fsync. Then, flip the data device to throw
+# errors, write to it again and do an fdatasync. Then open an O_PATH fd on the
+# same file and call syncfs against it and ensure that an error is reported,
+# then call syncfs again and ensure that no error is reported. Finally, repeat
+# the open and syncfs and ensure that there is no error reported.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2018, Jeff Layton <jlayton@redhat.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1    # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+	_dmerror_cleanup
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/dmerror
+
+# real QA test starts here
+_supported_os Linux
+_require_xfs_io_command 'open' '-P'
+_require_scratch_nocheck
+# This test uses "dm" without taking into account the data could be on
+# realtime subvolume, thus the test will fail with rtinherit=1
+_require_no_rtinherit
+_require_dm_target error
+
+rm -f $seqres.full
+
+echo "Format and mount"
+_scratch_mkfs > $seqres.full 2>&1
+_dmerror_init
+_dmerror_mount
+
+datalen=65536
+_require_fs_space $SCRATCH_MNT $datalen
+
+# use fd 5 to hold file open
+testfile=$SCRATCH_MNT/syncfs-reports-errors
+exec 5>$testfile
+
+# write some data to file and fsync it out
+$XFS_IO_PROG -c "pwrite -W -q 0 $datalen" $testfile
+
+# flip device to non-working mode
+_dmerror_load_error_table
+
+# rewrite the data, and do fdatasync
+$XFS_IO_PROG -c "pwrite -w -q 0 $datalen" $testfile
+
+# heal the device error
+_dmerror_load_working_table
+
+# open again and call syncfs twice
+echo "One of the following syncfs calls should fail with EIO:"
+$XFS_IO_PROG -P -c syncfs -c syncfs $testfile
+echo "done"
+
+echo "This syncfs call should succeed:"
+$XFS_IO_PROG -P -c syncfs $testfile
+echo "done"
+
+# close file
+exec 5>&-
+
+# success, all done
+_dmerror_cleanup
+
+status=0
+exit
diff --git a/tests/generic/999.out b/tests/generic/999.out
new file mode 100644
index 000000000000..950a2ba42503
--- /dev/null
+++ b/tests/generic/999.out
@@ -0,0 +1,8 @@
+QA output created by 999
+Format and mount
+fdatasync: Input/output error
+One of the following syncfs calls should fail with EIO:
+syncfs: Input/output error
+done
+This syncfs call should succeed:
+done
diff --git a/tests/generic/group b/tests/generic/group
index 752ee35ed3f7..e35491f69e97 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -497,3 +497,4 @@
 493 auto quick swap
 494 auto quick swap
 495 auto quick swap
+999 auto quick
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails
  2018-05-31 11:29 [PATCH v2 0/5] vfs: allow syncfs to return an error when inode writeback fails Jeff Layton
                   ` (5 preceding siblings ...)
  2018-05-31 15:02 ` [fstests PATCH] generic: test reporting of wb errors via syncfs Jeff Layton
@ 2018-06-01 16:16 ` Jeff Layton
  6 siblings, 0 replies; 8+ messages in thread
From: Jeff Layton @ 2018-06-01 16:16 UTC (permalink / raw)
  To: viro; +Cc: willy, andres, linux-fsdevel, linux-kernel, cmaiolino, David Howells

On Thu, 2018-05-31 at 07:29 -0400, Jeff Layton wrote:
> From: Jeff Layton <jlayton@redhat.com>
> 
> v2: don't modify sync_fs op prototype, handle errors at vfs layer
> 
> The syncfs system call returns an int error code, but in general it does
> not return errors when an inode fails writeback. It will return an error
> if __sync_blockdev fails, but that's not useful on non-block based
> filesystems and is generally not useful on more modern filesystems that
> don't rely on that call.
> 
> This patchset aims to remedy that by adding some infrastructure to allow
> syncfs to return an error when an inode fails writeback. The basic idea
> is to add a new errseq_t to the super_block to record writeback errors.
> 
> Because we don't want to grow struct file for this purpose, this new
> behavior is only activated when the fd passed to syncfs is opened with
> O_PATH.
> 
> One of the items on the wishlist from the PostgreSQL developers at this
> year's LSF/MM was a way to tell whether there has been any writeback
> failure on a filesystem without forcing everything to be synced out.
> 
> The final patch in this series adds a new generic vfs ioctl that
> presents the new sb->s_wb_err field to userland applications that wish
> to see it.
> 
> Comments and suggestions welcome.
> 
> Jeff Layton (5):
>   vfs: push __sync_blockdev calls down into sync_fs routines
>   vfs: add an errseq_t pointer arg to sync_filesystem and
>     __sync_filesystem
>   vfs: track per-sb writeback errors and report them to syncfs
>   buffer: record blockdev write errors in super_block that backs them
>   vfs: add a new ioctl for fetching the superblock's errseq_t
> 
>  drivers/staging/ncpfs/inode.c |  2 +-
>  fs/adfs/super.c               |  2 +-
>  fs/affs/super.c               |  4 +--
>  fs/befs/linuxvfs.c            |  2 +-
>  fs/block_dev.c                |  3 ++-
>  fs/btrfs/super.c              |  4 +--
>  fs/buffer.c                   |  2 ++
>  fs/cachefiles/interface.c     |  2 +-
>  fs/cifs/cifsfs.c              |  2 +-
>  fs/coda/inode.c               |  2 +-
>  fs/cramfs/inode.c             |  2 +-
>  fs/debugfs/inode.c            |  2 +-
>  fs/efs/super.c                |  2 +-
>  fs/ext2/super.c               |  4 +--
>  fs/ext4/super.c               | 13 +++++-----
>  fs/f2fs/super.c               | 15 ++++++-----
>  fs/fat/inode.c                |  2 +-
>  fs/freevxfs/vxfs_super.c      |  2 +-
>  fs/fuse/inode.c               |  2 +-
>  fs/gfs2/super.c               |  6 +++--
>  fs/hfs/super.c                |  4 +--
>  fs/hfsplus/super.c            |  2 +-
>  fs/hpfs/super.c               |  2 +-
>  fs/internal.h                 |  7 ------
>  fs/ioctl.c                    |  3 +++
>  fs/isofs/inode.c              |  2 +-
>  fs/jffs2/super.c              |  2 +-
>  fs/jfs/super.c                |  5 ++--
>  fs/minix/inode.c              |  2 +-
>  fs/nfs/super.c                |  2 +-
>  fs/nilfs2/super.c             |  7 +++---
>  fs/ntfs/super.c               |  2 +-
>  fs/ocfs2/super.c              |  4 +--
>  fs/open.c                     |  6 ++---
>  fs/openpromfs/inode.c         |  2 +-
>  fs/overlayfs/super.c          |  2 +-
>  fs/proc/root.c                |  2 +-
>  fs/pstore/inode.c             |  2 +-
>  fs/qnx4/inode.c               |  2 +-
>  fs/qnx6/inode.c               |  2 +-
>  fs/quota/dquot.c              | 11 +++-----
>  fs/reiserfs/super.c           |  4 +--
>  fs/romfs/super.c              |  2 +-
>  fs/squashfs/super.c           |  2 +-
>  fs/super.c                    |  4 +--
>  fs/sync.c                     | 47 +++++++++++++++++++++++++++--------
>  fs/sysv/inode.c               |  5 ++--
>  fs/tracefs/inode.c            |  2 +-
>  fs/ubifs/super.c              |  2 +-
>  fs/udf/super.c                |  2 +-
>  fs/ufs/super.c                |  2 +-
>  fs/xfs/xfs_super.c            |  2 +-
>  include/linux/errseq.h        |  1 +
>  include/linux/fs.h            | 13 +++++++++-
>  include/linux/pagemap.h       |  5 +++-
>  include/uapi/linux/fs.h       |  1 +
>  lib/errseq.c                  | 33 ++++++++++++++++++++++--
>  57 files changed, 173 insertions(+), 102 deletions(-)
> 

After chatting with David Howells about this, I think I'm going to
withdraw this set and do one that only exposes s_wb_err via the new
fsinfo syscall that's going in soon. We can always add the other
interfaces later if it's 

Let's just disregard this set for now and I'll look at respinning it
around that as an interface.

Cheers,
-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2018-06-01 16:16 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH v2 1/5] vfs: push __sync_blockdev calls down into sync_fs routines Jeff Layton
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).