vfs: have syncfs return an error when inode writeback fails
Subsystems (38)
cover vfs: have syncfs return an error when inode writeback fails
From: Jeff Layton <[email protected]>
Currently, syncfs does not return errors when one of the inodes fails to be written back. It will return errors based on the legacy AS_EIO and AS_ENOSPC flags when syncing out the block device fails, but that's not particularly helpful for filesystems that aren't backed by a blockdev and more granular errors are often not caught.
At LSF/MM this year, we had a discussion about tracking writeback errors on a per-sb basis to help remedy this. This patchset is an inital foray into doing that:
The basic idea is to add a new errseq_t to struct super_block, and use that to track writeback errors for the filesystem as a whole.
Because syncfs is not a common operation, it's not desirable to grow struct file in order to house an errseq_t cursor for it. Willy's suggestion was to reuse file->f_wb_err, but only when the file is opened with O_PATH. fsync always returns an error on an O_PATH fd, so this should be safe, and seems semantically sane, given that syncfs operates on the whole filesystem.
The patchset starts by pushing the __sync_blockdev calls down into the various sync_fs operations. It then plumbs in an extra errseq_t pointer into the sync_fs ops, and the relevant callers. It then adds the new errseq_t field to struct super_block, and adds the machinery to handle syncfs on an O_PATH open correctly. Lastly, it has some filesystems return stored writeback errors in sync_fs ops when they are passed a non-NULL errseq_t pointer.
This is just a start (more filesystems will need similar patches to the later ones in the pile). This all works vs. the fstests testcase I have. I haven't submitted that testcase yet, as I want to get consensus about the interface. Does it make sense to treat O_PATH opens specially like this?
Another thing on the wishlist for this is to expose the per-sb errseq_t via another interface so that applications could periodically check to see whether there has been a writeback error without syncing out the whole fs. This patch doesn't add that yet, but once sb->s_wb_err is in place and tracking errors it should be simple to do (possibly via a new generic filesystem ioctl).
Jeff Layton (11):
vfs: push __sync_blockdev calls down into sync_fs routines
vfs: add a new errseq_t pointer to sync_fs prototype
vfs: add an errseq_t pointer to sync_filesystem
vfs: add errseq_t pointer to __sync_filesystem
fs: track per-sb writeback errors and report them to syncfs
buffer: record blockdev write errors in super_block that backs them
ext4: have sync_fs op report writeback errors when passed a since
pointer
xfs: have sync_fs op report writeback errors when passed a since
pointer
btrfs: have sync_fs op report writeback errors when passed a since
pointer
ext2: have sync_fs op report writeback errors when passed a since
pointer
vfs: have call_sync_fs op report writeback errors when passed a since
pointer
drivers/staging/ncpfs/inode.c | 2 +- fs/adfs/super.c | 2 +- fs/affs/super.c | 6 +++--- fs/befs/linuxvfs.c | 2 +- fs/block_dev.c | 3 ++- fs/btrfs/ctree.h | 2 +- fs/btrfs/ioctl.c | 2 +- fs/btrfs/super.c | 28 +++++++++++++++++++--------- fs/buffer.c | 2 ++ fs/cachefiles/interface.c | 2 +- fs/ceph/super.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/exofs/super.c | 2 +- fs/ext2/super.c | 19 +++++++++++++------ fs/ext4/super.c | 19 +++++++++++-------- fs/f2fs/f2fs.h | 2 +- fs/f2fs/file.c | 6 +++--- fs/f2fs/namei.c | 16 ++++++++-------- fs/f2fs/segment.c | 2 +- fs/f2fs/super.c | 19 +++++++++++-------- fs/fat/inode.c | 2 +- fs/freevxfs/vxfs_super.c | 2 +- fs/fuse/inode.c | 2 +- fs/gfs2/super.c | 8 +++++--- fs/hfs/super.c | 6 +++--- fs/hfsplus/super.c | 10 +++++----- fs/hpfs/super.c | 2 +- fs/internal.h | 7 ------- fs/isofs/inode.c | 2 +- fs/jffs2/super.c | 4 ++-- fs/jfs/super.c | 7 +++---- fs/minix/inode.c | 2 +- fs/nfs/super.c | 2 +- fs/nilfs2/super.c | 9 +++++---- fs/ntfs/super.c | 2 +- fs/ocfs2/super.c | 8 ++++---- fs/open.c | 6 +++--- fs/openpromfs/inode.c | 2 +- fs/overlayfs/super.c | 4 ++-- 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 | 8 ++++---- fs/romfs/super.c | 2 +- fs/squashfs/super.c | 2 +- fs/super.c | 4 ++-- fs/sync.c | 28 +++++++++++++++++----------- fs/sysv/inode.c | 7 +++---- fs/tracefs/inode.c | 2 +- fs/ubifs/super.c | 4 ++-- fs/udf/super.c | 6 +++--- fs/ufs/super.c | 6 +++--- fs/xfs/xfs_super.c | 18 +++++++++++++----- include/linux/fs.h | 35 +++++++++++++++++++++++++++++++++-- include/linux/pagemap.h | 5 ++++- 61 files changed, 223 insertions(+), 158 deletions(-)
Signature · 1 line
2.17.0
RFC PATCH 1/11 vfs: push __sync_blockdev calls down into sync_fs routines
From: Jeff Layton <[email protected]>
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.
--- 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(-)
fs/affs/super.c +1 -1
@@ -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)
fs/block_dev.c +1 -0
@@ -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
fs/ext2/super.c +1 -1
@@ -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)
fs/ext4/super.c +5 -4
@@ -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; }/*
fs/f2fs/super.c +9 -6
@@ -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)
fs/gfs2/super.c +3 -1
@@ -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)
fs/hfs/super.c +1 -1
@@ -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); }/*
fs/internal.h +0 -7
@@ -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 /*
fs/jfs/super.c +1 -2
@@ -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)
fs/nilfs2/super.c +3 -2
@@ -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,
fs/ocfs2/super.c +1 -1
@@ -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)
fs/quota/dquot.c +3 -6
@@ -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
fs/reiserfs/super.c +1 -1
@@ -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)
fs/sync.c +4 -5
@@ -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)
fs/sysv/inode.c +1 -2
@@ -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)
fs/xfs/xfs_super.c +3 -3
@@ -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
include/linux/fs.h +18 -0
@@ -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 );
Signature · 1 line
2.17.0
Re: [RFC PATCH 01/11] vfs: push __sync_blockdev calls down into sync_fs routines
Quoted 12 lines
fs/xfs/xfs_super.c +1
-1@@ -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) {
fs/xfs/xfs_super.c xfs_fs_sync_fs( · line 1112
Quoted 7 lines
fs/xfs/xfs_super.c +2
-2@@ -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);
XFS never uses the block device mapping for anything, so this is not needed.
fs/xfs/xfs_super.c xfs_fs_sync_fs(
Quoted 10 lines
fs/xfs/xfs_super.c +10
-0+/* +* 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); +}
The proper name for this would be vfs_sync_fs. And I don't think it warrants an inline.
Re: [RFC PATCH 01/11] vfs: push __sync_blockdev calls down into sync_fs routines
Quoted 9 lines · Christoph Hellwig
Quoted 9 lines
fs/xfs/xfs_super.c +1
-1@@ -1097,7 +1097,7 @@ xfs_fs_sync_fs(* Doing anything during the async pass would be counterproductive. */ if (!wait) -return 0 ; + goto out;
Quoted 14 lines
fs/xfs/xfs_super.c xfs_fs_sync_fs( · line 1112
Quoted 10 lines
fs/xfs/xfs_super.c +2
-2xfs_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);XFS never uses the block device mapping for anything, so this is not needed.
Thanks, I wasn't sure about xfs. I'll drop this hunk.
FWIW, I think pushing this call down into the sync_fs routines is still probably the right thing to do, regardless of the state of the later patches.
Quoted 5 lines
Quoted 5 lines
fs/xfs/xfs_super.c +5
-0+/* +* 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)
Quoted 8 lines
fs/xfs/xfs_super.c
Quoted 5 lines
fs/xfs/xfs_super.c +5
-0+{ +if (sb->s_op->sync_fs) +return sb->s_op->sync_fs (sb, wait); +return __sync_blockdev (sb->s_bdev, wait); +}The proper name for this would be
vfs_sync_fs. And I don't think it warrants an inline.
I patterned the name after the call_mmap (and now-defunct call_fsync) helpers. I'll rename it and change it to be non-inlined.
Thanks,
Signature · 1 line
Jeff Layton <[email protected]>
RFC PATCH 2/11 vfs: add a new errseq_t pointer to sync_fs prototype
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
Plumb a new "since" pointer into the ->sync_fs operation. This will eventually allow us to pass in an optional pointer to an errseq_t to act as a cursor for error reporting.
For now it's ignored and all of the callers pass in NULL.
--- fs/affs/super.c | 2 +- fs/btrfs/ctree.h | 2 +- fs/btrfs/ioctl.c | 2 +- fs/btrfs/super.c | 2 +- fs/ceph/super.c | 2 +- fs/exofs/super.c | 2 +- fs/ext2/super.c | 8 ++++---- fs/ext4/super.c | 4 ++-- fs/f2fs/f2fs.h | 2 +- fs/f2fs/file.c | 6 +++--- fs/f2fs/namei.c | 16 ++++++++-------- fs/f2fs/segment.c | 2 +- fs/f2fs/super.c | 4 ++-- fs/gfs2/super.c | 2 +- fs/hfs/super.c | 2 +- fs/hfsplus/super.c | 8 ++++---- fs/jffs2/super.c | 2 +- fs/jfs/super.c | 2 +- fs/nilfs2/super.c | 2 +- fs/ocfs2/super.c | 4 ++-- fs/overlayfs/super.c | 2 +- fs/quota/dquot.c | 4 ++-- fs/reiserfs/super.c | 4 ++-- fs/sync.c | 4 ++-- fs/sysv/inode.c | 2 +- fs/ubifs/super.c | 2 +- fs/udf/super.c | 4 ++-- fs/ufs/super.c | 4 ++-- fs/xfs/xfs_super.c | 3 ++- include/linux/fs.h | 7 ++++--- 30 files changed, 57 insertions(+), 55 deletions(-)
fs/affs/super.c +1 -1
@@ -55,7 +55,7 @@ affs_put_super(struct super_block *sb) }static int -affs_sync_fs (struct super_block *sb,int wait) +affs_sync_fs (struct super_block *sb,int wait,errseq_t *since) {affs_commit_super (sb, wait);return __sync_blockdev (sb->s_bdev, wait);
fs/btrfs/ctree.h +1 -1
@@ -3316,7 +3316,7 @@ void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info);/* super.c */ int btrfs_parse_options (struct btrfs_fs_info *info,char *options,unsigned long new_flags); -int btrfs_sync_fs (struct super_block *sb,int wait); +int btrfs_sync_fs (struct super_block *sb,int wait,errseq_t *since); static inline __printf(2, 3) __cold void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
fs/btrfs/ioctl.c +1 -1
@@ -5500,7 +5500,7 @@ long btrfs_ioctl(struct file *file, unsigned int ret =btrfs_start_delalloc_roots (fs_info,0 ,-1 );if (ret)return ret; - ret =btrfs_sync_fs (inode->i_sb,1 ); + ret =btrfs_sync_fs (inode->i_sb,1 ,NULL );/* * The transaction thread may want to do more work, * namely it pokes the cleaner kthread that will start
fs/btrfs/super.c +1 -1
@@ -1226,7 +1226,7 @@ static int btrfs_fill_super(struct super_block *sb,return err; } -int btrfs_sync_fs (struct super_block *sb,int wait) +int btrfs_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct btrfs_trans_handle *trans;struct btrfs_fs_info *fs_info =btrfs_sb (sb);
fs/ceph/super.c +1 -1
@@ -103,7 +103,7 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) } -static int ceph_sync_fs (struct super_block *sb,int wait) +static int ceph_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct ceph_fs_client *fsc =ceph_sb_to_client (sb);
fs/exofs/super.c +1 -1
@@ -364,7 +364,7 @@ static const struct export_operations exofs_export_ops;/* * Write the superblock to the OSD */ -static int exofs_sync_fs (struct super_block *sb,int wait) +static int exofs_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct exofs_sb_info *sbi;struct exofs_fscb *fscb;
fs/ext2/super.c +4 -4
@@ -41,7 +41,7 @@static void ext2_write_super (struct super_block *sb);static int ext2_remount (struct super_block * sb,int * flags,char * data);static int ext2_statfs (struct dentry * dentry,struct kstatfs * buf); -static int ext2_sync_fs (struct super_block *sb,int wait); +static int ext2_sync_fs (struct super_block *sb,int wait,errseq_t *since);static int ext2_freeze (struct super_block *sb);static int ext2_unfreeze (struct super_block *sb);
@@ -1262,7 +1262,7 @@ void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es,* may have been checked while mounted and e2fsck may have * set s_state to EXT2_VALID_FS after some corrections. */ -static int ext2_sync_fs (struct super_block *sb,int wait) +static int ext2_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct ext2_sb_info *sbi =EXT2_SB (sb);struct ext2_super_block *es =EXT2_SB (sb)->s_es;
@@ -1293,7 +1293,7 @@ static int ext2_freeze(struct super_block *sb)* consistent. */ if (atomic_long_read (&sb->s_remove_count)) { -ext2_sync_fs (sb,1 ); +ext2_sync_fs (sb,1 ,NULL );return 0 ; }/* Set EXT2_FS_VALID flag */
@@ -1316,7 +1316,7 @@ static int ext2_unfreeze(struct super_block *sb)static void ext2_write_super (struct super_block *sb) {if (!sb_rdonly (sb)) -ext2_sync_fs (sb,1 ); +ext2_sync_fs (sb,1 ,NULL ); }static int ext2_remount (struct super_block * sb,int * flags,char * data)
fs/ext4/super.c +2 -2
@@ -69,7 +69,7 @@ static void ext4_mark_recovery_complete(struct super_block *sb, struct ext4_super_block *es);static void ext4_clear_journal_err (struct super_block *sb,struct ext4_super_block *es); -static int ext4_sync_fs (struct super_block *sb,int wait); +static int ext4_sync_fs (struct super_block *sb,int wait,errseq_t *since);static int ext4_remount (struct super_block *sb,int *flags,char *data);static int ext4_statfs (struct dentry *dentry,struct kstatfs *buf);static int ext4_unfreeze (struct super_block *sb);
@@ -4855,7 +4855,7 @@ int ext4_force_commit(struct super_block *sb)return ext4_journal_force_commit (journal); } -static int ext4_sync_fs (struct super_block *sb,int wait) +static int ext4_sync_fs (struct super_block *sb,int wait,errseq_t *since) {int ret =0 , ret2;tid_t target;
fs/f2fs/f2fs.h +1 -1
@@ -2703,7 +2703,7 @@ void f2fs_inode_synced(struct inode *inode);int f2fs_enable_quota_files (struct f2fs_sb_info *sbi,bool rdonly);void f2fs_quota_off_umount (struct super_block *sb);int f2fs_commit_super (struct f2fs_sb_info *sbi,bool recover); -int f2fs_sync_fs (struct super_block *sb,int sync); +int f2fs_sync_fs (struct super_block *sb,int sync,errseq_t *since); extern __printf(3, 4) void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...); int sanity_check_ckpt(struct f2fs_sb_info *sbi);
fs/f2fs/file.c +3 -3
@@ -260,7 +260,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,if (cp_reason) {/* all the dirty node pages should be flushed for POR */ - ret =f2fs_sync_fs (inode->i_sb,1 ); + ret =f2fs_sync_fs (inode->i_sb,1 ,NULL );/* * We've secured consistency through sync_fs. Following pino
@@ -1869,7 +1869,7 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)break ;case F2FS_GOING_DOWN_METASYNC :/* do checkpoint only */ - ret =f2fs_sync_fs (sb,1 ); + ret =f2fs_sync_fs (sb,1 ,NULL );if (ret) goto out;f2fs_stop_checkpoint (sbi, false);
@@ -2097,7 +2097,7 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)if (ret)return ret; - ret =f2fs_sync_fs (sbi->sb,1 ); + ret =f2fs_sync_fs (sbi->sb,1 ,NULL );mnt_drop_write_file (filp);return ret;
fs/f2fs/namei.c +8 -8
@@ -298,7 +298,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,unlock_new_inode (inode);if (IS_DIRSYNC (dir)) -f2fs_sync_fs (sbi->sb,1 ); +f2fs_sync_fs (sbi->sb,1 ,NULL );f2fs_balance_fs (sbi, true);return 0 ;
@@ -345,7 +345,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,d_instantiate (dentry, inode);if (IS_DIRSYNC (dir)) -f2fs_sync_fs (sbi->sb,1 ); +f2fs_sync_fs (sbi->sb,1 ,NULL );return 0 ; out:clear_inode_flag (inode,FI_INC_LINK );
@@ -531,7 +531,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)f2fs_unlock_op (sbi);if (IS_DIRSYNC (dir)) -f2fs_sync_fs (sbi->sb,1 ); +f2fs_sync_fs (sbi->sb,1 ,NULL ); fail:trace_f2fs_unlink_exit (inode, err);return err;
@@ -614,7 +614,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, disk_link.len - 1);if (IS_DIRSYNC (dir)) -f2fs_sync_fs (sbi->sb,1 ); +f2fs_sync_fs (sbi->sb,1 ,NULL ); }else {f2fs_unlink (dir, dentry); }
@@ -665,7 +665,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)unlock_new_inode (inode);if (IS_DIRSYNC (dir)) -f2fs_sync_fs (sbi->sb,1 ); +f2fs_sync_fs (sbi->sb,1 ,NULL );f2fs_balance_fs (sbi, true);return 0 ;
@@ -717,7 +717,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,unlock_new_inode (inode);if (IS_DIRSYNC (dir)) -f2fs_sync_fs (sbi->sb,1 ); +f2fs_sync_fs (sbi->sb,1 ,NULL );f2fs_balance_fs (sbi, true);return 0 ;
@@ -979,7 +979,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,f2fs_unlock_op (sbi);if (IS_DIRSYNC (old_dir) ||IS_DIRSYNC (new_dir)) -f2fs_sync_fs (sbi->sb,1 ); +f2fs_sync_fs (sbi->sb,1 ,NULL );return 0 ; put_out_dir:
@@ -1132,7 +1132,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,f2fs_unlock_op (sbi);if (IS_DIRSYNC (old_dir) ||IS_DIRSYNC (new_dir)) -f2fs_sync_fs (sbi->sb,1 ); +f2fs_sync_fs (sbi->sb,1 ,NULL );return 0 ; out_new_dir:if (new_dir_entry) {
fs/f2fs/segment.c +1 -1
@@ -507,7 +507,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)sync_dirty_inodes (sbi,FILE_INODE );blk_finish_plug (&plug); } -f2fs_sync_fs (sbi->sb, true); +f2fs_sync_fs (sbi->sb,1 ,NULL );stat_inc_bg_cp_count (sbi->stat_info); } }
fs/f2fs/super.c +2 -2
@@ -1055,7 +1055,7 @@ static void f2fs_put_super(struct super_block *sb)kfree (sbi); } -int f2fs_sync_fs (struct super_block *sb,int sync) +int f2fs_sync_fs (struct super_block *sb,int sync,errseq_t *since) {struct f2fs_sb_info *sbi =F2FS_SB (sb);int err =0 , err2;
@@ -1497,7 +1497,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)set_sbi_flag (sbi,SBI_IS_DIRTY );set_sbi_flag (sbi,SBI_IS_CLOSE ); -f2fs_sync_fs (sb,1 ); +f2fs_sync_fs (sb,1 ,NULL );clear_sbi_flag (sbi,SBI_IS_CLOSE ); }
fs/gfs2/super.c +1 -1
@@ -949,7 +949,7 @@ static void gfs2_put_super(struct super_block *sb)* Flushes the log to disk. */ -static int gfs2_sync_fs (struct super_block *sb,int wait) +static int gfs2_sync_fs (struct super_block *sb,int wait,errseq_t *since) {int bderr;struct gfs2_sbd *sdp = sb->s_fs_info;
fs/hfs/super.c +1 -1
@@ -30,7 +30,7 @@ static struct kmem_cache *hfs_inode_cachep;MODULE_LICENSE ("GPL" ); -static int hfs_sync_fs (struct super_block *sb,int wait) +static int hfs_sync_fs (struct super_block *sb,int wait,errseq_t *since) {hfs_mdb_commit (sb);return __sync_blockdev (sb->s_bdev, wait);
fs/hfsplus/super.c +4 -4
@@ -172,7 +172,7 @@ static void hfsplus_evict_inode(struct inode *inode) } } -static int hfsplus_sync_fs (struct super_block *sb,int wait) +static int hfsplus_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct hfsplus_sb_info *sbi =HFSPLUS_SB (sb);struct hfsplus_vh *vhdr = sbi->s_vhdr;
@@ -254,7 +254,7 @@ static void delayed_sync_fs(struct work_struct *work) sbi->work_queued =0 ;spin_unlock (&sbi->work_lock); - err =hfsplus_sync_fs (sbi->alloc_file->i_sb,1 ); + err =hfsplus_sync_fs (sbi->alloc_file->i_sb,1 ,NULL );if (err)pr_err ("delayed sync fs err %d\n" , err); }
@@ -291,7 +291,7 @@ static void hfsplus_put_super(struct super_block *sb) vhdr->attributes |=cpu_to_be32 (HFSPLUS_VOL_UNMNT ); vhdr->attributes &=cpu_to_be32 (~HFSPLUS_VOL_INCNSTNT ); -hfsplus_sync_fs (sb,1 ); +hfsplus_sync_fs (sb,1 ,NULL ); }hfs_btree_close (sbi->attr_tree);
@@ -545,7 +545,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)be32_add_cpu (&vhdr->write_count,1 ); vhdr->attributes &=cpu_to_be32 (~HFSPLUS_VOL_UNMNT ); vhdr->attributes |=cpu_to_be32 (HFSPLUS_VOL_INCNSTNT ); -hfsplus_sync_fs (sb,1 ); +hfsplus_sync_fs (sb,1 ,NULL );if (!sbi->hidden_dir) {mutex_lock (&sbi->vh_mutex);
fs/jffs2/super.c +1 -1
@@ -96,7 +96,7 @@ static int jffs2_show_options(struct seq_file *s, struct dentry *root)return 0 ; } -static int jffs2_sync_fs (struct super_block *sb,int wait) +static int jffs2_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct jffs2_sb_info *c =JFFS2_SB_INFO (sb);
fs/jfs/super.c +1 -1
@@ -703,7 +703,7 @@ static struct dentry *jfs_do_mount(struct file_system_type *fs_type,return mount_bdev (fs_type, flags, dev_name, data, jfs_fill_super); } -static int jfs_sync_fs (struct super_block *sb,int wait) +static int jfs_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct jfs_log *log =JFS_SBI (sb)->log;
fs/nilfs2/super.c +1 -1
@@ -491,7 +491,7 @@ static void nilfs_put_super(struct super_block *sb) sb->s_fs_info =NULL ; } -static int nilfs_sync_fs (struct super_block *sb,int wait) +static int nilfs_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct the_nilfs *nilfs = sb->s_fs_info;struct nilfs_super_block **sbp;
fs/ocfs2/super.c +2 -2
@@ -115,7 +115,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb);static int ocfs2_statfs (struct dentry *dentry,struct kstatfs *buf); -static int ocfs2_sync_fs (struct super_block *sb,int wait); +static int ocfs2_sync_fs (struct super_block *sb,int wait,errseq_t *since);static int ocfs2_init_global_system_inodes (struct ocfs2_super *osb);static int ocfs2_init_local_system_inodes (struct ocfs2_super *osb);
@@ -406,7 +406,7 @@ static const struct file_operations ocfs2_osb_debug_fops = { .llseek = generic_file_llseek, }; -static int ocfs2_sync_fs (struct super_block *sb,int wait) +static int ocfs2_sync_fs (struct super_block *sb,int wait,errseq_t *since) {int status;tid_t target;
fs/overlayfs/super.c +1 -1
@@ -266,7 +266,7 @@ static void ovl_put_super(struct super_block *sb) }/* Sync real dirty inodes in upper filesystem (if it exists) */ -static int ovl_sync_fs (struct super_block *sb,int wait) +static int ovl_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct ovl_fs *ofs = sb->s_fs_info;struct super_block *upper_sb;
fs/quota/dquot.c +2 -2
@@ -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... */ -call_sync_fs (sb,1 ); +call_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). */ -call_sync_fs (sb,1 ); +call_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
fs/reiserfs/super.c +2 -2
@@ -64,7 +64,7 @@ static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)static int reiserfs_remount (struct super_block *s,int *flags,char *data);static int reiserfs_statfs (struct dentry *dentry,struct kstatfs *buf); -static int reiserfs_sync_fs (struct super_block *s,int wait) +static int reiserfs_sync_fs (struct super_block *s,int wait,errseq_t *since) {struct reiserfs_transaction_handle th;
@@ -108,7 +108,7 @@ static void flush_old_commits(struct work_struct *work) sbi->work_queued =0 ;spin_unlock (&sbi->old_work_lock); -reiserfs_sync_fs (s,1 ); +reiserfs_sync_fs (s,1 ,NULL );up_read (&s->s_umount); }
fs/sync.c +2 -2
@@ -35,7 +35,7 @@ static int __sync_filesystem(struct super_block *sb, int wait)else writeback_inodes_sb (sb,WB_REASON_SYNC ); -return call_sync_fs (sb, wait); +return call_sync_fs (sb, wait,NULL ); }/*
@@ -78,7 +78,7 @@ static void sync_fs_one_sb(struct super_block *sb, void *arg)if (sb_rdonly (sb))return ; -call_sync_fs (sb, wait); +call_sync_fs (sb, wait,NULL ); }static void fdatawrite_one_bdev (struct block_device *bdev,void *arg)
fs/sysv/inode.c +1 -1
@@ -32,7 +32,7 @@#include <asm/byteorder.h> #include "sysv.h" -static int sysv_sync_fs (struct super_block *sb,int wait) +static int sysv_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct sysv_sb_info *sbi =SYSV_SB (sb);unsigned long time =get_seconds (), old_time;
fs/ubifs/super.c +1 -1
@@ -449,7 +449,7 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)return 0 ; } -static int ubifs_sync_fs (struct super_block *sb,int wait) +static int ubifs_sync_fs (struct super_block *sb,int wait,errseq_t *since) {int i, err;struct ubifs_info *c = sb->s_fs_info;
fs/udf/super.c +2 -2
@@ -89,7 +89,7 @@ enum { UDF_MAX_LINKS = 0xffff };/* These are the "meat" - everything else is stuffing */ static int udf_fill_super (struct super_block *,void *,int );static void udf_put_super (struct super_block *); -static int udf_sync_fs (struct super_block *,int ); +static int udf_sync_fs (struct super_block *,int ,errseq_t *);static int udf_remount_fs (struct super_block *,int *,char *);static void udf_load_logicalvolint (struct super_block *,struct kernel_extent_ad ); static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *,
@@ -2345,7 +2345,7 @@ static void udf_put_super(struct super_block *sb) sb->s_fs_info =NULL ; } -static int udf_sync_fs (struct super_block *sb,int wait) +static int udf_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct udf_sb_info *sbi =UDF_SB (sb);
fs/ufs/super.c +2 -2
@@ -680,7 +680,7 @@ static void ufs_put_super_internal(struct super_block *sb)UFSD ("EXIT\n" ); } -static int ufs_sync_fs (struct super_block *sb,int wait) +static int ufs_sync_fs (struct super_block *sb,int wait,errseq_t *since) {struct ufs_sb_private_info * uspi;struct ufs_super_block_first * usb1;
@@ -720,7 +720,7 @@ static void delayed_sync_fs(struct work_struct *work) sbi->work_queued =0 ;spin_unlock (&sbi->work_lock); -ufs_sync_fs (sbi->sb,1 ); +ufs_sync_fs (sbi->sb,1 ,NULL ); }void ufs_mark_sb_dirty (struct super_block *sb)
fs/xfs/xfs_super.c +2 -1
@@ -1089,7 +1089,8 @@ xfs_free_fsname( STATIC intxfs_fs_sync_fs (struct super_block *sb, -int wait) +int wait, +errseq_t *since) {struct xfs_mount *mp =XFS_M (sb);
include/linux/fs.h +4 -3
@@ -1821,7 +1821,7 @@ struct super_operations {int (*drop_inode) (struct inode *);void (*evict_inode) (struct inode *);void (*put_super) (struct super_block *); -int (*sync_fs)(struct super_block *sb,int wait); +int (*sync_fs)(struct super_block *sb,int wait,errseq_t *since);int (*freeze_super) (struct super_block *);int (*freeze_fs) (struct super_block *);int (*thaw_super) (struct super_block *);
@@ -2499,10 +2499,11 @@ 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) +static inline int call_sync_fs (struct super_block *sb,int wait, +errseq_t *since) {if (sb->s_op->sync_fs) -return sb->s_op->sync_fs (sb, wait); +return sb->s_op->sync_fs (sb, wait, since);return __sync_blockdev (sb->s_bdev, wait); }
Signature · 1 line
2.17.0
RFC PATCH 3/11 vfs: add an errseq_t pointer to sync_filesystem
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
Allow sync_filesystem to take an errseq_t for the purposes of error reporting. This value is just passed directly to the ->sync_fs op.
--- 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 | 4 ++-- 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, 52 insertions(+), 52 deletions(-)
drivers/staging/ncpfs/inode.c +1 -1
@@ -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 ; }
fs/adfs/super.c +1 -1
@@ -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); }
fs/affs/super.c +1 -1
@@ -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 );
fs/befs/linuxvfs.c +1 -1
@@ -951,7 +951,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 ;
fs/block_dev.c +1 -1
@@ -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; }
fs/btrfs/super.c +2 -2
@@ -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) {
fs/cachefiles/interface.c +1 -1
@@ -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);
fs/cifs/cifsfs.c +1 -1
@@ -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 ; }
fs/coda/inode.c +1 -1
@@ -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 ; }
fs/cramfs/inode.c +1 -1
@@ -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 ; }
fs/debugfs/inode.c +1 -1
@@ -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;
fs/efs/super.c +1 -1
@@ -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 ; }
fs/ext2/super.c +1 -1
@@ -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;
fs/ext4/super.c +2 -2
@@ -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;
fs/fat/inode.c +1 -1
@@ -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 ;
fs/freevxfs/vxfs_super.c +1 -1
@@ -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 ; }
fs/fuse/inode.c +1 -1
@@ -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 ;
fs/gfs2/super.c +1 -1
@@ -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_spin); args.ar_commit = gt->gt_logd_secs;
fs/hfs/super.c +1 -1
@@ -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 ;
fs/hfsplus/super.c +1 -1
@@ -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 )) {
fs/hpfs/super.c +1 -1
@@ -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 ;
fs/isofs/inode.c +1 -1
@@ -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 ;
fs/jffs2/super.c +1 -1
@@ -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 ;
fs/jfs/super.c +1 -1
@@ -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 ;
fs/minix/inode.c +1 -1
@@ -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 ;
fs/nfs/super.c +1 -1
@@ -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
fs/nilfs2/super.c +1 -1
@@ -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;
fs/ntfs/super.c +1 -1
@@ -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. */
fs/ocfs2/super.c +1 -1
@@ -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)) {
fs/openpromfs/inode.c +1 -1
@@ -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 ; }
fs/overlayfs/super.c +1 -1
@@ -289,7 +289,7 @@ static int ovl_sync_fs(struct super_block *sb, int wait, errseq_t *since) 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;
fs/proc/root.c +1 -1
@@ -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); }
fs/pstore/inode.c +1 -1
@@ -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 ;
fs/qnx4/inode.c +1 -1
@@ -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 ;
fs/qnx6/inode.c +1 -1
@@ -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 ; }
fs/quota/dquot.c +1 -1
@@ -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); }
fs/reiserfs/super.c +1 -1
@@ -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
fs/romfs/super.c +1 -1
@@ -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 ; }
fs/squashfs/super.c +1 -1
@@ -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 ; }
fs/super.c +2 -2
@@ -426,7 +426,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);
@@ -1466,7 +1466,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 ;
fs/sync.c +2 -2
@@ -43,7 +43,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;
@@ -169,7 +169,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);
fs/sysv/inode.c +1 -1
@@ -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 ;
fs/tracefs/inode.c +1 -1
@@ -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;
fs/ubifs/super.c +1 -1
@@ -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 );
fs/udf/super.c +1 -1
@@ -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 ))
fs/ufs/super.c +1 -1
@@ -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;
fs/xfs/xfs_super.c +1 -1
@@ -1282,7 +1282,7 @@ xfs_fs_remount(if (error)return error; -sync_filesystem (sb); +sync_filesystem (sb,NULL );while ((p =strsep (&options,"," )) !=NULL ) {int token;
include/linux/fs.h +1 -1
@@ -2491,7 +2491,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) return false; }#endif -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;
Signature · 1 line
2.17.0
RFC PATCH 4/11 vfs: add errseq_t pointer to __sync_filesystem
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
...and pass that to the sync_fs operation. Also, have __sync_filesystem return the error from sync_fs (if there is one).
--- fs/sync.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
fs/sync.c +6 -4
@@ -28,14 +28,16 @@* 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) { +int ret =0 ; +if (wait)sync_inodes_sb (sb);else writeback_inodes_sb (sb,WB_REASON_SYNC ); -return call_sync_fs (sb, wait,NULL ); +return call_sync_fs (sb, wait, since); }/*
@@ -59,10 +61,10 @@ int sync_filesystem(struct super_block *sb, errseq_t *since)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);
Signature · 1 line
2.17.0
RFC PATCH 5/11 fs: track per-sb writeback errors and report them to syncfs
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
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 may be more efficient, 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 return an error. syncfs only returns an error if __sync_blockdev fails.
It would be better if it 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 implements a suggestion from Willy to remedy this. It adds a new errseq_t to struct super_block, and has mapping_set_error also record writeback errors there.
To report errors recorded there, 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.
As an alternative, this patch only has syncfs report errors recorded in s_wb_err when the file has been opened with O_PATH. Any file opened with O_PATH will not have its fsync field defined in its file_operations so we can be sure that nothing else will be using its f_wb_err field.
Note that calling syncfs on an O_PATH descriptor today will return -EBADF, so this scheme gives userland a way to tell whether this mechanism will work at runtime.
--- fs/open.c | 6 +++--- fs/sync.c | 9 +++++++-- include/linux/fs.h | 3 +++ include/linux/pagemap.h | 5 ++++- 4 files changed, 17 insertions(+), 6 deletions(-)
fs/open.c +3 -3
@@ -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))
fs/sync.c +7 -2
@@ -162,16 +162,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);
include/linux/fs.h +3 -0
@@ -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;
include/linux/pagemap.h +4 -1
@@ -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 )
Signature · 1 line
2.17.0
RFC PATCH 6/11 buffer: record blockdev write errors in super_block that backs them
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
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.
Change mark_buffer_write_io_error to record the error in the corresponding super_block when a writeback error occurs and the block device contains a mounted superblock.
--- fs/buffer.c | 2 ++ 1 file changed, 2 insertions(+)
fs/buffer.c +2 -0
@@ -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);
Signature · 1 line
2.17.0
RFC PATCH 7/11 ext4: have sync_fs op report writeback errors when passed a since pointer
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
When ext4_sync_fs gets a non-NULL since pointer, use it to report errors vs. the errseq_t in the super_block. This allows us to properly report an error to sync_fs when any inode has failed writeback since we last checked for it.
--- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+)
fs/ext4/super.c +2 -0
@@ -4898,6 +4898,8 @@ static int ext4_sync_fs(struct super_block *sb, int wait, errseq_t *since) } out: ret2 =__sync_blockdev (sb->s_bdev, wait); +if (since) + ret2 =errseq_check_and_advance (&sb->s_wb_err, since);return ret ? ret : ret2; }
Signature · 1 line
2.17.0
Matthew Wilcox
maintainerRe: [RFC PATCH 07/11] ext4: have sync_fs op report writeback errors when passed a since pointer
Quoted 17 lines · Jeff Layton
From: Jeff Layton <[email protected]>
When
ext4_sync_fsgets a non-NULL since pointer, use it to report errors vs. theerrseq_tin thesuper_block. This allows us to properly report an error tosync_fswhen any inode has failed writeback since we last checked for it.Signed-off-by Jeff Layton <[email protected]>--- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+)fs/ext4/super.c +0
-0
fs/ext4/super.c static int ext4_sync_fs(struct super_block *sb, int wait, errseq_t *since) · line 4904
Quoted 7 lines
fs/ext4/super.c +2
-0@@ -4898,6 +4898,8 @@ static int ext4_sync_fs(struct super_block *sb, int wait, errseq_t *since) } out: ret2 =__sync_blockdev (sb->s_bdev, wait); +if (since) + ret2 =errseq_check_and_advance (&sb->s_wb_err, since);return ret ? ret : ret2; }
This is inconsistent with the ext2 and xfs implementations ...
I'm worried this is too much complexity to push down to the filesystems. When should errors get reported through the return value; when should they be reported through the errseq_t?
Can we hide all of this? Maybe ext4 could do:
errseq_set(&sb->s_wb_err, __sync_blockdev(sb->s_bdev, wait)); return ret;
(we'd need to make calling errseq_set(x, 0) be a no-op instead of an error)
and then the caller is the one who takes care of calling errseq_check_and_advance() so we don't have to pass 'since' into each filesystem.
Re: [RFC PATCH 07/11] ext4: have sync_fs op report writeback errors when passed a since pointer
Quoted 28 lines · Matthew Wilcox
Quoted 17 lines · Jeff Layton
From: Jeff Layton <[email protected]>
When
ext4_sync_fsgets a non-NULL since pointer, use it to report errors vs. theerrseq_tin thesuper_block. This allows us to properly report an error tosync_fswhen any inode has failed writeback since we last checked for it.Signed-off-by Jeff Layton <[email protected]>--- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+)fs/ext4/super.c +0
-0fs/ext4/super.c static int ext4_sync_fs(struct super_block *sb, int wait, errseq_t *since) · line 4904
Quoted 7 lines
fs/ext4/super.c +2
-0@@ -4898,6 +4898,8 @@ static int ext4_sync_fs(struct super_block *sb, int wait, errseq_t *since) } out: ret2 =__sync_blockdev (sb->s_bdev, wait); +if (since) + ret2 =errseq_check_and_advance (&sb->s_wb_err, since);return ret ? ret : ret2; }This is inconsistent with the ext2 and xfs implementations ...
Quoted 9 lines
I'm worried this is too much complexity to push down to the filesystems. When should errors get reported through the return value; when should they be reported through the
errseq_t?Can we hide all of this? Maybe ext4 could do:
errseq_set(&sb->s_wb_err, __sync_blockdev(sb->s_bdev, wait)); return ret;
I'm not sure I understand what you intend here. If __sync_blockdev fails, then the error should have already been marked in sb->s_wb_err (via patch #6). We wouldn't want to record that again at syncfs time. Note that __sync_blockdev will return errors based on the legacy AS_EIO/AS_ENOSPC flags.
We really do need to record it in the superblock as soon as possible after an error occurs. If we want to allow userland to eventually be able to scrape this value out of the kernel (as we discussed at LSF/MM) then we can't assume that it'll be doing any sort of syncfs call beforehand.
The main reason to push this down into the filesystems is to allow them control over whether to report errors at syncfs time via the superblock errseq_t or not. If we don't really care about allowing this to be an opt-in thing, then we could just take the patch that I sent on April 17th:
[PATCH] fs: track per-sb writeback errors and report them to syncfs
We'd also want patch #6 from this series, I think, but that's more or less enough to implement this over all filesystems, assuming they use mapping_set_error to record writeback errors. I'm fine with either approach.
Quoted 5 lines
(we'd need to make calling
errseq_set(x, 0)be a no-op instead of an error)and then the caller is the one who takes care of calling
errseq_check_and_advance()so we don't have to pass 'since' into each filesystem.
RFC PATCH 8/11 xfs: have sync_fs op report writeback errors when passed a since pointer
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
--- fs/xfs/xfs_super.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
fs/xfs/xfs_super.c +8 -1
@@ -1092,6 +1092,7 @@ xfs_fs_sync_fs(int wait, errseq_t *since) { + int ret;struct xfs_mount *mp =XFS_M (sb);/*
@@ -1110,7 +1111,13 @@ xfs_fs_sync_fs(flush_delayed_work (&mp->m_log->l_work); } out: -return __sync_blockdev (sb->s_bdev, 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; }STATIC int
Signature · 1 line
2.17.0
Re: [RFC PATCH 08/11] xfs: have sync_fs op report writeback errors when passed a since pointer
Quoted 20 lines · Jeff Layton
From: Jeff Layton <[email protected]>
Signed-off-by Jeff Layton <[email protected]>--- fs/xfs/xfs_super.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)fs/xfs/xfs_super.c +1
-0@@ -1092,6 +1092,7 @@ xfs_fs_sync_fs(int wait, errseq_t *since) { + int ret;struct xfs_mount *mp =XFS_M (sb);/*
fs/xfs/xfs_super.c xfs_fs_sync_fs( · line 1113
Quoted 4 lines
fs/xfs/xfs_super.c +0
-1@@ -1110,7 +1111,13 @@ xfs_fs_sync_fs(flush_delayed_work (&mp->m_log->l_work); } out: -return __sync_blockdev (sb->s_bdev, wait);
Where did this come from? XFS doesn't use the underlying blockdev address space, so this does nothing at all and should not be here.
fs/xfs/xfs_super.c xfs_fs_sync_fs( · line 1121
Quoted 8 lines
fs/xfs/xfs_super.c +7
-0+ 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; }
So to return errors correctly, xfs_fs_sync_fs() needs to capture errors from the log force (i.e. metadata errors such as filesystem shutdowns, journal IO errors, etc), then check for pending data IO errors. i.e:
STATIC int
xfs_fs_sync_fs(
struct super_block *sb,
int wait)
{
struct xfs_mount *mp = XFS_M(sb);
+ int err;
/*
* Doing anything during the async pass would be counterproductive. */
if (!wait)
return 0;
- xfs_log_force(mp, XFS_LOG_SYNC);
+ err = xfs_log_force(mp, XFS_LOG_SYNC);
+ if (err)
+ return err;
+
if (laptop_mode) {
/*
* The disk must be active because we're syncing.
* We schedule log work now (now that the disk is
* active) instead of later (when it might not be). */
flush_delayed_work(&mp->m_log->l_work);
}
- return 0
+ return errseq_check_and_advance(&sb->s_wb_err, since);
}
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Re: [RFC PATCH 08/11] xfs: have sync_fs op report writeback errors when passed a since pointer
Quoted 19 lines · Dave Chinner
Quoted 18 lines · Jeff Layton
From: Jeff Layton <[email protected]>
Signed-off-by Jeff Layton <[email protected]>--- fs/xfs/xfs_super.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)fs/xfs/xfs_super.c +1
-0@@ -1092,6 +1092,7 @@ xfs_fs_sync_fs(int wait, errseq_t *since) { + int ret;struct xfs_mount *mp =XFS_M (sb);
Quoted 10 lines
fs/xfs/xfs_super.c xfs_fs_sync_fs( · line 1113
Quoted 6 lines
fs/xfs/xfs_super.c +0
-1/* @@ -1110,7 +1111,13 @@ xfs_fs_sync_fs(flush_delayed_work (&mp->m_log->l_work); } out: -return __sync_blockdev (sb->s_bdev, wait);Where did this come from? XFS doesn't use the underlying blockdev address space, so this does nothing at all and should not be here.
An earlier patch that pushed this down into the sync_fs routines. We call this today for all filesystems, and I wasn't sure about xfs.
Christoph already pointed out that it's not needed so it's removed from my current branch.
Quoted 37 lines
fs/xfs/xfs_super.c xfs_fs_sync_fs( · line 1121
Quoted 8 lines
fs/xfs/xfs_super.c +7
-0+ 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; }So to return errors correctly,
xfs_fs_sync_fs()needs to capture errors from the log force (i.e. metadata errors such as filesystem shutdowns, journal IO errors, etc), then check for pending data IO errors. i.e:STATIC int
xfs_fs_sync_fs((quoted diff) +5
-1struct super_block *sb, int wait) { struct xfs_mount *mp = XFS_M(sb); + int err; /* * Doing anything during the async pass would be counterproductive. */ if (!wait) return 0; - xfs_log_force(mp, XFS_LOG_SYNC); + err = xfs_log_force(mp, XFS_LOG_SYNC); + if (err) + return err; + if (laptop_mode) { /*
Review
Quoted 10 lines
(quoted diff) +1
-1* The disk must be active because we're syncing. * We schedule log work now (now that the disk is * active) instead of later (when it might not be). */ flush_delayed_work(&mp->m_log->l_work); } - return 0 + return errseq_check_and_advance(&sb->s_wb_err, since); }
Ok, sounds good. I'll fix that too.
FWIW, we'll actually want to advance the cursor even if xfs_log_force returns an error to ensure that we don't end up reporting errors twice, but that's simple enough to do.
Thanks!
Signature · 1 line
Jeff Layton <[email protected]>
RFC PATCH 9/11 btrfs: have sync_fs op report writeback errors when passed a since pointer
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
--- fs/btrfs/super.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
fs/btrfs/super.c +16 -6
@@ -1231,12 +1231,13 @@ int btrfs_sync_fs(struct super_block *sb, int wait, errseq_t *since)struct btrfs_trans_handle *trans;struct btrfs_fs_info *fs_info =btrfs_sb (sb);struct btrfs_root *root = fs_info->tree_root; +int ret =0 ;trace_btrfs_sync_fs (fs_info, wait);if (!wait) {filemap_flush (fs_info->btree_inode->i_mapping); -return 0 ; + goto out; }btrfs_wait_ordered_roots (fs_info,U64_MAX ,0 , (u64)-1 );
@@ -1250,7 +1251,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait, errseq_t *since)* that need to go through commit */ if (fs_info->pending_changes ==0 ) -return 0 ; + goto out;/* * A non-blocking test if the fs is frozen. We must not * start a new transaction here otherwise a deadlock
@@ -1260,13 +1261,22 @@ int btrfs_sync_fs(struct super_block *sb, int wait, errseq_t *since)if (sb_start_write_trylock (sb))sb_end_write (sb);else -return 0 ; + goto out; trans =btrfs_start_transaction (root,0 ); } -if (IS_ERR (trans)) -return PTR_ERR (trans); +if (IS_ERR (trans)) { + ret =PTR_ERR (trans); + goto out; + } } -return btrfs_commit_transaction (trans); + ret =btrfs_commit_transaction (trans); +out: +if (since) { +int ret2 =errseq_check_and_advance (&sb->s_wb_err, since); +if (ret ==0 ) + ret = ret2; + } +return ret; }static int btrfs_show_options (struct seq_file *seq,struct dentry *dentry)
Signature · 1 line
2.17.0
RFC PATCH 10/11 ext2: have sync_fs op report writeback errors when passed a since pointer
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
--- fs/ext2/super.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
fs/ext2/super.c +8 -1
@@ -1264,6 +1264,7 @@ void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es,*/ static int ext2_sync_fs (struct super_block *sb,int wait,errseq_t *since) { +int ret;struct ext2_sb_info *sbi =EXT2_SB (sb);struct ext2_super_block *es =EXT2_SB (sb)->s_es;
@@ -1280,7 +1281,13 @@ static int ext2_sync_fs(struct super_block *sb, int wait, errseq_t *since) }spin_unlock (&sbi->s_lock);ext2_sync_super (sb, es, wait); -return __sync_blockdev (sb->s_bdev, 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; }static int ext2_freeze (struct super_block *sb)
Signature · 1 line
2.17.0
RFC PATCH 11/11 vfs: have call_sync_fs op report writeback errors when passed a since pointer
In reply to Jeff LaytonFrom: Jeff Layton <[email protected]>
...on filesystems that don't define a ->sync_fs operation.
--- include/linux/fs.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
NB: I'm not sure this is something we really want to do. It's a bit cavalier and some filesystems might not like it if they are tracking errors in other ways. An alternative here is to add a simple_sync_fs helper that does this and add that to a whole swath of different fs'.
include/linux/fs.h +10 -1
@@ -2505,9 +2505,18 @@ extern const struct file_operations def_chr_fops;static inline int call_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, since); -return __sync_blockdev (sb->s_bdev, 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; }#ifdef CONFIG_BLOCK
Signature · 1 line
2.17.0