@@ -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))
@@ -159,18 +159,25 @@ 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;
+ int ret, wberr;
- if (!f.file)
+ if (!f.file) {
+ printk("fd %d is NULL!\n", fd);
return -EBADF;
+ }
sb = f.file->f_path.dentry->d_sb;
down_read(&sb->s_umount);
ret = sync_filesystem(sb);
up_read(&sb->s_umount);
+ if (f.file->f_flags & O_PATH) {
+ wberr = errseq_check_and_advance(&sb->s_wb_err, &f.file->f_wb_err);
+ if (!ret)
+ ret = wberr;
+ }
fdput(f);
return ret;
}
@@ -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;
@@ -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)