[v7,19/22] ext4: add more robust reporting of metadata writeback errors
diff mbox

Message ID 20170616193427.13955-20-jlayton@redhat.com
State New
Headers show

Commit Message

Jeff Layton June 16, 2017, 7:34 p.m. UTC
ext4 uses the blockdev mapping for tracking metadata stored in the
pagecache. Sample its wb_err when opening a file and store that in
the f_md_wb_err field.

Change ext4_sync_file to check for data errors first, and then check the
blockdev mapping for metadata errors afterward.

Note that because metadata writeback errors are only tracked on a
per-device level, this does mean that we'll end up reporting an error on
all open file descriptors when there is a metadata writeback failure.
That's not ideal, but we can possibly improve upon it in the future.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/ext4/dir.c   |  8 ++++++--
 fs/ext4/file.c  |  5 ++++-
 fs/ext4/fsync.c | 13 +++++++++++++
 3 files changed, 23 insertions(+), 3 deletions(-)

Patch
diff mbox

diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index e8b365000d73..6bbb19510f74 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -611,9 +611,13 @@  static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
 
 static int ext4_dir_open(struct inode * inode, struct file * filp)
 {
+	int ret = 0;
+
 	if (ext4_encrypted_inode(inode))
-		return fscrypt_get_encryption_info(inode) ? -EACCES : 0;
-	return 0;
+		ret = fscrypt_get_encryption_info(inode) ? -EACCES : 0;
+	if (!ret)
+		filp->f_md_wb_err = filemap_sample_wb_err(inode->i_sb->s_bdev->bd_inode->i_mapping);
+	return ret;
 }
 
 static int ext4_release_dir(struct inode *inode, struct file *filp)
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 02ce7e7bbdf5..6e505269132c 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -435,7 +435,10 @@  static int ext4_file_open(struct inode * inode, struct file * filp)
 		if (ret < 0)
 			return ret;
 	}
-	return dquot_file_open(inode, filp);
+	ret = dquot_file_open(inode, filp);
+	if (!ret)
+		filp->f_md_wb_err = filemap_sample_wb_err(sb->s_bdev->bd_inode->i_mapping);
+	return ret;
 }
 
 /*
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 03d6259d8662..8ea8ec517da5 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -161,10 +161,23 @@  int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 			ret = err;
 	}
 out:
+	/*
+	 * Was there a metadata writeback error since last fsync?
+	 *
+	 * FIXME: ext4 tracks metadata with a whole-block device mapping. If
+	 * there is any sort of metadata writeback error, we'll report an
+	 * error on all open fds, even ones not associated with this inode.
+	 */
+	err = filemap_report_md_wb_err(file,
+				inode->i_sb->s_bdev->bd_inode->i_mapping);
+	if (!ret)
+		ret = err;
+
 	/* Was there a writeback error of the data since last fsync? */
 	err = filemap_report_wb_err(file);
 	if (!ret)
 		ret = err;
+
 	trace_ext4_sync_file_exit(inode, ret);
 	return ret;
 }