Skip to content

Commit 9e70e98

Browse files
josefbacikbrauner
authored andcommitted
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>
1 parent 9a98f9e commit 9e70e98

1 file changed

Lines changed: 35 additions & 11 deletions

File tree

fs/inode.c

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,20 +1908,44 @@ static void iput_final(struct inode *inode)
19081908
*/
19091909
void iput(struct inode *inode)
19101910
{
1911-
if (!inode)
1911+
if (unlikely(!inode))
19121912
return;
1913-
BUG_ON(inode->i_state & I_CLEAR);
1913+
19141914
retry:
1915-
if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) {
1916-
if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) {
1917-
atomic_inc(&inode->i_count);
1918-
spin_unlock(&inode->i_lock);
1919-
trace_writeback_lazytime_iput(inode);
1920-
mark_inode_dirty_sync(inode);
1921-
goto retry;
1922-
}
1923-
iput_final(inode);
1915+
lockdep_assert_not_held(&inode->i_lock);
1916+
VFS_BUG_ON_INODE(inode->i_state & I_CLEAR, inode);
1917+
/*
1918+
* Note this assert is technically racy as if the count is bogusly
1919+
* equal to one, then two CPUs racing to further drop it can both
1920+
* conclude it's fine.
1921+
*/
1922+
VFS_BUG_ON_INODE(atomic_read(&inode->i_count) < 1, inode);
1923+
1924+
if (atomic_add_unless(&inode->i_count, -1, 1))
1925+
return;
1926+
1927+
if ((inode->i_state & I_DIRTY_TIME) && inode->i_nlink) {
1928+
trace_writeback_lazytime_iput(inode);
1929+
mark_inode_dirty_sync(inode);
1930+
goto retry;
19241931
}
1932+
1933+
spin_lock(&inode->i_lock);
1934+
if (unlikely((inode->i_state & I_DIRTY_TIME) && inode->i_nlink)) {
1935+
spin_unlock(&inode->i_lock);
1936+
goto retry;
1937+
}
1938+
1939+
if (!atomic_dec_and_test(&inode->i_count)) {
1940+
spin_unlock(&inode->i_lock);
1941+
return;
1942+
}
1943+
1944+
/*
1945+
* iput_final() drops ->i_lock, we can't assert on it as the inode may
1946+
* be deallocated by the time the call returns.
1947+
*/
1948+
iput_final(inode);
19251949
}
19261950
EXPORT_SYMBOL(iput);
19271951

0 commit comments

Comments
 (0)