1
0
mirror of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2026-01-12 01:20:14 +00:00

fs: rework iput logic

Currently, if we are the last iput, and we have the I_DIRTY_TIME bit
set, we will grab a reference on the inode again and then mark it dirty
and then redo the put.  This is to make sure we delay the time update
for as long as possible.

We can rework this logic to simply dec i_count if it is not 1, and if it
is do the time update while still holding the i_count reference.

Then we can replace the atomic_dec_and_lock with locking the ->i_lock
and doing atomic_dec_and_test, since we did the atomic_add_unless above.

Co-developed-by: Mateusz Guzik <mjguzik@gmail.com>
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Link: https://lore.kernel.org/be208b89bdb650202e712ce2bcfc407ac7044c7a.1756222464.git.josef@toxicpanda.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Josef Bacik 2025-08-26 11:39:03 -04:00 committed by Christian Brauner
parent 9a98f9e84c
commit 9e70e985bd
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2

View File

@ -1908,20 +1908,44 @@ static void iput_final(struct inode *inode)
*/
void iput(struct inode *inode)
{
if (!inode)
if (unlikely(!inode))
return;
BUG_ON(inode->i_state & I_CLEAR);
retry:
if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) {
if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) {
atomic_inc(&inode->i_count);
spin_unlock(&inode->i_lock);
trace_writeback_lazytime_iput(inode);
mark_inode_dirty_sync(inode);
goto retry;
}
iput_final(inode);
lockdep_assert_not_held(&inode->i_lock);
VFS_BUG_ON_INODE(inode->i_state & I_CLEAR, inode);
/*
* Note this assert is technically racy as if the count is bogusly
* equal to one, then two CPUs racing to further drop it can both
* conclude it's fine.
*/
VFS_BUG_ON_INODE(atomic_read(&inode->i_count) < 1, inode);
if (atomic_add_unless(&inode->i_count, -1, 1))
return;
if ((inode->i_state & I_DIRTY_TIME) && inode->i_nlink) {
trace_writeback_lazytime_iput(inode);
mark_inode_dirty_sync(inode);
goto retry;
}
spin_lock(&inode->i_lock);
if (unlikely((inode->i_state & I_DIRTY_TIME) && inode->i_nlink)) {
spin_unlock(&inode->i_lock);
goto retry;
}
if (!atomic_dec_and_test(&inode->i_count)) {
spin_unlock(&inode->i_lock);
return;
}
/*
* iput_final() drops ->i_lock, we can't assert on it as the inode may
* be deallocated by the time the call returns.
*/
iput_final(inode);
}
EXPORT_SYMBOL(iput);