@@ -744,12 +744,10 @@ 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 | FMODE_OPENED;
f->f_op = &empty_fops;
+ f->f_wb_err = errseq_sample(&f->f_path.dentry->d_sb->s_wb_err);
return 0;
}
@@ -759,6 +757,8 @@ static int do_dentry_open(struct file *f,
goto cleanup_file;
}
+ 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))
@@ -159,7 +159,7 @@ void emergency_sync(void)
*/
SYSCALL_DEFINE1(syncfs, int, fd)
{
- struct fd f = fdget(fd);
+ struct fd f = fdget_raw(fd);
struct super_block *sb;
int ret;
@@ -171,6 +171,13 @@ SYSCALL_DEFINE1(syncfs, int, fd)
ret = sync_filesystem(sb);
up_read(&sb->s_umount);
+ if (f.file->f_flags & O_PATH) {
+ int ret2 = errseq_check_and_advance(&sb->s_wb_err,
+ &f.file->f_wb_err);
+ if (ret == 0)
+ ret = ret2;
+ }
+
fdput(f);
return ret;
}
@@ -1514,6 +1514,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;
@@ -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)