On Thu, Aug 21, 2025 at 04:18:23PM -0400, Josef Bacik wrote: > 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. > > This is preparation for no longer allowing 0 i_count inodes to exist. > > Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx> > --- > fs/inode.c | 31 ++++++++++++++++--------------- > 1 file changed, 16 insertions(+), 15 deletions(-) > > diff --git a/fs/inode.c b/fs/inode.c > index 16acad5583fc..814c03f5dbb1 100644 > --- a/fs/inode.c > +++ b/fs/inode.c > @@ -1928,22 +1928,23 @@ void iput(struct inode *inode) > if (!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)) { > - /* > - * Increment i_count directly as we still have our > - * i_obj_count reference still. This is temporary and > - * will go away in a future patch. > - */ > - 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); > + > + if (atomic_add_unless(&inode->i_count, -1, 1)) { > + iobj_put(inode); > + return; > } > + > + if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) { > + trace_writeback_lazytime_iput(inode); > + mark_inode_dirty_sync(inode); > + } > + > + spin_lock(&inode->i_lock); > + if (atomic_dec_and_test(&inode->i_count)) > + iput_final(inode); Personally, I'd add a // drops i_lock comment behind iput_final() but that's a matter of taste tbf. > + else > + spin_unlock(&inode->i_lock); > + > iobj_put(inode); > } > EXPORT_SYMBOL(iput); This looks a lot less magical than the current variant! We should maybe split this patch in two. A cleanup patch that removes the questionable "drop to zero, take lock then increment from zero again" logic and then in a separate patch add in the iobj_put(). So the cleanup can go to the front of the series.