]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs: add missing fences to I_NEW handling
authorMateusz Guzik <mjguzik@gmail.com>
Sun, 5 Oct 2025 23:15:26 +0000 (01:15 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 20 Oct 2025 18:22:25 +0000 (20:22 +0200)
Suppose there are 2 CPUs racing inode hash lookup func (say ilookup5())
and unlock_new_inode().

In principle the latter can clear the I_NEW flag before prior stores
into the inode were made visible.

The former can in turn observe I_NEW is cleared and proceed to use the
inode, while possibly reading from not-yet-published areas.

Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/dcache.c
fs/inode.c
include/linux/writeback.h

index a067fa0a965a123b256d73c9700f6b06b3b96c93..806d6a665124f1e39e76025884c5c1ca0de61ac4 100644 (file)
@@ -1981,6 +1981,10 @@ void d_instantiate_new(struct dentry *entry, struct inode *inode)
        spin_lock(&inode->i_lock);
        __d_instantiate(entry, inode);
        WARN_ON(!(inode->i_state & I_NEW));
+       /*
+        * Pairs with smp_rmb in wait_on_inode().
+        */
+       smp_wmb();
        inode->i_state &= ~I_NEW & ~I_CREATING;
        /*
         * Pairs with the barrier in prepare_to_wait_event() to make sure
index fa82cb810af440f3ff52418ccfc796398e85f5bf..37fc7a72aba55b64a722f0af43f6e5a84b19daf0 100644 (file)
@@ -1181,6 +1181,10 @@ void unlock_new_inode(struct inode *inode)
        lockdep_annotate_inode_mutex_key(inode);
        spin_lock(&inode->i_lock);
        WARN_ON(!(inode->i_state & I_NEW));
+       /*
+        * Pairs with smp_rmb in wait_on_inode().
+        */
+       smp_wmb();
        inode->i_state &= ~I_NEW & ~I_CREATING;
        /*
         * Pairs with the barrier in prepare_to_wait_event() to make sure
@@ -1198,6 +1202,10 @@ void discard_new_inode(struct inode *inode)
        lockdep_annotate_inode_mutex_key(inode);
        spin_lock(&inode->i_lock);
        WARN_ON(!(inode->i_state & I_NEW));
+       /*
+        * Pairs with smp_rmb in wait_on_inode().
+        */
+       smp_wmb();
        inode->i_state &= ~I_NEW;
        /*
         * Pairs with the barrier in prepare_to_wait_event() to make sure
index 22dd4adc5667d952f1baf7fff14d8525f5e3b28e..e1e1231a68303a019456f1f8293263caa518b9a9 100644 (file)
@@ -194,6 +194,10 @@ static inline void wait_on_inode(struct inode *inode)
 {
        wait_var_event(inode_state_wait_address(inode, __I_NEW),
                       !(READ_ONCE(inode->i_state) & I_NEW));
+       /*
+        * Pairs with routines clearing I_NEW.
+        */
+       smp_rmb();
 }
 
 #ifdef CONFIG_CGROUP_WRITEBACK