projects/linux·commit ff68e5f5

Merge tag 'vfs-7.3-rc1.sync' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

ff68e5f5 · Linus Torvalds <[email protected]> · 2026-08-17 14:21:00 -07:00

Pull vfs writeback updates from Christian Brauner:
 "This makes sync_inode_metadata() and writeback_single_inode() persist
  not only the inode but all metadata associated with it.

  A new .sync_inode_metadata superblock operation is called from
  __writeback_single_inode(). Alongside it a new I_METADATA_WRITEBACK
  state flag is added.

  Filesystems no longer need their own mmb_fsync() implementations and
  can just use simple_fsync(). All metadata is now written for IS_SYNC
  and IS_DIRSYNC inodes. Races where several fsyncs raced and mmb_sync()
  could return before all buffers were really persisted are fixed since
  I_SYNC now serializes properly.

  The I_METADATA_WRITEBACK scheme also fixes the case where a
  WB_SYNC_NONE writeback landing between write(2) and fsync(2) left
  fsync(2) failing to persist the inode. That problem is not specific to
  filesystems using the generic metadata bh tracking, and the ones that
  do not are left alone.

  ext2, udf, bfs, minix, fat and ext4 in nojournal mode have their data
  integrity writeout fixed and are converted. affs drops metadata bh
  tracking and mmb_fsync() is removed.

  A few other fixes came out of this:

   - a UAF in mark_buffer_write_io_error()

   - missed inode writeback when racing with __writeback_single_inode()

   - ext4 allocating the mapping_metadata_bhs struct on demand

   - three fat fixes: a lost inode update in do_msdos_rename() with
     DIRSYNC, inode buffer write errors not propagating out of
     fat_sync_inode_metadata() and directory entries not being
     persisted on fsync(2) of the root directory"

* tag 'vfs-7.3-rc1.sync' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (24 commits)
  writeback: Export __inode_attach_wb()
  fat: Fix persisting directory entries on fsync(2) of the root directory
  fat: Propagate inode buffer write errors from fat_sync_inode_metadata()
  fat: Fix lost inode update in do_msdos_rename() with DIRSYNC
  vfs: Remove mmb_fsync()
  fat: Replace fat_sync_inode() with sync_inode_metadata()
  fat: Fix missed inode writeback during fsync(2)
  ext4: Fix data integrity writeout issues in nojournal mode
  minix: Fix data integrity writeout issues
  bfs: Fix data integrity writeout issues
  udf: Fold udf_update_inode() into udf_write_inode()
  udf: Use sync_inode_metadata() in udf_evict_inode()
  udf: Drop udf_sync_inode()
  udf: Use sync_inode_metadata() to writeout IS_SYNC inode
  udf: Fix data integrity writeout issues
  ext2: Fix data integrity writeout issues
  ext2: Avoid unnecessary inode buffer writeback for sync(2)
  ext2: Drop __ext2_write_inode()
  ext2: Fix lost inode updates for IS_SYNC inodes
  fs: Provide way for filesystem to wait for metadata writeback
  ...
Commit
ff68e5f557f69a08fdcfa4ce8b1b809d63bd4f45
Parents
1781f0b3 · 974d0be0

Merge commit. Changes below are compared with the first parent: 1781f0b3.

Changes

41 files changed · +409 −362

FileStatusAddDelContent
fs/affs/affs.hmodified+0−2View file
fs/affs/amigaffs.cmodified+6−6View file
fs/affs/file.cmodified+11−14View file
fs/affs/inode.cmodified+5−8View file
fs/affs/namei.cmodified+4−5View file
fs/affs/super.cmodified+0−1View file
fs/bfs/dir.cmodified+1−8View file
fs/bfs/inode.cmodified+24−6View file
fs/buffer.cmodified+8−75View file
fs/ext2/dir.cmodified+1−1View file
fs/ext2/ext2.hmodified+1−2View file
fs/ext2/file.cmodified+1−16View file
fs/ext2/inode.cmodified+30−19View file
fs/ext2/super.cmodified+1−0View file
fs/ext2/xattr.cmodified+2−2View file
fs/ext4/ext4.hmodified+13−1View file
fs/ext4/ext4_jbd2.cmodified+21−4View file
fs/ext4/fsync.cmodified+5−19View file
fs/ext4/inode.cmodified+68−34View file
fs/ext4/super.cmodified+12−4View file
fs/fat/dir.cmodified+3−3View file
fs/fat/fat.hmodified+0−1View file
fs/fat/file.cmodified+4−5View file
fs/fat/inode.cmodified+46−17View file
fs/fat/misc.cmodified+4−3View file
fs/fat/namei_msdos.cmodified+16−17View file
fs/fat/namei_vfat.cmodified+10−10View file
fs/fs-writeback.cmodified+27−7View file
fs/libfs.cmodified+5−2View file
fs/minix/dir.cmodified+1−1View file
fs/minix/file.cmodified+1−8View file
fs/minix/inode.cmodified+35−17View file
fs/minix/minix.hmodified+0−1View file
fs/udf/dir.cmodified+1−1View file
fs/udf/file.cmodified+3−8View file
fs/udf/inode.cmodified+26−28View file
fs/udf/super.cmodified+1−0View file
fs/udf/udfdecl.hmodified+1−1View file
include/linux/buffer_head.hmodified+0−4View file
include/linux/fs.hmodified+9−1View file
include/linux/fs/super_types.hmodified+2−0View file

Only the first 600 diff lines are shown. Download the complete patch.

fs/affs/affs.h

View file
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index d6b3393..d1c506c 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -44,7 +44,6 @@ struct affs_inode_info {
struct mutex i_link_lock; /* Protects internal inode access. */
struct mutex i_ext_lock; /* Protects internal inode access. */
#define i_hash_lock i_ext_lock
- struct mapping_metadata_bhs i_metadata_bhs;
u32 i_blkcnt; /* block count */
u32 i_extcnt; /* extended block count */
u32 *i_lc; /* linear cache of extended blocks */
@@ -152,7 +151,6 @@ extern bool affs_nofilenametruncate(const struct dentry *dentry);
extern int affs_check_name(const unsigned char *name, int len,
bool notruncate);
extern int affs_copy_name(unsigned char *bstr, struct dentry *dentry);
-struct mapping_metadata_bhs *affs_get_metadata_bhs(struct inode *inode);
/* bitmap. c */

fs/affs/amigaffs.c

View file
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index bed4fc8..6cc0fc9 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -57,7 +57,7 @@ affs_insert_hash(struct inode *dir, struct buffer_head *bh)
AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);
affs_adjust_checksum(dir_bh, ino);
- mmb_mark_buffer_dirty(dir_bh, &AFFS_I(dir)->i_metadata_bhs);
+ mark_buffer_dirty(dir_bh);
affs_brelse(dir_bh);
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
@@ -100,7 +100,7 @@ affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
else
AFFS_TAIL(sb, bh)->hash_chain = ino;
affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
- mmb_mark_buffer_dirty(bh, &AFFS_I(dir)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
AFFS_TAIL(sb, rem_bh)->parent = 0;
retval = 0;
break;
@@ -180,7 +180,7 @@ affs_remove_link(struct dentry *dentry)
affs_unlock_dir(dir);
goto done;
}
- mmb_mark_buffer_dirty(link_bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(link_bh);
memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
retval = affs_insert_hash(dir, bh);
@@ -188,7 +188,7 @@ affs_remove_link(struct dentry *dentry)
affs_unlock_dir(dir);
goto done;
}
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
affs_unlock_dir(dir);
iput(dir);
@@ -203,7 +203,7 @@ affs_remove_link(struct dentry *dentry)
__be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain;
AFFS_TAIL(sb, bh)->link_chain = ino2;
affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
retval = 0;
/* Fix the link count, if bh is a normal header block without links */
switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
@@ -306,7 +306,7 @@ affs_remove_header(struct dentry *dentry)
retval = affs_remove_hash(dir, bh);
if (retval)
goto done_unlock;
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
affs_unlock_dir(dir);

fs/affs/file.c

View file
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 144b174..23e088a 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -140,14 +140,14 @@ affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext)
AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino);
affs_fix_checksum(sb, new_bh);
- mmb_mark_buffer_dirty(new_bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(new_bh);
tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
if (tmp)
affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp);
AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr);
affs_adjust_checksum(bh, blocknr - tmp);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
AFFS_I(inode)->i_extcnt++;
mark_inode_dirty(inode);
@@ -581,7 +581,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
memset(AFFS_DATA(bh) + boff, 0, tmp);
be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);
affs_fix_checksum(sb, bh);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
size += tmp;
bidx++;
} else if (bidx) {
@@ -603,7 +603,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
affs_fix_checksum(sb, bh);
bh->b_state &= ~(1UL << BH_New);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
if (prev_bh) {
u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
@@ -613,8 +613,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
bidx, tmp_next);
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
- mmb_mark_buffer_dirty(prev_bh,
- &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(prev_bh);
affs_brelse(prev_bh);
}
size += bsize;
@@ -733,7 +732,7 @@ static int affs_write_end_ofs(const struct kiocb *iocb,
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(
max(boff + tmp, be32_to_cpu(AFFS_DATA_HEAD(bh)->size)));
affs_fix_checksum(sb, bh);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
written += tmp;
from += tmp;
bidx++;
@@ -766,13 +765,12 @@ static int affs_write_end_ofs(const struct kiocb *iocb,
bidx, tmp_next);
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
- mmb_mark_buffer_dirty(prev_bh,
- &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(prev_bh);
}
}
affs_brelse(prev_bh);
affs_fix_checksum(sb, bh);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
written += bsize;
from += bsize;
bidx++;
@@ -801,14 +799,13 @@ static int affs_write_end_ofs(const struct kiocb *iocb,
bidx, tmp_next);
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
- mmb_mark_buffer_dirty(prev_bh,
- &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(prev_bh);
}
} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
affs_brelse(prev_bh);
affs_fix_checksum(sb, bh);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
written += tmp;
from += tmp;
bidx++;
@@ -945,7 +942,7 @@ affs_truncate(struct inode *inode)
}
AFFS_TAIL(sb, ext_bh)->extension = 0;
affs_fix_checksum(sb, ext_bh);
- mmb_mark_buffer_dirty(ext_bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(ext_bh);
affs_brelse(ext_bh);
if (inode->i_size) {

fs/affs/inode.c

View file
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 5dd1b01..d4a3f38 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -206,7 +206,7 @@ affs_write_inode(struct inode *inode, struct writeback_control *wbc)
}
}
affs_fix_checksum(sb, bh);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
affs_free_prealloc(inode);
return 0;
@@ -266,11 +266,8 @@ affs_evict_inode(struct inode *inode)
if (!inode->i_nlink) {
inode->i_size = 0;
affs_truncate(inode);
- } else {
- mmb_sync(&AFFS_I(inode)->i_metadata_bhs);
}
- mmb_invalidate(&AFFS_I(inode)->i_metadata_bhs);
clear_inode(inode);
affs_free_prealloc(inode);
cache_page = (unsigned long)AFFS_I(inode)->i_lc;
@@ -305,7 +302,7 @@ affs_new_inode(struct inode *dir)
bh = affs_getzeroblk(sb, block);
if (!bh)
goto err_bh;
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
inode->i_uid = current_fsuid();
@@ -393,17 +390,17 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
AFFS_TAIL(sb, bh)->link_chain = chain;
AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
- mmb_mark_buffer_dirty(inode_bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(inode_bh);
set_nlink(inode, 2);
ihold(inode);
}
affs_fix_checksum(sb, bh);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
dentry->d_fsdata = (void *)(long)bh->b_blocknr;
affs_lock_dir(dir);
retval = affs_insert_hash(dir, bh);
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
affs_unlock_dir(dir);
affs_unlock_link(inode);

fs/affs/namei.c

View file
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 5311828..6cb52ef 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -373,7 +373,7 @@ affs_symlink(struct mnt_idmap *idmap, struct inode *dir,
}
*p = 0;
inode->i_size = i + 1;
- mmb_mark_buffer_dirty(bh, &AFFS_I(inode)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
mark_inode_dirty(inode);
@@ -443,8 +443,7 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* TODO: move it back to old_dir, if error? */
done:
- mmb_mark_buffer_dirty(bh,
- &AFFS_I(retval ? old_dir : new_dir)->i_metadata_bhs);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
return retval;
}
@@ -497,8 +496,8 @@ affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
retval = affs_insert_hash(old_dir, bh_new);
affs_unlock_dir(old_dir);
done:
- mmb_mark_buffer_dirty(bh_old, &AFFS_I(new_dir)->i_metadata_bhs);
- mmb_mark_buffer_dirty(bh_new, &AFFS_I(old_dir)->i_metadata_bhs);
+ mark_buffer_dirty(bh_old);
+ mark_buffer_dirty(bh_new);
affs_brelse(bh_old);
affs_brelse(bh_new);
return retval;

fs/affs/super.c

View file
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 4f331f7..ed8225b 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -108,7 +108,6 @@ static struct inode *affs_alloc_inode(struct super_block *sb)
i->i_lc = NULL;
i->i_ext_bh = NULL;
i->i_pa_cnt = 0;
- mmb_init(&i->i_metadata_bhs, &i->vfs_inode.i_data);
return &i->vfs_inode;
}

fs/bfs/dir.c

View file
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 4c3b4db..91a4871 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -68,17 +68,10 @@ static int bfs_readdir(struct file *f, struct dir_context *ctx)
return 0;
}
-static int bfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
-{
- return mmb_fsync(file,
- &BFS_I(file->f_mapping->host)->i_metadata_bhs,
- start, end, datasync);
-}
-
const struct file_operations bfs_dir_operations = {
.read = generic_read_dir,
.iterate_shared = bfs_readdir,
- .fsync = bfs_fsync,
+ .fsync = simple_fsync,
.llseek = generic_file_llseek,
};

fs/bfs/inode.c

View file
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index e41efdd..06e3a84 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -136,7 +136,6 @@ static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)
unsigned long i_sblock;
struct bfs_inode *di;
struct buffer_head *bh;
- int err = 0;
dprintf("ino=%08x\n", ino);
@@ -165,13 +164,31 @@ static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)
di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1);
mark_buffer_dirty(bh);
- if (wbc->sync_mode == WB_SYNC_ALL) {
- sync_dirty_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh))
- err = -EIO;
- }
brelse(bh);
mutex_unlock(&info->bfs_lock);
+ set_inode_metadata_writeback(inode);
+ return 0;
+}
+
+static int bfs_sync_inode_metadata(struct inode *inode,
+ struct writeback_control *wbc)
+{
+ int err = 0;
+ struct bfs_inode *di;
+ struct buffer_head *bh;
+
+ di = find_inode(inode->i_sb, (u16)inode->i_ino, &bh);
+ if (IS_ERR(di))
+ return PTR_ERR(di);
+
+ sync_dirty_buffer(bh);
+ if (buffer_write_io_error(bh)) {
+ err = -EIO;
+ goto out;
+ }
+ err = mmb_sync(&BFS_I(inode)->i_metadata_bhs);
+out:
+ brelse(bh);
return err;
}
@@ -302,6 +319,7 @@ static const struct super_operations bfs_sops = {
.alloc_inode = bfs_alloc_inode,
.free_inode = bfs_free_inode,
.write_inode = bfs_write_inode,
+ .sync_inode_metadata = bfs_sync_inode_metadata,
.evict_inode = bfs_evict_inode,
.put_super = bfs_put_super,
.statfs = bfs_statfs,

fs/buffer.c

View file
diff --git a/fs/buffer.c b/fs/buffer.c
index 9af5f06..be8b57a 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -628,79 +628,6 @@ int mmb_sync(struct mapping_metadata_bhs *mmb)
}
EXPORT_SYMBOL(mmb_sync);
-/**
- * mmb_fsync_noflush - fsync implementation for simple filesystems with
- * metadata buffers list
- *
- * @file: file to synchronize
- * @mmb: list of metadata bhs to flush
- * @start: start offset in bytes
- * @end: end offset in bytes (inclusive)
- * @datasync: only synchronize essential metadata if true
- *
- * This is an implementation of the fsync method for simple filesystems which
- * track all non-inode metadata in the buffers list hanging off the @mmb
- * structure.
- */
-int mmb_fsync_noflush(struct file *file, struct mapping_metadata_bhs *mmb,
- loff_t start, loff_t end, bool datasync)
-{
- struct inode *inode = file->f_mapping->host;
- int err;
- int ret = 0;
-
- err = file_write_and_wait_range(file, start, end);
- if (err)
- return err;
-
- if (mmb)
- ret = mmb_sync(mmb);
- if (!(inode_state_read_once(inode) & I_DIRTY_ALL))
- goto out;
- if (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC))
- goto out;
-
- err = sync_inode_metadata(inode, 1);
- if (ret == 0)
- ret = err;
-
-out:
- /* check and advance again to catch errors after syncing out buffers */
- err = file_check_and_advance_wb_err(file);
- if (ret == 0)
- ret = err;
- return ret;
-}
-EXPORT_SYMBOL(mmb_fsync_noflush);
-
-/**
- * mmb_fsync - fsync implementation for simple filesystems with metadata
- * buffers list
- *
- * @file: file to synchronize
- * @mmb: list of metadata bhs to flush
- * @start: start offset in bytes
- * @end: end offset in bytes (inclusive)
- * @datasync: only synchronize essential metadata if true
- *
- * This is an implementation of the fsync method for simple filesystems which
- * track all non-inode metadata in the buffers list hanging off the @mmb
- * structure. This also makes sure that a device cache flush operation is
- * called at the end.
- */
-int mmb_fsync(struct file *file, struct mapping_metadata_bhs *mmb,
- loff_t start, loff_t end, bool datasync)
-{
- struct inode *inode = file->f_mapping->host;
- int ret;
-
- ret = mmb_fsync_noflush(file, mmb, start, end, datasync);
- if (!ret)
- ret = blkdev_issue_flush(inode->i_sb->s_bdev);
- return ret;
-}
-EXPORT_SYMBOL(mmb_fsync);
-
/*
* Called when we've recently written block `bblock', and it is known that
* `bblock' was for a buffer_boundary() buffer. This means that the block at
@@ -1123,12 +1050,18 @@ EXPORT_SYMBOL(mark_buffer_dirty);
void mark_buffer_write_io_error(struct buffer_head *bh)
{
+ struct mapping_metadata_bhs *mmb;
+
set_buffer_write_io_error(bh);
/* FIXME: do we need to set this in both places? */
if (bh->b_folio && bh->b_folio->mapping)
mapping_set_error(bh->b_folio->mapping, -EIO);
- if (bh->b_mmb)
- mapping_set_error(bh->b_mmb->mapping, -EIO);
+ /* Protect us from mmb & inode getting freed while we work on it */
+ rcu_read_lock();
+ mmb = READ_ONCE(bh->b_mmb);
+ if (mmb)
+ mapping_set_error(mmb->mapping, -EIO);
+ rcu_read_unlock();
}
EXPORT_SYMBOL(mark_buffer_write_io_error);

fs/ext2/dir.c

View file
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 278d4be..e17bbc7 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -734,6 +734,6 @@ const struct file_operations ext2_dir_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = ext2_compat_ioctl,
#endif
- .fsync = ext2_fsync,
+ .fsync = simple_fsync,
.setlease = generic_setlease,
};

fs/ext2/ext2.h

View file
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 79f7b39..5642451 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -735,6 +735,7 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
/* inode.c */
extern struct inode *ext2_iget (struct super_block *, unsigned long);
extern int ext2_write_inode (struct inode *, struct writeback_control *);
+extern int ext2_sync_inode_metadata(struct inode *, struct writeback_control *);
extern void ext2_evict_inode(struct inode *);
void ext2_write_failed(struct address_space *mapping, loff_t to);
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
@@ -772,8 +773,6 @@ extern void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es,
extern const struct file_operations ext2_dir_operations;
/* file.c */
-extern int ext2_fsync(struct file *file, loff_t start, loff_t end,
- int datasync);
extern const struct inode_operations ext2_file_inode_operations;
extern const struct file_operations ext2_file_operations;

fs/ext2/file.c

View file
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 8dca9ec..b9020df 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -47,21 +47,6 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
return 0;
}
-int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
-{
- int ret;
- struct inode *inode = file->f_mapping->host;
- struct super_block *sb = inode->i_sb;
-
- ret = mmb_fsync(file, &EXT2_I(inode)->i_metadata_bhs,
- start, end, datasync);
- if (ret == -EIO)
- /* We don't really know where the IO error happened... */
- ext2_error(sb, __func__,
- "detected IO error when writing metadata buffers");
- return ret;
-}
-
static ssize_t ext2_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
struct file *file = iocb->ki_filp;
@@ -213,7 +198,7 @@ const struct file_operations ext2_file_operations = {
.mmap_prepare = generic_file_mmap_prepare,
.open = ext2_file_open,
.release = ext2_release_file,
- .fsync = ext2_fsync,
+ .fsync = simple_fsync,
.get_unmapped_area = thp_get_unmapped_area,
.splice_read = filemap_splice_read,
.splice_write = iter_file_splice_write,

fs/ext2/inode.c

View file
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 7e0fa9c..a9245f0 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -39,8 +39,6 @@
#include "acl.h"
#include "xattr.h"
-static int __ext2_write_inode(struct inode *inode, int do_sync);
-
/*
* Test whether an inode is a fast symlink.
*/
@@ -87,7 +85,7 @@ void ext2_evict_inode(struct inode * inode)
/* set dtime */
EXT2_I(inode)->i_dtime = ktime_get_real_seconds();
mark_inode_dirty(inode);
- __ext2_write_inode(inode, inode_needs_sync(inode));
+ sync_inode_metadata(inode, inode_needs_sync(inode));
/* truncate to 0 */
inode->i_size = 0;
if (inode->i_blocks)
@@ -1260,12 +1258,9 @@ static int ext2_setsize(struct inode *inode, loff_t newsize)
filemap_invalidate_unlock(inode->i_mapping);
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
- if (inode_needs_sync(inode)) {
- mmb_sync(&EXT2_I(inode)->i_metadata_bhs);
+ mark_inode_dirty(inode);
+ if (inode_needs_sync(inode))
sync_inode_metadata(inode, 1);
- } else {
- mark_inode_dirty(inode);
- }
return 0;
}
@@ -1471,7 +1466,7 @@ bad_inode:
return ERR_PTR(ret);
}
-static int __ext2_write_inode(struct inode *inode, int do_sync)
+int ext2_write_inode(struct inode *inode, struct writeback_control *wbc)
{
struct ext2_inode_info *ei = EXT2_I(inode);
struct super_block *sb = inode->i_sb;
@@ -1562,22 +1557,38 @@ static int __ext2_write_inode(struct inode *inode, int do_sync)
} else for (n = 0; n < EXT2_N_BLOCKS; n++)
raw_inode->i_block[n] = ei->i_data[n];
mark_buffer_dirty(bh);
- if (do_sync) {
- sync_dirty_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh)) {
- printk ("IO error syncing ext2 inode [%s:%08lx]\n",
- sb->s_id, (unsigned long) ino);
- err = -EIO;
- }
- }
ei->i_state &= ~EXT2_STATE_NEW;
brelse (bh);
+ set_inode_metadata_writeback(inode);
return err;
}
-int ext2_write_inode(struct inode *inode, struct writeback_control *wbc)
+int ext2_sync_inode_metadata(struct inode *inode, struct writeback_control *wbc)
{
- return __ext2_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);

This diff is incomplete. Download the complete patch.

fs/ext2/super.c

View file

This diff is incomplete. Download the complete patch.

fs/ext2/xattr.c

View file

This diff is incomplete. Download the complete patch.

fs/ext4/ext4.h

View file

This diff is incomplete. Download the complete patch.

fs/ext4/ext4_jbd2.c

View file

This diff is incomplete. Download the complete patch.

fs/ext4/fsync.c

View file

This diff is incomplete. Download the complete patch.

fs/ext4/inode.c

View file

This diff is incomplete. Download the complete patch.

fs/ext4/super.c

View file

This diff is incomplete. Download the complete patch.

fs/fat/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/fat/fat.h

View file

This diff is incomplete. Download the complete patch.

fs/fat/file.c

View file

This diff is incomplete. Download the complete patch.

fs/fat/inode.c

View file

This diff is incomplete. Download the complete patch.

fs/fat/misc.c

View file

This diff is incomplete. Download the complete patch.

fs/fat/namei_msdos.c

View file

This diff is incomplete. Download the complete patch.

fs/fat/namei_vfat.c

View file

This diff is incomplete. Download the complete patch.

fs/fs-writeback.c

View file

This diff is incomplete. Download the complete patch.

fs/libfs.c

View file

This diff is incomplete. Download the complete patch.

fs/minix/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/minix/file.c

View file

This diff is incomplete. Download the complete patch.

fs/minix/inode.c

View file

This diff is incomplete. Download the complete patch.

fs/minix/minix.h

View file

This diff is incomplete. Download the complete patch.

fs/udf/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/udf/file.c

View file

This diff is incomplete. Download the complete patch.

fs/udf/inode.c

View file

This diff is incomplete. Download the complete patch.

fs/udf/super.c

View file

This diff is incomplete. Download the complete patch.

fs/udf/udfdecl.h

View file

This diff is incomplete. Download the complete patch.

include/linux/buffer_head.h

View file

This diff is incomplete. Download the complete patch.

include/linux/fs.h

View file

This diff is incomplete. Download the complete patch.

include/linux/fs/super_types.h

View file

This diff is incomplete. Download the complete patch.