linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eric Biggers <ebiggers@kernel.org>
To: linux-fsdevel@vger.kernel.org
Cc: linux-ext4@vger.kernel.org,
	linux-f2fs-devel@lists.sourceforge.net,
	linux-xfs@vger.kernel.org, Theodore Ts'o <tytso@mit.edu>,
	Christoph Hellwig <hch@lst.de>,
	stable@vger.kernel.org
Subject: [PATCH 01/13] fs: avoid double-writing inodes on lazytime expiration
Date: Mon,  4 Jan 2021 16:54:40 -0800	[thread overview]
Message-ID: <20210105005452.92521-2-ebiggers@kernel.org> (raw)
In-Reply-To: <20210105005452.92521-1-ebiggers@kernel.org>

From: Eric Biggers <ebiggers@google.com>

When lazytime is enabled and an inode with dirty timestamps is being
expired, either due to dirtytime_expire_interval being exceeded or due
to a sync or syncfs system call, we need to inform the filesystem that
the inode is dirty so that the inode's timestamps can be copied out to
the on-disk data structures.  That's because if the filesystem supports
lazytime, it will have ignored the ->dirty_inode(inode, I_DIRTY_TIME)
notification when the timestamp was modified in memory.

Currently this is accomplished by calling mark_inode_dirty_sync() from
__writeback_single_inode().  However, this has the unfortunate side
effect of also putting the inode the writeback list.  That's not
appropriate in this case, since the inode is already being written.

That causes the inode to remain dirty after a sync.  Normally that's
just wasteful, as it causes the inode to be written twice.  But when
fscrypt is used this bug also partially breaks the
FS_IOC_REMOVE_ENCRYPTION_KEY ioctl, as the ioctl reports that files are
still in-use when they aren't.  For more details, see the original
report at https://lore.kernel.org/r/20200306004555.GB225345@gmail.com

Fix this by calling ->dirty_inode(inode, I_DIRTY_SYNC) directly instead
of mark_inode_dirty_sync().

This fixes xfstest generic/580 when lazytime is enabled.

A later patch will introduce a ->lazytime_expired method to cleanly
separate out the lazytime expiration case, in particular for XFS which
uses the VFS-level dirtiness tracking only for lazytime.  But that's
separate from fixing this bug.  Also, note that XFS will incorrectly
ignore the I_DIRTY_SYNC notification from __writeback_single_inode()
both before and after this patch, as I_DIRTY_TIME was already cleared in
i_state.  Later patches will fix this separate bug.

Fixes: 0ae45f63d4ef ("vfs: add support for a lazytime mount option")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 fs/fs-writeback.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index acfb55834af23..081e335cdee47 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -1509,11 +1509,22 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
 
 	spin_unlock(&inode->i_lock);
 
-	if (dirty & I_DIRTY_TIME)
-		mark_inode_dirty_sync(inode);
 	/* Don't write the inode if only I_DIRTY_PAGES was set */
 	if (dirty & ~I_DIRTY_PAGES) {
-		int err = write_inode(inode, wbc);
+		int err;
+
+		/*
+		 * If the inode is being written due to a lazytime timestamp
+		 * expiration, then the filesystem needs to be notified about it
+		 * so that e.g. the filesystem can update on-disk fields and
+		 * journal the timestamp update.  Just calling write_inode()
+		 * isn't enough.  Don't call mark_inode_dirty_sync(), as that
+		 * would put the inode back on the dirty list.
+		 */
+		if ((dirty & I_DIRTY_TIME) && inode->i_sb->s_op->dirty_inode)
+			inode->i_sb->s_op->dirty_inode(inode, I_DIRTY_SYNC);
+
+		err = write_inode(inode, wbc);
 		if (ret == 0)
 			ret = err;
 	}

base-commit: e71ba9452f0b5b2e8dc8aa5445198cd9214a6a62
-- 
2.30.0


  reply	other threads:[~2021-01-05  0:56 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-05  0:54 [PATCH 00/13] lazytime fixes and cleanups Eric Biggers
2021-01-05  0:54 ` Eric Biggers [this message]
2021-01-07 14:47   ` [PATCH 01/13] fs: avoid double-writing inodes on lazytime expiration Jan Kara
2021-01-07 14:58     ` Matthew Wilcox
2021-01-07 21:46     ` Eric Biggers
2021-01-08  8:54       ` Christoph Hellwig
2021-01-08  9:01     ` Christoph Hellwig
2021-01-09 17:11       ` Eric Biggers
2021-01-05  0:54 ` [PATCH 02/13] gfs2: don't worry about I_DIRTY_TIME in gfs2_fsync() Eric Biggers
2021-01-08  8:54   ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 03/13] fs: only specify I_DIRTY_TIME when needed in generic_update_time() Eric Biggers
2021-01-08  8:57   ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 04/13] fat: only specify I_DIRTY_TIME when needed in fat_update_time() Eric Biggers
2021-01-07 13:13   ` Jan Kara
2021-01-07 19:10     ` Eric Biggers
2021-01-05  0:54 ` [PATCH 05/13] fs: don't call ->dirty_inode for lazytime timestamp updates Eric Biggers
2021-01-07 13:17   ` Jan Kara
2021-01-07 13:18     ` Jan Kara
2021-01-08  9:02   ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 06/13] fs: pass only I_DIRTY_INODE flags to ->dirty_inode Eric Biggers
2021-01-08  9:02   ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 07/13] fs: correctly document the inode dirty flags Eric Biggers
2021-01-08  9:03   ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 08/13] ext4: simplify i_state checks in __ext4_update_other_inode_time() Eric Biggers
2021-01-07 13:24   ` Jan Kara
2021-01-07 19:06     ` Eric Biggers
2021-01-05  0:54 ` [PATCH 09/13] fs: drop redundant checks from __writeback_single_inode() Eric Biggers
2021-01-08  9:12   ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 10/13] fs: clean up __mark_inode_dirty() a bit Eric Biggers
2021-01-08  9:10   ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 11/13] fs: add a lazytime_expired method Eric Biggers
2021-01-07 14:02   ` Jan Kara
2021-01-07 22:05     ` Eric Biggers
2021-01-08  9:14       ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 12/13] xfs: remove a stale comment from xfs_file_aio_write_checks() Eric Biggers
2021-01-08  9:15   ` Christoph Hellwig
2021-01-05  0:54 ` [PATCH 13/13] xfs: implement lazytime_expired Eric Biggers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210105005452.92521-2-ebiggers@kernel.org \
    --to=ebiggers@kernel.org \
    --cc=hch@lst.de \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-xfs@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).