]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
ext4: Mark pages with journalled data dirty
authorJan Kara <jack@suse.cz>
Wed, 29 Mar 2023 15:49:33 +0000 (17:49 +0200)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 14 Apr 2023 23:38:50 +0000 (19:38 -0400)
Currently pages with journalled data written by write(2) or modified by
block zeroing during truncate(2) are not marked as dirty. They are
dirtied only once the transaction commits. This however makes writeback
code think inode has no pages to write and so ext4_writepages() is not
called to make pages with journalled data persistent. Mark pages with
journalled data dirty (similarly as it happens for writes through mmap)
so that writeback code knows about them and ext4_writepages() can do
what it needs to to the inode.

Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20230329154950.19720-2-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/inode.c

index 6d628d6c0847ecc22255b26001eeb140f80dc60e..c5de0c04204cbe3a525ff788291a19d9ed11a042 100644 (file)
@@ -1003,6 +1003,18 @@ int ext4_walk_page_buffers(handle_t *handle, struct inode *inode,
        return ret;
 }
 
+/*
+ * Helper for handling dirtying of journalled data. We also mark the folio as
+ * dirty so that writeback code knows about this page (and inode) contains
+ * dirty data. ext4_writepages() then commits appropriate transaction to
+ * make data stable.
+ */
+static int ext4_dirty_journalled_data(handle_t *handle, struct buffer_head *bh)
+{
+       folio_mark_dirty(bh->b_folio);
+       return ext4_handle_dirty_metadata(handle, NULL, bh);
+}
+
 int do_journal_get_write_access(handle_t *handle, struct inode *inode,
                                struct buffer_head *bh)
 {
@@ -1025,7 +1037,7 @@ int do_journal_get_write_access(handle_t *handle, struct inode *inode,
        ret = ext4_journal_get_write_access(handle, inode->i_sb, bh,
                                            EXT4_JTR_NONE);
        if (!ret && dirty)
-               ret = ext4_handle_dirty_metadata(handle, NULL, bh);
+               ret = ext4_dirty_journalled_data(handle, bh);
        return ret;
 }
 
@@ -1272,7 +1284,7 @@ static int write_end_fn(handle_t *handle, struct inode *inode,
        if (!buffer_mapped(bh) || buffer_freed(bh))
                return 0;
        set_buffer_uptodate(bh);
-       ret = ext4_handle_dirty_metadata(handle, NULL, bh);
+       ret = ext4_dirty_journalled_data(handle, bh);
        clear_buffer_meta(bh);
        clear_buffer_prio(bh);
        return ret;
@@ -1356,7 +1368,7 @@ static int ext4_write_end(struct file *file,
 /*
  * This is a private version of page_zero_new_buffers() which doesn't
  * set the buffer to be dirty, since in data=journalled mode we need
- * to call ext4_handle_dirty_metadata() instead.
+ * to call ext4_dirty_journalled_data() instead.
  */
 static void ext4_journalled_zero_new_buffers(handle_t *handle,
                                            struct inode *inode,
@@ -3740,7 +3752,7 @@ static int __ext4_block_zero_page_range(handle_t *handle,
        BUFFER_TRACE(bh, "zeroed end of block");
 
        if (ext4_should_journal_data(inode)) {
-               err = ext4_handle_dirty_metadata(handle, inode, bh);
+               err = ext4_dirty_journalled_data(handle, bh);
        } else {
                err = 0;
                mark_buffer_dirty(bh);