[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <62383d1029eca5053a2fa320ae51f407c9ae2896.1756222465.git.josef@toxicpanda.com>
Date: Tue, 26 Aug 2025 11:39:13 -0400
From: Josef Bacik <josef@...icpanda.com>
To: linux-fsdevel@...r.kernel.org,
linux-btrfs@...r.kernel.org,
kernel-team@...com,
linux-ext4@...r.kernel.org,
linux-xfs@...r.kernel.org,
brauner@...nel.org,
viro@...IV.linux.org.uk,
amir73il@...il.com
Subject: [PATCH v2 13/54] fs: hold an i_obj_count when we have an i_count reference
This is the start of the semantic changes of inode lifetimes.
Unfortunately we have to do two things in one patch to be properly safe,
but this is the only case where this happens.
First we take and drop an i_obj_count reference every time we get an
i_count reference. This is because we will be changing the i_count
reference to be the indicator of a "live" inode.
The second thing we do is move the life time of the memory allocation
for the inode under the control of the i_obj_count reference.
Signed-off-by: Josef Bacik <josef@...icpanda.com>
---
fs/btrfs/inode.c | 4 +++-
fs/fs-writeback.c | 2 --
fs/inode.c | 28 +++++++++-------------------
include/linux/fs.h | 1 +
4 files changed, 13 insertions(+), 22 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ac00554e8479..e16df38e0eef 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3418,8 +3418,10 @@ void btrfs_add_delayed_iput(struct btrfs_inode *inode)
struct btrfs_fs_info *fs_info = inode->root->fs_info;
unsigned long flags;
- if (atomic_add_unless(&inode->vfs_inode.i_count, -1, 1))
+ if (atomic_add_unless(&inode->vfs_inode.i_count, -1, 1)) {
+ iobj_put(&inode->vfs_inode);
return;
+ }
WARN_ON_ONCE(test_bit(BTRFS_FS_STATE_NO_DELAYED_IPUT, &fs_info->fs_state));
atomic_inc(&fs_info->nr_delayed_iputs);
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 773b276328ec..b83d556d7ffe 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -2736,7 +2736,6 @@ static void wait_sb_inodes(struct super_block *sb)
continue;
}
__iget(inode);
- iobj_get(inode);
spin_unlock(&inode->i_lock);
rcu_read_unlock();
@@ -2750,7 +2749,6 @@ static void wait_sb_inodes(struct super_block *sb)
cond_resched();
iput(inode);
- iobj_put(inode);
rcu_read_lock();
spin_lock_irq(&sb->s_inode_wblist_lock);
diff --git a/fs/inode.c b/fs/inode.c
index b146b37f7097..ddaf282f7c25 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -527,6 +527,7 @@ static void init_once(void *foo)
*/
void ihold(struct inode *inode)
{
+ iobj_get(inode);
WARN_ON(atomic_inc_return(&inode->i_count) < 2);
}
EXPORT_SYMBOL(ihold);
@@ -843,13 +844,6 @@ static void evict(struct inode *inode)
*/
inode_wake_up_bit(inode, __I_NEW);
BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
-
- /*
- * refcount_dec_and_test must be used here to avoid the underflow
- * warning.
- */
- WARN_ON(!refcount_dec_and_test(&inode->i_obj_count));
- destroy_inode(inode);
}
/*
@@ -867,16 +861,8 @@ static void dispose_list(struct list_head *head)
inode = list_first_entry(head, struct inode, i_lru);
list_del_init(&inode->i_lru);
- /*
- * This is going right here for now only because we are
- * currently not using the i_obj_count reference for anything,
- * and it needs to hit 0 when we call evict().
- *
- * This will be moved when we change the lifetime rules in a
- * future patch.
- */
- iobj_put(inode);
evict(inode);
+ iobj_put(inode);
cond_resched();
}
}
@@ -1943,8 +1929,10 @@ void iput(struct inode *inode)
return;
BUG_ON(inode->i_state & I_CLEAR);
- if (atomic_add_unless(&inode->i_count, -1, 1))
+ 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);
@@ -1958,6 +1946,7 @@ void iput(struct inode *inode)
} else {
spin_unlock(&inode->i_lock);
}
+ iobj_put(inode);
}
EXPORT_SYMBOL(iput);
@@ -1965,13 +1954,14 @@ EXPORT_SYMBOL(iput);
* iobj_put - put a object reference on an inode
* @inode: inode to put
*
- * Puts a object reference on an inode.
+ * Puts a object reference on an inode, free's it if we get to zero.
*/
void iobj_put(struct inode *inode)
{
if (!inode)
return;
- refcount_dec(&inode->i_obj_count);
+ if (refcount_dec_and_test(&inode->i_obj_count))
+ destroy_inode(inode);
}
EXPORT_SYMBOL(iobj_put);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 84f5218755c3..023ad47685be 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3381,6 +3381,7 @@ static inline unsigned int iobj_count_read(const struct inode *inode)
*/
static inline void __iget(struct inode *inode)
{
+ iobj_get(inode);
atomic_inc(&inode->i_count);
}
--
2.49.0
Powered by blists - more mailing lists