lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230308142528.12384-1-jack@suse.cz>
Date:   Wed,  8 Mar 2023 15:25:28 +0100
From:   Jan Kara <jack@...e.cz>
To:     Ted Tso <tytso@....edu>
Cc:     <linux-ext4@...r.kernel.org>, Jan Kara <jack@...e.cz>
Subject: [PATCH] ext4: Fix warnings when freezing filesystem with journaled data

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.

Signed-off-by: Jan Kara <jack@...e.cz>
---
 fs/ext4/inode.c | 15 ++++++++++++++-
 fs/ext4/super.c | 11 +++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)

  This patch fixes warnings for generic/390 test. Admittedly it is a bit of a
hack and the right fix is to change jbd2 code to avoid leaving stray page dirty
bits but that is actually surprisingly difficult to do due to locking
constraints without regressing metadata intensive workloads. Applies on top of
my data=journal cleanup series.

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 4a45d320fda8..d86efa3d959d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -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,7 +2428,15 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
 	else
 		tag = PAGECACHE_TAG_DIRTY;
 
-	if (ext4_should_journal_data(mpd->inode)) {
+	/*
+	 * 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))
@@ -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)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 88f7b8a88c76..8cdf1a4e0011 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -6259,6 +6259,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))
-- 
2.35.3

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ