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 PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Thu, 28 Jul 2022 15:39:14 +0200 From: Lukas Czerner <lczerner@...hat.com> To: linux-ext4@...r.kernel.org Cc: jlayton@...nel.org, tytso@....edu, linux-fsdevel@...r.kernel.org Subject: [PATCH 2/2] fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE Currently the I_DIRTY_TIME will never get set if the inode already has I_DIRTY_INODE with assumption that it supersedes I_DIRTY_TIME. That's true, however ext4 will only update the on-disk inode in ->dirty_inode(), not on actual writeback. As a result if the inode already has I_DIRTY_INODE state by the time we get to __mark_inode_dirty() only with I_DIRTY_TIME, the time was already filled into on-disk inode and will not get updated until the next I_DIRTY_INODE update, which might never come if we crash or get a power failure. The problem can be reproduced on ext4 by running xfstest generic/622 with -o iversion mount option. Fix it by setting I_DIRTY_TIME even if the inode already has I_DIRTY_INODE. Also clear the I_DIRTY_TIME after ->dirty_inode() otherwise it may never get cleared. Signed-off-by: Lukas Czerner <lczerner@...hat.com> --- fs/fs-writeback.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 05221366a16d..174f01e6b912 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -2383,6 +2383,11 @@ void __mark_inode_dirty(struct inode *inode, int flags) /* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ flags &= ~I_DIRTY_TIME; + if (inode->i_state & I_DIRTY_TIME) { + spin_lock(&inode->i_lock); + inode->i_state &= ~I_DIRTY_TIME; + spin_unlock(&inode->i_lock); + } } else { /* * Else it's either I_DIRTY_PAGES, I_DIRTY_TIME, or nothing. @@ -2399,13 +2404,20 @@ void __mark_inode_dirty(struct inode *inode, int flags) */ smp_mb(); - if (((inode->i_state & flags) == flags) || - (dirtytime && (inode->i_state & I_DIRTY_INODE))) + if ((inode->i_state & flags) == flags) return; spin_lock(&inode->i_lock); - if (dirtytime && (inode->i_state & I_DIRTY_INODE)) + if (dirtytime && (inode->i_state & I_DIRTY_INODE)) { + /* + * We've got a new lazytime update. Make sure it's recorded in + * i_state, because the time might have already got updated in + * ->dirty_inode() and will not get updated until next + * I_DIRTY_INODE update. + */ + inode->i_state |= I_DIRTY_TIME; goto out_unlock_inode; + } if ((inode->i_state & flags) != flags) { const int was_dirty = inode->i_state & I_DIRTY; -- 2.35.3
Powered by blists - more mailing lists