]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
ext4: Fix warnings when freezing filesystem with journaled data
authorJan Kara <jack@suse.cz>
Wed, 8 Mar 2023 14:25:28 +0000 (15:25 +0100)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 24 Mar 2023 02:53:00 +0000 (22:53 -0400)
Test generic/390 in data=journal mode often triggers a warning that
ext4_do_writepages() tries to start a transaction on frozen filesystem.
This happens because although all dirty data is properly written, jbd2
checkpointing code writes data through submit_bh() and as a result only
buffer dirty bits are cleared but page dirty bits stay set. Later when
the filesystem is frozen, writeback code comes, tries to write
supposedly dirty pages and the warning triggers. Fix the problem by
calling sync_filesystem() once more after flushing the whole journal to
clear stray page dirty bits.

[ Applied fixup patches to address crashes when running data=journal
  tests; see links for more details -- TYT ]

Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20230308142528.12384-1-jack@suse.cz
Reported-by: Eric Biggers <ebiggers@kernel.org>
Link: https://lore.kernel.org/all/20230319183617.GA896@sol.localdomain
Link: https://lore.kernel.org/r/20230323145404.21381-1-jack@suse.cz
Link: https://lore.kernel.org/r/20230323145404.21381-2-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/inode.c
fs/ext4/super.c

index 652efb2221bfea3ca5914257830f3b55dce62c0c..6445b8017a8ee63f2a40944af6cde8202f4601e3 100644 (file)
@@ -2410,6 +2410,7 @@ static int mpage_journal_page_buffers(handle_t *handle,
 static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
 {
        struct address_space *mapping = mpd->inode->i_mapping;
+       struct super_block *sb = mpd->inode->i_sb;
        struct folio_batch fbatch;
        unsigned int nr_folios;
        pgoff_t index = mpd->first_page;
@@ -2427,15 +2428,23 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
        else
                tag = PAGECACHE_TAG_DIRTY;
 
-       if (ext4_should_journal_data(mpd->inode)) {
+       mpd->map.m_len = 0;
+       mpd->next_page = index;
+       /*
+        * Start a transaction for writeback of journalled data. We don't start
+        * start the transaction if the filesystem is frozen. In that case we
+        * should not have any dirty data to write anymore but possibly there
+        * are stray page dirty bits left by the checkpointing code so this
+        * loop clears them.
+        */
+       if (ext4_should_journal_data(mpd->inode) &&
+           sb->s_writers.frozen < SB_FREEZE_FS) {
                handle = ext4_journal_start(mpd->inode, EXT4_HT_WRITE_PAGE,
                                            bpp);
                if (IS_ERR(handle))
                        return PTR_ERR(handle);
        }
        folio_batch_init(&fbatch);
-       mpd->map.m_len = 0;
-       mpd->next_page = index;
        while (index <= end) {
                nr_folios = filemap_get_folios_tag(mapping, &index, end,
                                tag, &fbatch);
@@ -2520,12 +2529,16 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
                         */
                        if (!mpd->can_map) {
                                if (ext4_page_nomap_can_writeout(&folio->page)) {
+                                       WARN_ON_ONCE(sb->s_writers.frozen ==
+                                                    SB_FREEZE_COMPLETE);
                                        err = mpage_submit_page(mpd, &folio->page);
                                        if (err < 0)
                                                goto out;
                                }
                                /* Pending dirtying of journalled data? */
                                if (PageChecked(&folio->page)) {
+                                       WARN_ON_ONCE(sb->s_writers.frozen >=
+                                                    SB_FREEZE_FS);
                                        err = mpage_journal_page_buffers(handle,
                                                mpd, &folio->page);
                                        if (err < 0)
index f43e526112ae837498c918637f50d7e15a004a0a..f226f8ab469b058022a48f35f83c50097b7440c7 100644 (file)
@@ -6293,6 +6293,17 @@ static int ext4_freeze(struct super_block *sb)
                if (error < 0)
                        goto out;
 
+               /*
+                * Do another sync. We really should not have any dirty data
+                * anymore but our checkpointing code does not clear page dirty
+                * bits due to locking constraints so writeback still can get
+                * started for inodes with journalled data which triggers
+                * annoying warnings.
+                */
+               error = sync_filesystem(sb);
+               if (error < 0)
+                       goto out;
+
                /* Journal blocked and flushed, clear needs_recovery flag. */
                ext4_clear_feature_journal_needs_recovery(sb);
                if (ext4_orphan_file_empty(sb))