* [PATCH v7 01/14] fs: move wait_on_inode() from writeback.h to fs.h
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 13:47 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 02/14] fs: spell out fenced ->i_state accesses with explicit smp_wmb/smp_rmb Mateusz Guzik
` (14 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
The only consumer outside of fs/inode.c is gfs2 and it already includes
fs.h in the relevant file.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
include/linux/fs.h | 10 ++++++++++
include/linux/writeback.h | 11 -----------
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ac62b9d10b00..b35014ba681b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -949,6 +949,16 @@ static inline void inode_fake_hash(struct inode *inode)
hlist_add_fake(&inode->i_hash);
}
+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();
+}
+
/*
* inode->i_rwsem nesting subclasses for the lock validator:
*
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index e1e1231a6830..06195c2a535b 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -189,17 +189,6 @@ void wakeup_flusher_threads_bdi(struct backing_dev_info *bdi,
void inode_wait_for_writeback(struct inode *inode);
void inode_io_list_del(struct inode *inode);
-/* writeback.h requires fs.h; it, too, is not included from here. */
-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
#include <linux/cgroup.h>
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 01/14] fs: move wait_on_inode() from writeback.h to fs.h
2025-10-09 7:59 ` [PATCH v7 01/14] fs: move wait_on_inode() from writeback.h to fs.h Mateusz Guzik
@ 2025-10-10 13:47 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 13:47 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:15, Mateusz Guzik wrote:
> The only consumer outside of fs/inode.c is gfs2 and it already includes
> fs.h in the relevant file.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Fair. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> include/linux/fs.h | 10 ++++++++++
> include/linux/writeback.h | 11 -----------
> 2 files changed, 10 insertions(+), 11 deletions(-)
>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index ac62b9d10b00..b35014ba681b 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -949,6 +949,16 @@ static inline void inode_fake_hash(struct inode *inode)
> hlist_add_fake(&inode->i_hash);
> }
>
> +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();
> +}
> +
> /*
> * inode->i_rwsem nesting subclasses for the lock validator:
> *
> diff --git a/include/linux/writeback.h b/include/linux/writeback.h
> index e1e1231a6830..06195c2a535b 100644
> --- a/include/linux/writeback.h
> +++ b/include/linux/writeback.h
> @@ -189,17 +189,6 @@ void wakeup_flusher_threads_bdi(struct backing_dev_info *bdi,
> void inode_wait_for_writeback(struct inode *inode);
> void inode_io_list_del(struct inode *inode);
>
> -/* writeback.h requires fs.h; it, too, is not included from here. */
> -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
>
> #include <linux/cgroup.h>
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 02/14] fs: spell out fenced ->i_state accesses with explicit smp_wmb/smp_rmb
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
2025-10-09 7:59 ` [PATCH v7 01/14] fs: move wait_on_inode() from writeback.h to fs.h Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 13:48 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 03/14] fs: provide accessors for ->i_state Mateusz Guzik
` (13 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
The incomming helpers don't ship with _release/_acquire variants, for
the time being anyway.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
fs/fs-writeback.c | 5 +++--
include/linux/backing-dev.h | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 2b35e80037fe..9cda19a40ca2 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -476,10 +476,11 @@ static bool inode_do_switch_wbs(struct inode *inode,
switched = true;
skip_switch:
/*
- * Paired with load_acquire in unlocked_inode_to_wb_begin() and
+ * Paired with an acquire fence in unlocked_inode_to_wb_begin() and
* ensures that the new wb is visible if they see !I_WB_SWITCH.
*/
- smp_store_release(&inode->i_state, inode->i_state & ~I_WB_SWITCH);
+ smp_wmb();
+ inode->i_state &= ~I_WB_SWITCH;
xa_unlock_irq(&mapping->i_pages);
spin_unlock(&inode->i_lock);
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 3e64f14739dd..065cba5dc111 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -277,10 +277,11 @@ unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
rcu_read_lock();
/*
- * Paired with store_release in inode_switch_wbs_work_fn() and
+ * Paired with a release fence in inode_do_switch_wbs() and
* ensures that we see the new wb if we see cleared I_WB_SWITCH.
*/
- cookie->locked = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
+ cookie->locked = inode->i_state & I_WB_SWITCH;
+ smp_rmb();
if (unlikely(cookie->locked))
xa_lock_irqsave(&inode->i_mapping->i_pages, cookie->flags);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 02/14] fs: spell out fenced ->i_state accesses with explicit smp_wmb/smp_rmb
2025-10-09 7:59 ` [PATCH v7 02/14] fs: spell out fenced ->i_state accesses with explicit smp_wmb/smp_rmb Mateusz Guzik
@ 2025-10-10 13:48 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 13:48 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:16, Mateusz Guzik wrote:
> The incomming helpers don't ship with _release/_acquire variants, for
> the time being anyway.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> fs/fs-writeback.c | 5 +++--
> include/linux/backing-dev.h | 5 +++--
> 2 files changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
> index 2b35e80037fe..9cda19a40ca2 100644
> --- a/fs/fs-writeback.c
> +++ b/fs/fs-writeback.c
> @@ -476,10 +476,11 @@ static bool inode_do_switch_wbs(struct inode *inode,
> switched = true;
> skip_switch:
> /*
> - * Paired with load_acquire in unlocked_inode_to_wb_begin() and
> + * Paired with an acquire fence in unlocked_inode_to_wb_begin() and
> * ensures that the new wb is visible if they see !I_WB_SWITCH.
> */
> - smp_store_release(&inode->i_state, inode->i_state & ~I_WB_SWITCH);
> + smp_wmb();
> + inode->i_state &= ~I_WB_SWITCH;
>
> xa_unlock_irq(&mapping->i_pages);
> spin_unlock(&inode->i_lock);
> diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
> index 3e64f14739dd..065cba5dc111 100644
> --- a/include/linux/backing-dev.h
> +++ b/include/linux/backing-dev.h
> @@ -277,10 +277,11 @@ unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
> rcu_read_lock();
>
> /*
> - * Paired with store_release in inode_switch_wbs_work_fn() and
> + * Paired with a release fence in inode_do_switch_wbs() and
> * ensures that we see the new wb if we see cleared I_WB_SWITCH.
> */
> - cookie->locked = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
> + cookie->locked = inode->i_state & I_WB_SWITCH;
> + smp_rmb();
>
> if (unlikely(cookie->locked))
> xa_lock_irqsave(&inode->i_mapping->i_pages, cookie->flags);
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
2025-10-09 7:59 ` [PATCH v7 01/14] fs: move wait_on_inode() from writeback.h to fs.h Mateusz Guzik
2025-10-09 7:59 ` [PATCH v7 02/14] fs: spell out fenced ->i_state accesses with explicit smp_wmb/smp_rmb Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 13:51 ` Jan Kara
2025-10-10 14:44 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 04/14] Coccinelle-based conversion to use ->i_state accessors Mateusz Guzik
` (12 subsequent siblings)
15 siblings, 2 replies; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Open-coded accesses prevent asserting they are done correctly. One
obvious aspect is locking, but significantly more can checked. For
example it can be detected when the code is clearing flags which are
already missing, or is setting flags when it is illegal (e.g., I_FREEING
when ->i_count > 0).
In order to keep things manageable this patchset merely gets the thing
off the ground with only lockdep checks baked in.
Current consumers can be trivially converted.
Suppose flags I_A and I_B are to be handled.
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
The "_once" vs "_raw" discrepancy stems from the read variant differing
by READ_ONCE as opposed to just lockdep checks.
Finally, if you want to atomically clear flags and set new ones, the
following:
state = inode->i_state;
state &= ~I_A;
state |= I_B;
inode->i_state = state;
turns into:
inode_state_replace(inode, I_A, I_B);
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
include/linux/fs.h | 78 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 76 insertions(+), 2 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b35014ba681b..909eb1e68637 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -759,7 +759,7 @@ enum inode_state_bits {
/* reserved wait address bit 3 */
};
-enum inode_state_flags_t {
+enum inode_state_flags_enum {
I_NEW = (1U << __I_NEW),
I_SYNC = (1U << __I_SYNC),
I_LRU_ISOLATING = (1U << __I_LRU_ISOLATING),
@@ -843,7 +843,7 @@ struct inode {
#endif
/* Misc */
- enum inode_state_flags_t i_state;
+ enum inode_state_flags_enum i_state;
/* 32-bit hole */
struct rw_semaphore i_rwsem;
@@ -902,6 +902,80 @@ struct inode {
void *i_private; /* fs or device private pointer */
} __randomize_layout;
+/*
+ * i_state handling
+ *
+ * We hide all of it behind helpers so that we can validate consumers.
+ */
+static inline enum inode_state_flags_enum inode_state_read_once(struct inode *inode)
+{
+ return READ_ONCE(inode->i_state);
+}
+
+static inline enum inode_state_flags_enum inode_state_read(struct inode *inode)
+{
+ lockdep_assert_held(&inode->i_lock);
+ return inode->i_state;
+}
+
+static inline void inode_state_set_raw(struct inode *inode,
+ enum inode_state_flags_enum flags)
+{
+ WRITE_ONCE(inode->i_state, inode->i_state | flags);
+}
+
+static inline void inode_state_set(struct inode *inode,
+ enum inode_state_flags_enum flags)
+{
+ lockdep_assert_held(&inode->i_lock);
+ inode_state_set_raw(inode, flags);
+}
+
+static inline void inode_state_clear_raw(struct inode *inode,
+ enum inode_state_flags_enum flags)
+{
+ WRITE_ONCE(inode->i_state, inode->i_state & ~flags);
+}
+
+static inline void inode_state_clear(struct inode *inode,
+ enum inode_state_flags_enum flags)
+{
+ lockdep_assert_held(&inode->i_lock);
+ inode_state_clear_raw(inode, flags);
+}
+
+static inline void inode_state_assign_raw(struct inode *inode,
+ enum inode_state_flags_enum flags)
+{
+ WRITE_ONCE(inode->i_state, flags);
+}
+
+static inline void inode_state_assign(struct inode *inode,
+ enum inode_state_flags_enum flags)
+{
+ lockdep_assert_held(&inode->i_lock);
+ inode_state_assign_raw(inode, flags);
+}
+
+static inline void inode_state_replace_raw(struct inode *inode,
+ enum inode_state_flags_enum clearflags,
+ enum inode_state_flags_enum setflags)
+{
+ enum inode_state_flags_enum flags;
+ flags = inode->i_state;
+ flags &= ~clearflags;
+ flags |= setflags;
+ inode_state_assign_raw(inode, flags);
+}
+
+static inline void inode_state_replace(struct inode *inode,
+ enum inode_state_flags_enum clearflags,
+ enum inode_state_flags_enum setflags)
+{
+ lockdep_assert_held(&inode->i_lock);
+ inode_state_replace_raw(inode, clearflags, setflags);
+}
+
static inline void inode_set_cached_link(struct inode *inode, char *link, int linklen)
{
VFS_WARN_ON_INODE(strlen(link) != linklen, inode);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-09 7:59 ` [PATCH v7 03/14] fs: provide accessors for ->i_state Mateusz Guzik
@ 2025-10-10 13:51 ` Jan Kara
2025-10-10 14:44 ` Jan Kara
1 sibling, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 13:51 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:17, Mateusz Guzik wrote:
> Open-coded accesses prevent asserting they are done correctly. One
> obvious aspect is locking, but significantly more can checked. For
> example it can be detected when the code is clearing flags which are
> already missing, or is setting flags when it is illegal (e.g., I_FREEING
> when ->i_count > 0).
>
> In order to keep things manageable this patchset merely gets the thing
> off the ground with only lockdep checks baked in.
>
> Current consumers can be trivially converted.
>
> Suppose flags I_A and I_B are to be handled.
>
> If ->i_lock is held, then:
>
> state = inode->i_state => state = inode_state_read(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
>
> If ->i_lock is not held or only held conditionally:
>
> state = inode->i_state => state = inode_state_read_once(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
>
> The "_once" vs "_raw" discrepancy stems from the read variant differing
> by READ_ONCE as opposed to just lockdep checks.
>
> Finally, if you want to atomically clear flags and set new ones, the
> following:
>
> state = inode->i_state;
> state &= ~I_A;
> state |= I_B;
> inode->i_state = state;
>
> turns into:
>
> inode_state_replace(inode, I_A, I_B);
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> include/linux/fs.h | 78 ++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 76 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index b35014ba681b..909eb1e68637 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -759,7 +759,7 @@ enum inode_state_bits {
> /* reserved wait address bit 3 */
> };
>
> -enum inode_state_flags_t {
> +enum inode_state_flags_enum {
> I_NEW = (1U << __I_NEW),
> I_SYNC = (1U << __I_SYNC),
> I_LRU_ISOLATING = (1U << __I_LRU_ISOLATING),
> @@ -843,7 +843,7 @@ struct inode {
> #endif
>
> /* Misc */
> - enum inode_state_flags_t i_state;
> + enum inode_state_flags_enum i_state;
> /* 32-bit hole */
> struct rw_semaphore i_rwsem;
>
> @@ -902,6 +902,80 @@ struct inode {
> void *i_private; /* fs or device private pointer */
> } __randomize_layout;
>
> +/*
> + * i_state handling
> + *
> + * We hide all of it behind helpers so that we can validate consumers.
> + */
> +static inline enum inode_state_flags_enum inode_state_read_once(struct inode *inode)
> +{
> + return READ_ONCE(inode->i_state);
> +}
> +
> +static inline enum inode_state_flags_enum inode_state_read(struct inode *inode)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + return inode->i_state;
> +}
> +
> +static inline void inode_state_set_raw(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + WRITE_ONCE(inode->i_state, inode->i_state | flags);
> +}
> +
> +static inline void inode_state_set(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + inode_state_set_raw(inode, flags);
> +}
> +
> +static inline void inode_state_clear_raw(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + WRITE_ONCE(inode->i_state, inode->i_state & ~flags);
> +}
> +
> +static inline void inode_state_clear(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + inode_state_clear_raw(inode, flags);
> +}
> +
> +static inline void inode_state_assign_raw(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + WRITE_ONCE(inode->i_state, flags);
> +}
> +
> +static inline void inode_state_assign(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + inode_state_assign_raw(inode, flags);
> +}
> +
> +static inline void inode_state_replace_raw(struct inode *inode,
> + enum inode_state_flags_enum clearflags,
> + enum inode_state_flags_enum setflags)
> +{
> + enum inode_state_flags_enum flags;
> + flags = inode->i_state;
> + flags &= ~clearflags;
> + flags |= setflags;
> + inode_state_assign_raw(inode, flags);
> +}
> +
> +static inline void inode_state_replace(struct inode *inode,
> + enum inode_state_flags_enum clearflags,
> + enum inode_state_flags_enum setflags)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + inode_state_replace_raw(inode, clearflags, setflags);
> +}
> +
> static inline void inode_set_cached_link(struct inode *inode, char *link, int linklen)
> {
> VFS_WARN_ON_INODE(strlen(link) != linklen, inode);
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-09 7:59 ` [PATCH v7 03/14] fs: provide accessors for ->i_state Mateusz Guzik
2025-10-10 13:51 ` Jan Kara
@ 2025-10-10 14:44 ` Jan Kara
2025-10-10 15:51 ` Mateusz Guzik
2025-10-14 21:57 ` Dave Chinner
1 sibling, 2 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:44 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:17, Mateusz Guzik wrote:
> +static inline void inode_state_set_raw(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + WRITE_ONCE(inode->i_state, inode->i_state | flags);
> +}
I think this shouldn't really exist as it is dangerous to use and if we
deal with XFS, nobody will actually need this function.
> +static inline void inode_state_set(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + inode_state_set_raw(inode, flags);
> +}
> +
> +static inline void inode_state_clear_raw(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + WRITE_ONCE(inode->i_state, inode->i_state & ~flags);
> +}
Ditto here.
> +static inline void inode_state_clear(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + inode_state_clear_raw(inode, flags);
> +}
> +
> +static inline void inode_state_assign_raw(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + WRITE_ONCE(inode->i_state, flags);
> +}
> +
> +static inline void inode_state_assign(struct inode *inode,
> + enum inode_state_flags_enum flags)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + inode_state_assign_raw(inode, flags);
> +}
> +
> +static inline void inode_state_replace_raw(struct inode *inode,
> + enum inode_state_flags_enum clearflags,
> + enum inode_state_flags_enum setflags)
> +{
> + enum inode_state_flags_enum flags;
> + flags = inode->i_state;
> + flags &= ~clearflags;
> + flags |= setflags;
> + inode_state_assign_raw(inode, flags);
> +}
Nobody needs this so I'd just provide inode_state_replace().
> +static inline void inode_state_replace(struct inode *inode,
> + enum inode_state_flags_enum clearflags,
> + enum inode_state_flags_enum setflags)
> +{
> + lockdep_assert_held(&inode->i_lock);
> + inode_state_replace_raw(inode, clearflags, setflags);
> +}
> +
> static inline void inode_set_cached_link(struct inode *inode, char *link, int linklen)
> {
> VFS_WARN_ON_INODE(strlen(link) != linklen, inode);
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-10 14:44 ` Jan Kara
@ 2025-10-10 15:51 ` Mateusz Guzik
2025-10-14 22:24 ` Dave Chinner
2025-10-20 9:43 ` Jan Kara
2025-10-14 21:57 ` Dave Chinner
1 sibling, 2 replies; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-10 15:51 UTC (permalink / raw)
To: Jan Kara
Cc: brauner, viro, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs
On Fri, Oct 10, 2025 at 4:44 PM Jan Kara <jack@suse.cz> wrote:
>
> On Thu 09-10-25 09:59:17, Mateusz Guzik wrote:
> > +static inline void inode_state_set_raw(struct inode *inode,
> > + enum inode_state_flags_enum flags)
> > +{
> > + WRITE_ONCE(inode->i_state, inode->i_state | flags);
> > +}
>
> I think this shouldn't really exist as it is dangerous to use and if we
> deal with XFS, nobody will actually need this function.
>
That's not strictly true, unless you mean code outside of fs/inode.c
First, something is still needed to clear out the state in
inode_init_always_gfp().
Afterwards there are few spots which further modify it without the
spinlock held (for example see insert_inode_locked4()).
My take on the situation is that the current I_NEW et al handling is
crap and the inode hash api is also crap.
For starters freshly allocated inodes should not be starting with 0,
but with I_NEW.
I can agree after the dust settles there should be no _raw thing for
filesystems to use, but getting there is beyond the scope of this
patchset.
> > +static inline void inode_state_set(struct inode *inode,
> > + enum inode_state_flags_enum flags)
> > +{
> > + lockdep_assert_held(&inode->i_lock);
> > + inode_state_set_raw(inode, flags);
> > +}
> > +
> > +static inline void inode_state_clear_raw(struct inode *inode,
> > + enum inode_state_flags_enum flags)
> > +{
> > + WRITE_ONCE(inode->i_state, inode->i_state & ~flags);
> > +}
>
> Ditto here.
>
> > +static inline void inode_state_clear(struct inode *inode,
> > + enum inode_state_flags_enum flags)
> > +{
> > + lockdep_assert_held(&inode->i_lock);
> > + inode_state_clear_raw(inode, flags);
> > +}
> > +
> > +static inline void inode_state_assign_raw(struct inode *inode,
> > + enum inode_state_flags_enum flags)
> > +{
> > + WRITE_ONCE(inode->i_state, flags);
> > +}
> > +
> > +static inline void inode_state_assign(struct inode *inode,
> > + enum inode_state_flags_enum flags)
> > +{
> > + lockdep_assert_held(&inode->i_lock);
> > + inode_state_assign_raw(inode, flags);
> > +}
> > +
> > +static inline void inode_state_replace_raw(struct inode *inode,
> > + enum inode_state_flags_enum clearflags,
> > + enum inode_state_flags_enum setflags)
> > +{
> > + enum inode_state_flags_enum flags;
> > + flags = inode->i_state;
> > + flags &= ~clearflags;
> > + flags |= setflags;
> > + inode_state_assign_raw(inode, flags);
> > +}
>
> Nobody needs this so I'd just provide inode_state_replace().
>
The unused _raw variants are provided for consistency for the time
being. I do expect some of them to die later.
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-10 15:51 ` Mateusz Guzik
@ 2025-10-14 22:24 ` Dave Chinner
2025-10-15 5:46 ` Mateusz Guzik
2025-10-20 9:43 ` Jan Kara
1 sibling, 1 reply; 41+ messages in thread
From: Dave Chinner @ 2025-10-14 22:24 UTC (permalink / raw)
To: Mateusz Guzik
Cc: Jan Kara, brauner, viro, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Fri, Oct 10, 2025 at 05:51:06PM +0200, Mateusz Guzik wrote:
> On Fri, Oct 10, 2025 at 4:44 PM Jan Kara <jack@suse.cz> wrote:
> >
> > On Thu 09-10-25 09:59:17, Mateusz Guzik wrote:
> > > +static inline void inode_state_set_raw(struct inode *inode,
> > > + enum inode_state_flags_enum flags)
> > > +{
> > > + WRITE_ONCE(inode->i_state, inode->i_state | flags);
> > > +}
> >
> > I think this shouldn't really exist as it is dangerous to use and if we
> > deal with XFS, nobody will actually need this function.
> >
>
> That's not strictly true, unless you mean code outside of fs/inode.c
>
> First, something is still needed to clear out the state in
> inode_init_always_gfp().
>
> Afterwards there are few spots which further modify it without the
> spinlock held (for example see insert_inode_locked4()).
>
> My take on the situation is that the current I_NEW et al handling is
> crap and the inode hash api is also crap.
The inode hash implementation is crap, too. The historically poor
scalability characteristics of the VFS inode cache is the primary
reason we've never considered ever trying to port XFS to use it,
even if we ignore all the inode lifecycle issues that would have to
be solved first...
> For starters freshly allocated inodes should not be starting with 0,
> but with I_NEW.
Not all inodes are cached filesystem inodes. e.g. anonymous inodes
are initialised to inode->i_state = I_DIRTY. pipe inodes also start
at I_DIRTY. socket inodes don't touch i_state at init, so they
essentially init i_state = 0....
IOWs, the initial inode state depends on what the inode is being
used for, and I_NEW is only relevant to inodes that are cached and
can be found before the filesystem has fully initialised the VFS
inode.
-Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-14 22:24 ` Dave Chinner
@ 2025-10-15 5:46 ` Mateusz Guzik
2025-10-15 22:06 ` Dave Chinner
0 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-15 5:46 UTC (permalink / raw)
To: Dave Chinner
Cc: Jan Kara, brauner, viro, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Wed, Oct 15, 2025 at 12:24 AM Dave Chinner <david@fromorbit.com> wrote:
>
> On Fri, Oct 10, 2025 at 05:51:06PM +0200, Mateusz Guzik wrote:
> > On Fri, Oct 10, 2025 at 4:44 PM Jan Kara <jack@suse.cz> wrote:
> > >
> > > On Thu 09-10-25 09:59:17, Mateusz Guzik wrote:
> > > > +static inline void inode_state_set_raw(struct inode *inode,
> > > > + enum inode_state_flags_enum flags)
> > > > +{
> > > > + WRITE_ONCE(inode->i_state, inode->i_state | flags);
> > > > +}
> > >
> > > I think this shouldn't really exist as it is dangerous to use and if we
> > > deal with XFS, nobody will actually need this function.
> > >
> >
> > That's not strictly true, unless you mean code outside of fs/inode.c
> >
> > First, something is still needed to clear out the state in
> > inode_init_always_gfp().
> >
> > Afterwards there are few spots which further modify it without the
> > spinlock held (for example see insert_inode_locked4()).
> >
> > My take on the situation is that the current I_NEW et al handling is
> > crap and the inode hash api is also crap.
>
> The inode hash implementation is crap, too. The historically poor
> scalability characteristics of the VFS inode cache is the primary
> reason we've never considered ever trying to port XFS to use it,
> even if we ignore all the inode lifecycle issues that would have to
> be solved first...
>
I don't know of anyone defending the inode hash tho. The performance
of the thing was already bashed a few times, I did not see anyone
dunking on the API ;)
> > For starters freshly allocated inodes should not be starting with 0,
> > but with I_NEW.
>
> Not all inodes are cached filesystem inodes. e.g. anonymous inodes
> are initialised to inode->i_state = I_DIRTY. pipe inodes also start
> at I_DIRTY. socket inodes don't touch i_state at init, so they
> essentially init i_state = 0....
>
> IOWs, the initial inode state depends on what the inode is being
> used for, and I_NEW is only relevant to inodes that are cached and
> can be found before the filesystem has fully initialised the VFS
> inode.
>
Well it is true that currently the I_NEW flag is there to help out
entities like the hash inode hash.
I'm looking to change it into a generic indicator of an uninitialized
inode. This is completely harmless for the consumers which currently
operate on inodes which never had the flag.
Here is one use: I'd like to introduce a mandatory routine to call
when the filesystem at hand claims the inode is ready to use.
Said routine would have 2 main purposes:
- validate the state of the inode (for example that a valid mode is
set; this would have caught some of the syzkaller bugs from the get
go)
- pre-compute a bunch of stuff, for example see this crapper:
static inline int do_inode_permission(struct mnt_idmap *idmap,
struct inode *inode, int mask)
{
if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
if (likely(inode->i_op->permission))
return inode->i_op->permission(idmap, inode,
mask);
/* This gets set once for the inode lifetime */
spin_lock(&inode->i_lock);
inode->i_opflags |= IOP_FASTPERM;
spin_unlock(&inode->i_lock);
}
return generic_permission(idmap, inode, mask);
}
The IOP_FASTPERM could be computed by the new routine, so this would
simplify to:
static inline int do_inode_permission(struct mnt_idmap *idmap,
struct inode *inode, int mask)
{
if (unlikely(!(inode->i_opflags & IOP_FASTPERM)))
return inode->i_op->permission(idmap, inode, mask);
return generic_permission(idmap, inode, mask);
}
The routine would assert the inode is I_NEW and would clear the flag,
replacing it with something else indicating the inode is indeed ready
to use.
While technically the I_NEW change is not necessarily to get there, I
do think it makes things cleaner.
Note unlock_new_inode() and similar are not mandatory to call.
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-15 5:46 ` Mateusz Guzik
@ 2025-10-15 22:06 ` Dave Chinner
0 siblings, 0 replies; 41+ messages in thread
From: Dave Chinner @ 2025-10-15 22:06 UTC (permalink / raw)
To: Mateusz Guzik
Cc: Jan Kara, brauner, viro, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Wed, Oct 15, 2025 at 07:46:39AM +0200, Mateusz Guzik wrote:
> On Wed, Oct 15, 2025 at 12:24 AM Dave Chinner <david@fromorbit.com> wrote:
> >
> > On Fri, Oct 10, 2025 at 05:51:06PM +0200, Mateusz Guzik wrote:
> > > On Fri, Oct 10, 2025 at 4:44 PM Jan Kara <jack@suse.cz> wrote:
> > > >
> > > > On Thu 09-10-25 09:59:17, Mateusz Guzik wrote:
> > > > > +static inline void inode_state_set_raw(struct inode *inode,
> > > > > + enum inode_state_flags_enum flags)
> > > > > +{
> > > > > + WRITE_ONCE(inode->i_state, inode->i_state | flags);
> > > > > +}
> > > >
> > > > I think this shouldn't really exist as it is dangerous to use and if we
> > > > deal with XFS, nobody will actually need this function.
> > > >
> > >
> > > That's not strictly true, unless you mean code outside of fs/inode.c
> > >
> > > First, something is still needed to clear out the state in
> > > inode_init_always_gfp().
> > >
> > > Afterwards there are few spots which further modify it without the
> > > spinlock held (for example see insert_inode_locked4()).
> > >
> > > My take on the situation is that the current I_NEW et al handling is
> > > crap and the inode hash api is also crap.
> >
> > The inode hash implementation is crap, too. The historically poor
> > scalability characteristics of the VFS inode cache is the primary
> > reason we've never considered ever trying to port XFS to use it,
> > even if we ignore all the inode lifecycle issues that would have to
> > be solved first...
> >
>
> I don't know of anyone defending the inode hash tho. The performance
> of the thing was already bashed a few times, I did not see anyone
> dunking on the API ;)
I think it goes without saying that the amount of
similar-but-slightly-different-and-inconsistently-named functions
that have simply grown organically as individual fs needs have
occurred has resulted in a bit of a mess that nobody really wants to
tackle... :/
> > > For starters freshly allocated inodes should not be starting with 0,
> > > but with I_NEW.
> >
> > Not all inodes are cached filesystem inodes. e.g. anonymous inodes
> > are initialised to inode->i_state = I_DIRTY. pipe inodes also start
> > at I_DIRTY. socket inodes don't touch i_state at init, so they
> > essentially init i_state = 0....
> >
> > IOWs, the initial inode state depends on what the inode is being
> > used for, and I_NEW is only relevant to inodes that are cached and
> > can be found before the filesystem has fully initialised the VFS
> > inode.
> >
>
> Well it is true that currently the I_NEW flag is there to help out
> entities like the hash inode hash.
>
> I'm looking to change it into a generic indicator of an uninitialized
> inode. This is completely harmless for the consumers which currently
> operate on inodes which never had the flag.
>
> Here is one use: I'd like to introduce a mandatory routine to call
> when the filesystem at hand claims the inode is ready to use.
I like the idea, but I don't think that overloading I_NEW is the
right thing to do nor is it that simple.
e.g. We added the I_CREATING state years ago as a subset of I_NEW so
that VFS inodes being instantiated can't be found -at all- by the
open-by-handle interface doing direct inode hash lookups. However,
only some of the inode hash APIs add this flag, and only overlay as
a filesystem adds it in certain circumstances.
IOWs, even during initialisation, different filesystems need to
behave differently w.r.t. how the core VFS performs various
operations on the inode during the initialisation stage...
FWIW, XFS has the XFS_INEW state that wraps around the outside of
the VFS inode initialisation process that prevents it from being
found via any type of inode cache lookup (internal or external)
until the inode is fully initialised.
IOWs, features that XFS has
supported for 25+ years (like open-by-handle) is supported natively
by the XFS inode cache and the XFS inode life cycle state machine.
In contrast, The way the VFS inode cache handles stuff like this is
very much a hacked-in "oops we didn't think of that" after-thought
that doesn't actually cover all the different APIs or filesystems...
> Said routine would have 2 main purposes:
> - validate the state of the inode (for example that a valid mode is
> set; this would have caught some of the syzkaller bugs from the get
> go)
I think that's going to be harder than it sounds (speaking as the
architect of the comprehensive on-disk metadata validation
infrastructure in XFS).
> - pre-compute a bunch of stuff, for example see this crapper:
>
> static inline int do_inode_permission(struct mnt_idmap *idmap,
> struct inode *inode, int mask)
> {
> if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
> if (likely(inode->i_op->permission))
> return inode->i_op->permission(idmap, inode,
> mask);
>
> /* This gets set once for the inode lifetime */
> spin_lock(&inode->i_lock);
> inode->i_opflags |= IOP_FASTPERM;
> spin_unlock(&inode->i_lock);
> }
> return generic_permission(idmap, inode, mask);
> }
Yup, that would be useful.
> Note unlock_new_inode() and similar are not mandatory to call.
To a point. i.e. if you are using a VFS inode hash implemtation that
sets I_NEW, then it is definitely mandatory to call
unlock_new_inode(). Documentation/filesystems/porting.rst even says
that.
However, if you aren't using a VFS inode cache implemenation that
sets I_NEW, then you've got to set it yourself and clear it
appropriately so the rest of the VFS functionality does the right
thing whilst the inode is published but still being initialised.
e.g. putting an inode still undergoing initialisation on the
sb->s_inodes list without it being marked as I_NEW is, quite simply,
a bug.
Hence it may not be mandatory to use unlock_new_inode(), but if you
are publishing a partially initialised inode on any VFS list or
cache, you still need to be doing the right thing w.r.t. locking,
I_NEW, I_CREATING and calling unlock_new_inode() during inode
initialisation and cache lookups.
-Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-10 15:51 ` Mateusz Guzik
2025-10-14 22:24 ` Dave Chinner
@ 2025-10-20 9:43 ` Jan Kara
1 sibling, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-20 9:43 UTC (permalink / raw)
To: Mateusz Guzik
Cc: Jan Kara, brauner, viro, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Fri 10-10-25 17:51:06, Mateusz Guzik wrote:
> On Fri, Oct 10, 2025 at 4:44 PM Jan Kara <jack@suse.cz> wrote:
> >
> > On Thu 09-10-25 09:59:17, Mateusz Guzik wrote:
> > > +static inline void inode_state_set_raw(struct inode *inode,
> > > + enum inode_state_flags_enum flags)
> > > +{
> > > + WRITE_ONCE(inode->i_state, inode->i_state | flags);
> > > +}
> >
> > I think this shouldn't really exist as it is dangerous to use and if we
> > deal with XFS, nobody will actually need this function.
> >
>
> That's not strictly true, unless you mean code outside of fs/inode.c
>
> First, something is still needed to clear out the state in
> inode_init_always_gfp().
>
> Afterwards there are few spots which further modify it without the
> spinlock held (for example see insert_inode_locked4()).
>
> My take on the situation is that the current I_NEW et al handling is
> crap and the inode hash api is also crap.
>
> For starters freshly allocated inodes should not be starting with 0,
> but with I_NEW.
>
> I can agree after the dust settles there should be no _raw thing for
> filesystems to use, but getting there is beyond the scope of this
> patchset.
OK, then we are on the same page wrt the final goal. I can bear the raw
variants in the tree for some time if that makes the whole transition
easier.
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 03/14] fs: provide accessors for ->i_state
2025-10-10 14:44 ` Jan Kara
2025-10-10 15:51 ` Mateusz Guzik
@ 2025-10-14 21:57 ` Dave Chinner
1 sibling, 0 replies; 41+ messages in thread
From: Dave Chinner @ 2025-10-14 21:57 UTC (permalink / raw)
To: Jan Kara
Cc: Mateusz Guzik, brauner, viro, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Fri, Oct 10, 2025 at 04:44:19PM +0200, Jan Kara wrote:
> On Thu 09-10-25 09:59:17, Mateusz Guzik wrote:
> > +static inline void inode_state_set_raw(struct inode *inode,
> > + enum inode_state_flags_enum flags)
> > +{
> > + WRITE_ONCE(inode->i_state, inode->i_state | flags);
> > +}
>
> I think this shouldn't really exist as it is dangerous to use and if we
> deal with XFS, nobody will actually need this function.
XFS does it's own inode caching outside the VFS, so for the moment
it needs to have access to the same VFS inode initialisation APIs as
the core VFS inode cache instantiation functions to maintain the
same externally visible behaviours.
Yes, if we change how the VFS inode caches initialise inodes, we
have to update the XFS code, but that's always been the case. This
isn't very hard to do....
Keep in mind that XFS has been caching inodes outside the VFS and
doing external state initialisation since it was first ported to
Linux (i.e. ~25 years ago). It's kinda strange to suddenly hear
people claim that this sort of VFS inode state manipulation thing is
"too dangerous" to allow anyone to use given how long we've actually
been doing this....
-Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 04/14] Coccinelle-based conversion to use ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (2 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 03/14] fs: provide accessors for ->i_state Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:07 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 05/14] Manual conversion to use ->i_state accessors of all places not covered by coccinelle Mateusz Guzik
` (11 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
All places were patched by coccinelle with the default expecting that
->i_lock is held, afterwards entries got fixed up by hand to use
unlocked variants as needed.
The script:
@@
expression inode, flags;
@@
- inode->i_state & flags
+ inode_state_read(inode) & flags
@@
expression inode, flags;
@@
- inode->i_state &= ~flags
+ inode_state_clear(inode, flags)
@@
expression inode, flag1, flag2;
@@
- inode->i_state &= ~flag1 & ~flag2
+ inode_state_clear(inode, flag1 | flag2)
@@
expression inode, flags;
@@
- inode->i_state |= flags
+ inode_state_set(inode, flags)
@@
expression inode, flags;
@@
- inode->i_state = flags
+ inode_state_assign(inode, flags)
@@
expression inode, flags;
@@
- flags = inode->i_state
+ flags = inode_state_read(inode)
@@
expression inode, flags;
@@
- READ_ONCE(inode->i_state) & flags
+ inode_state_read(inode) & flags
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
block/bdev.c | 4 +-
drivers/dax/super.c | 2 +-
fs/9p/vfs_inode.c | 2 +-
fs/9p/vfs_inode_dotl.c | 2 +-
fs/affs/inode.c | 2 +-
fs/afs/dynroot.c | 6 +-
fs/afs/inode.c | 6 +-
fs/befs/linuxvfs.c | 2 +-
fs/bfs/inode.c | 2 +-
fs/buffer.c | 4 +-
fs/coda/cnode.c | 4 +-
fs/cramfs/inode.c | 2 +-
fs/crypto/keyring.c | 2 +-
fs/crypto/keysetup.c | 2 +-
fs/dcache.c | 8 +--
fs/drop_caches.c | 2 +-
fs/ecryptfs/inode.c | 6 +-
fs/efs/inode.c | 2 +-
fs/erofs/inode.c | 2 +-
fs/ext2/inode.c | 2 +-
fs/freevxfs/vxfs_inode.c | 2 +-
fs/fs-writeback.c | 120 +++++++++++++++++------------------
fs/fuse/inode.c | 4 +-
fs/hfs/btree.c | 2 +-
fs/hfs/inode.c | 2 +-
fs/hfsplus/super.c | 2 +-
fs/hostfs/hostfs_kern.c | 2 +-
fs/hpfs/dir.c | 2 +-
fs/hpfs/inode.c | 2 +-
fs/inode.c | 92 +++++++++++++--------------
fs/isofs/inode.c | 2 +-
fs/jffs2/fs.c | 4 +-
fs/jfs/file.c | 4 +-
fs/jfs/inode.c | 2 +-
fs/jfs/jfs_txnmgr.c | 2 +-
fs/kernfs/inode.c | 2 +-
fs/libfs.c | 6 +-
fs/minix/inode.c | 2 +-
fs/namei.c | 8 +--
fs/netfs/misc.c | 8 +--
fs/netfs/read_single.c | 6 +-
fs/nfs/inode.c | 2 +-
fs/nfs/pnfs.c | 2 +-
fs/nfsd/vfs.c | 2 +-
fs/notify/fsnotify.c | 2 +-
fs/ntfs3/inode.c | 2 +-
fs/ocfs2/dlmglue.c | 2 +-
fs/ocfs2/inode.c | 4 +-
fs/omfs/inode.c | 2 +-
fs/openpromfs/inode.c | 2 +-
fs/orangefs/inode.c | 2 +-
fs/orangefs/orangefs-utils.c | 6 +-
fs/pipe.c | 2 +-
fs/qnx4/inode.c | 2 +-
fs/qnx6/inode.c | 2 +-
fs/quota/dquot.c | 2 +-
fs/romfs/super.c | 2 +-
fs/squashfs/inode.c | 2 +-
fs/sync.c | 2 +-
fs/ubifs/file.c | 2 +-
fs/ubifs/super.c | 2 +-
fs/udf/inode.c | 2 +-
fs/ufs/inode.c | 2 +-
fs/zonefs/super.c | 4 +-
mm/backing-dev.c | 2 +-
security/landlock/fs.c | 2 +-
66 files changed, 199 insertions(+), 199 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index 810707cca970..c33667e30eb7 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -67,7 +67,7 @@ static void bdev_write_inode(struct block_device *bdev)
int ret;
spin_lock(&inode->i_lock);
- while (inode->i_state & I_DIRTY) {
+ while (inode_state_read(inode) & I_DIRTY) {
spin_unlock(&inode->i_lock);
ret = write_inode_now(inode, true);
if (ret)
@@ -1265,7 +1265,7 @@ void sync_bdevs(bool wait)
struct block_device *bdev;
spin_lock(&inode->i_lock);
- if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) ||
+ if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW) ||
mapping->nrpages == 0) {
spin_unlock(&inode->i_lock);
continue;
diff --git a/drivers/dax/super.c b/drivers/dax/super.c
index d7714d8afb0f..c00b9dff4a06 100644
--- a/drivers/dax/super.c
+++ b/drivers/dax/super.c
@@ -433,7 +433,7 @@ static struct dax_device *dax_dev_get(dev_t devt)
return NULL;
dax_dev = to_dax_dev(inode);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
set_bit(DAXDEV_ALIVE, &dax_dev->flags);
inode->i_cdev = &dax_dev->cdev;
inode->i_mode = S_IFCHR;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index d0c77ec31b1d..8666c9c62258 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -422,7 +422,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode, st);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
/*
* initialize the inode with the stat info
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index be297e335468..1661a25f2772 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -112,7 +112,7 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode_dotl, st);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
/*
* initialize the inode with the stat info
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 0210df8d3500..0bfc7d151dcd 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -29,7 +29,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
pr_debug("affs_iget(%lu)\n", inode->i_ino);
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
index 8c6130789fde..475012555100 100644
--- a/fs/afs/dynroot.c
+++ b/fs/afs/dynroot.c
@@ -64,7 +64,7 @@ static struct inode *afs_iget_pseudo_dir(struct super_block *sb, ino_t ino)
vnode = AFS_FS_I(inode);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
netfs_inode_init(&vnode->netfs, NULL, false);
simple_inode_init_ts(inode);
set_nlink(inode, 2);
@@ -258,7 +258,7 @@ static struct dentry *afs_lookup_atcell(struct inode *dir, struct dentry *dentry
vnode = AFS_FS_I(inode);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
netfs_inode_init(&vnode->netfs, NULL, false);
simple_inode_init_ts(inode);
set_nlink(inode, 1);
@@ -383,7 +383,7 @@ struct inode *afs_dynroot_iget_root(struct super_block *sb)
vnode = AFS_FS_I(inode);
/* there shouldn't be an existing inode */
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
netfs_inode_init(&vnode->netfs, NULL, false);
simple_inode_init_ts(inode);
set_nlink(inode, 2);
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index e1cb17b85791..2fe2ccf59c7a 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -579,7 +579,7 @@ struct inode *afs_iget(struct afs_operation *op, struct afs_vnode_param *vp)
inode, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
/* deal with an existing inode */
- if (!(inode->i_state & I_NEW)) {
+ if (!(inode_state_read_once(inode) & I_NEW)) {
_leave(" = %p", inode);
return inode;
}
@@ -639,7 +639,7 @@ struct inode *afs_root_iget(struct super_block *sb, struct key *key)
_debug("GOT ROOT INODE %p { vl=%llx }", inode, as->volume->vid);
- BUG_ON(!(inode->i_state & I_NEW));
+ BUG_ON(!(inode_state_read_once(inode) & I_NEW));
vnode = AFS_FS_I(inode);
vnode->cb_v_check = atomic_read(&as->volume->cb_v_break);
@@ -748,7 +748,7 @@ void afs_evict_inode(struct inode *inode)
if ((S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)) &&
- (inode->i_state & I_DIRTY) &&
+ (inode_state_read_once(inode) & I_DIRTY) &&
!sbi->dyn_root) {
struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL,
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 8f430ff8e445..9fcfdd6b8189 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -307,7 +307,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
befs_ino = BEFS_I(inode);
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 1d41ce477df5..cb406a6ee811 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -42,7 +42,7 @@ struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {
diff --git a/fs/buffer.c b/fs/buffer.c
index 6a8752f7bbed..17b8ce567cc3 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -611,9 +611,9 @@ int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end,
return err;
ret = sync_mapping_buffers(inode->i_mapping);
- if (!(inode->i_state & I_DIRTY_ALL))
+ if (!(inode_state_read_once(inode) & I_DIRTY_ALL))
goto out;
- if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ if (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC))
goto out;
err = sync_inode_metadata(inode, 1);
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 62a3d2565c26..70bb0579b40c 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -70,7 +70,7 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
if (!inode)
return ERR_PTR(-ENOMEM);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
cii = ITOC(inode);
/* we still need to set i_ino for things like stat(2) */
inode->i_ino = hash;
@@ -148,7 +148,7 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
/* we should never see newly created inodes because we intentionally
* fail in the initialization callback */
- BUG_ON(inode->i_state & I_NEW);
+ BUG_ON(inode_state_read_once(inode) & I_NEW);
return inode;
}
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index ca54bf24b719..e54ebe402df7 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -95,7 +95,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb,
inode = iget_locked(sb, cramino(cramfs_inode, offset));
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
switch (cramfs_inode->mode & S_IFMT) {
diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
index 3adbd7167055..5e939ea3ac28 100644
--- a/fs/crypto/keyring.c
+++ b/fs/crypto/keyring.c
@@ -945,7 +945,7 @@ static void evict_dentries_for_decrypted_inodes(struct fscrypt_master_key *mk)
list_for_each_entry(ci, &mk->mk_decrypted_inodes, ci_master_key_link) {
inode = ci->ci_inode;
spin_lock(&inode->i_lock);
- if (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) {
+ if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) {
spin_unlock(&inode->i_lock);
continue;
}
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index 4bd3918f50e3..40fa05688d3a 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -834,7 +834,7 @@ int fscrypt_drop_inode(struct inode *inode)
* userspace is still using the files, inodes can be dirtied between
* then and now. We mustn't lose any writes, so skip dirty inodes here.
*/
- if (inode->i_state & I_DIRTY_ALL)
+ if (inode_state_read(inode) & I_DIRTY_ALL)
return 0;
/*
diff --git a/fs/dcache.c b/fs/dcache.c
index 806d6a665124..78ffa7b7e824 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -794,7 +794,7 @@ void d_mark_dontcache(struct inode *inode)
de->d_flags |= DCACHE_DONTCACHE;
spin_unlock(&de->d_lock);
}
- inode->i_state |= I_DONTCACHE;
+ inode_state_set(inode, I_DONTCACHE);
spin_unlock(&inode->i_lock);
}
EXPORT_SYMBOL(d_mark_dontcache);
@@ -1073,7 +1073,7 @@ struct dentry *d_find_alias_rcu(struct inode *inode)
spin_lock(&inode->i_lock);
// ->i_dentry and ->i_rcu are colocated, but the latter won't be
// used without having I_FREEING set, which means no aliases left
- if (likely(!(inode->i_state & I_FREEING) && !hlist_empty(l))) {
+ if (likely(!(inode_state_read(inode) & I_FREEING) && !hlist_empty(l))) {
if (S_ISDIR(inode->i_mode)) {
de = hlist_entry(l->first, struct dentry, d_u.d_alias);
} else {
@@ -1980,12 +1980,12 @@ void d_instantiate_new(struct dentry *entry, struct inode *inode)
security_d_instantiate(entry, inode);
spin_lock(&inode->i_lock);
__d_instantiate(entry, inode);
- WARN_ON(!(inode->i_state & I_NEW));
+ WARN_ON(!(inode_state_read(inode) & I_NEW));
/*
* Pairs with smp_rmb in wait_on_inode().
*/
smp_wmb();
- inode->i_state &= ~I_NEW & ~I_CREATING;
+ inode_state_clear(inode, I_NEW | I_CREATING);
/*
* Pairs with the barrier in prepare_to_wait_event() to make sure
* ___wait_var_event() either sees the bit cleared or
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index 019a8b4eaaf9..49f56a598ecb 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -28,7 +28,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
* inodes without pages but we deliberately won't in case
* we need to reschedule to avoid softlockups.
*/
- if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
+ if ((inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) ||
(mapping_empty(inode->i_mapping) && !need_resched())) {
spin_unlock(&inode->i_lock);
continue;
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index ed1394da8d6b..f3c68ef0271f 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -95,7 +95,7 @@ static struct inode *__ecryptfs_get_inode(struct inode *lower_inode,
iput(lower_inode);
return ERR_PTR(-EACCES);
}
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
iput(lower_inode);
return inode;
@@ -106,7 +106,7 @@ struct inode *ecryptfs_get_inode(struct inode *lower_inode,
{
struct inode *inode = __ecryptfs_get_inode(lower_inode, sb);
- if (!IS_ERR(inode) && (inode->i_state & I_NEW))
+ if (!IS_ERR(inode) && (inode_state_read_once(inode) & I_NEW))
unlock_new_inode(inode);
return inode;
@@ -364,7 +364,7 @@ static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry,
}
}
- if (inode->i_state & I_NEW)
+ if (inode_state_read_once(inode) & I_NEW)
unlock_new_inode(inode);
return d_splice_alias(inode, dentry);
}
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 462619e59766..28407578f83a 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -62,7 +62,7 @@ struct inode *efs_iget(struct super_block *super, unsigned long ino)
inode = iget_locked(super, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
in = INODE_INFO(inode);
diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
index cb780c095d28..bce98c845a18 100644
--- a/fs/erofs/inode.c
+++ b/fs/erofs/inode.c
@@ -295,7 +295,7 @@ struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid)
if (!inode)
return ERR_PTR(-ENOMEM);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
int err = erofs_fill_inode(inode);
if (err) {
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index e10c376843d7..dbfe9098a124 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1398,7 +1398,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
ei = EXT2_I(inode);
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index 20600e9ea202..21fc94b98209 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -258,7 +258,7 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
ip = iget_locked(sbp, ino);
if (!ip)
return ERR_PTR(-ENOMEM);
- if (!(ip->i_state & I_NEW))
+ if (!(inode_state_read_once(ip) & I_NEW))
return ip;
vip = VXFS_INO(ip);
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 9cda19a40ca2..f784d8b09b04 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -121,7 +121,7 @@ static bool inode_io_list_move_locked(struct inode *inode,
{
assert_spin_locked(&wb->list_lock);
assert_spin_locked(&inode->i_lock);
- WARN_ON_ONCE(inode->i_state & I_FREEING);
+ WARN_ON_ONCE(inode_state_read(inode) & I_FREEING);
list_move(&inode->i_io_list, head);
@@ -304,9 +304,9 @@ static void inode_cgwb_move_to_attached(struct inode *inode,
{
assert_spin_locked(&wb->list_lock);
assert_spin_locked(&inode->i_lock);
- WARN_ON_ONCE(inode->i_state & I_FREEING);
+ WARN_ON_ONCE(inode_state_read(inode) & I_FREEING);
- inode->i_state &= ~I_SYNC_QUEUED;
+ inode_state_clear(inode, I_SYNC_QUEUED);
if (wb != &wb->bdi->wb)
list_move(&inode->i_io_list, &wb->b_attached);
else
@@ -408,7 +408,7 @@ static bool inode_do_switch_wbs(struct inode *inode,
* Once I_FREEING or I_WILL_FREE are visible under i_lock, the eviction
* path owns the inode and we shouldn't modify ->i_io_list.
*/
- if (unlikely(inode->i_state & (I_FREEING | I_WILL_FREE)))
+ if (unlikely(inode_state_read(inode) & (I_FREEING | I_WILL_FREE)))
goto skip_switch;
trace_inode_switch_wbs(inode, old_wb, new_wb);
@@ -451,7 +451,7 @@ static bool inode_do_switch_wbs(struct inode *inode,
if (!list_empty(&inode->i_io_list)) {
inode->i_wb = new_wb;
- if (inode->i_state & I_DIRTY_ALL) {
+ if (inode_state_read(inode) & I_DIRTY_ALL) {
/*
* We need to keep b_dirty list sorted by
* dirtied_time_when. However properly sorting the
@@ -480,7 +480,7 @@ static bool inode_do_switch_wbs(struct inode *inode,
* ensures that the new wb is visible if they see !I_WB_SWITCH.
*/
smp_wmb();
- inode->i_state &= ~I_WB_SWITCH;
+ inode_state_clear(inode, I_WB_SWITCH);
xa_unlock_irq(&mapping->i_pages);
spin_unlock(&inode->i_lock);
@@ -601,12 +601,12 @@ static bool inode_prepare_wbs_switch(struct inode *inode,
/* while holding I_WB_SWITCH, no one else can update the association */
spin_lock(&inode->i_lock);
if (!(inode->i_sb->s_flags & SB_ACTIVE) ||
- inode->i_state & (I_WB_SWITCH | I_FREEING | I_WILL_FREE) ||
+ inode_state_read(inode) & (I_WB_SWITCH | I_FREEING | I_WILL_FREE) ||
inode_to_wb(inode) == new_wb) {
spin_unlock(&inode->i_lock);
return false;
}
- inode->i_state |= I_WB_SWITCH;
+ inode_state_set(inode, I_WB_SWITCH);
__iget(inode);
spin_unlock(&inode->i_lock);
@@ -636,7 +636,7 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
struct bdi_writeback *new_wb = NULL;
/* noop if seems to be already in progress */
- if (inode->i_state & I_WB_SWITCH)
+ if (inode_state_read_once(inode) & I_WB_SWITCH)
return;
/* avoid queueing a new switch if too many are already in flight */
@@ -1237,9 +1237,9 @@ static void inode_cgwb_move_to_attached(struct inode *inode,
{
assert_spin_locked(&wb->list_lock);
assert_spin_locked(&inode->i_lock);
- WARN_ON_ONCE(inode->i_state & I_FREEING);
+ WARN_ON_ONCE(inode_state_read(inode) & I_FREEING);
- inode->i_state &= ~I_SYNC_QUEUED;
+ inode_state_clear(inode, I_SYNC_QUEUED);
list_del_init(&inode->i_io_list);
wb_io_lists_depopulated(wb);
}
@@ -1352,7 +1352,7 @@ void inode_io_list_del(struct inode *inode)
wb = inode_to_wb_and_lock_list(inode);
spin_lock(&inode->i_lock);
- inode->i_state &= ~I_SYNC_QUEUED;
+ inode_state_clear(inode, I_SYNC_QUEUED);
list_del_init(&inode->i_io_list);
wb_io_lists_depopulated(wb);
@@ -1410,13 +1410,13 @@ static void redirty_tail_locked(struct inode *inode, struct bdi_writeback *wb)
{
assert_spin_locked(&inode->i_lock);
- inode->i_state &= ~I_SYNC_QUEUED;
+ inode_state_clear(inode, I_SYNC_QUEUED);
/*
* When the inode is being freed just don't bother with dirty list
* tracking. Flush worker will ignore this inode anyway and it will
* trigger assertions in inode_io_list_move_locked().
*/
- if (inode->i_state & I_FREEING) {
+ if (inode_state_read(inode) & I_FREEING) {
list_del_init(&inode->i_io_list);
wb_io_lists_depopulated(wb);
return;
@@ -1450,7 +1450,7 @@ static void inode_sync_complete(struct inode *inode)
{
assert_spin_locked(&inode->i_lock);
- inode->i_state &= ~I_SYNC;
+ inode_state_clear(inode, I_SYNC);
/* If inode is clean an unused, put it into LRU now... */
inode_add_lru(inode);
/* Called with inode->i_lock which ensures memory ordering. */
@@ -1494,7 +1494,7 @@ static int move_expired_inodes(struct list_head *delaying_queue,
spin_lock(&inode->i_lock);
list_move(&inode->i_io_list, &tmp);
moved++;
- inode->i_state |= I_SYNC_QUEUED;
+ inode_state_set(inode, I_SYNC_QUEUED);
spin_unlock(&inode->i_lock);
if (sb_is_blkdev_sb(inode->i_sb))
continue;
@@ -1580,14 +1580,14 @@ void inode_wait_for_writeback(struct inode *inode)
assert_spin_locked(&inode->i_lock);
- if (!(inode->i_state & I_SYNC))
+ if (!(inode_state_read(inode) & I_SYNC))
return;
wq_head = inode_bit_waitqueue(&wqe, inode, __I_SYNC);
for (;;) {
prepare_to_wait_event(wq_head, &wqe.wq_entry, TASK_UNINTERRUPTIBLE);
/* Checking I_SYNC with inode->i_lock guarantees memory ordering. */
- if (!(inode->i_state & I_SYNC))
+ if (!(inode_state_read(inode) & I_SYNC))
break;
spin_unlock(&inode->i_lock);
schedule();
@@ -1613,7 +1613,7 @@ static void inode_sleep_on_writeback(struct inode *inode)
wq_head = inode_bit_waitqueue(&wqe, inode, __I_SYNC);
prepare_to_wait_event(wq_head, &wqe.wq_entry, TASK_UNINTERRUPTIBLE);
/* Checking I_SYNC with inode->i_lock guarantees memory ordering. */
- sleep = !!(inode->i_state & I_SYNC);
+ sleep = !!(inode_state_read(inode) & I_SYNC);
spin_unlock(&inode->i_lock);
if (sleep)
schedule();
@@ -1632,7 +1632,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
struct writeback_control *wbc,
unsigned long dirtied_before)
{
- if (inode->i_state & I_FREEING)
+ if (inode_state_read(inode) & I_FREEING)
return;
/*
@@ -1640,7 +1640,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
* shot. If still dirty, it will be redirty_tail()'ed below. Update
* the dirty time to prevent enqueue and sync it again.
*/
- if ((inode->i_state & I_DIRTY) &&
+ if ((inode_state_read(inode) & I_DIRTY) &&
(wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages))
inode->dirtied_when = jiffies;
@@ -1651,7 +1651,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
* is odd for clean inodes, it can happen for some
* filesystems so handle that gracefully.
*/
- if (inode->i_state & I_DIRTY_ALL)
+ if (inode_state_read(inode) & I_DIRTY_ALL)
redirty_tail_locked(inode, wb);
else
inode_cgwb_move_to_attached(inode, wb);
@@ -1677,17 +1677,17 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
*/
redirty_tail_locked(inode, wb);
}
- } else if (inode->i_state & I_DIRTY) {
+ } else if (inode_state_read(inode) & I_DIRTY) {
/*
* Filesystems can dirty the inode during writeback operations,
* such as delayed allocation during submission or metadata
* updates after data IO completion.
*/
redirty_tail_locked(inode, wb);
- } else if (inode->i_state & I_DIRTY_TIME) {
+ } else if (inode_state_read(inode) & I_DIRTY_TIME) {
inode->dirtied_when = jiffies;
inode_io_list_move_locked(inode, wb, &wb->b_dirty_time);
- inode->i_state &= ~I_SYNC_QUEUED;
+ inode_state_clear(inode, I_SYNC_QUEUED);
} else {
/* The inode is clean. Remove from writeback lists. */
inode_cgwb_move_to_attached(inode, wb);
@@ -1713,7 +1713,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
unsigned dirty;
int ret;
- WARN_ON(!(inode->i_state & I_SYNC));
+ WARN_ON(!(inode_state_read_once(inode) & I_SYNC));
trace_writeback_single_inode_start(inode, wbc, nr_to_write);
@@ -1737,7 +1737,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
* mark_inode_dirty_sync() to notify the filesystem about it and to
* change I_DIRTY_TIME into I_DIRTY_SYNC.
*/
- if ((inode->i_state & I_DIRTY_TIME) &&
+ if ((inode_state_read_once(inode) & I_DIRTY_TIME) &&
(wbc->sync_mode == WB_SYNC_ALL ||
time_after(jiffies, inode->dirtied_time_when +
dirtytime_expire_interval * HZ))) {
@@ -1752,8 +1752,8 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
* after handling timestamp expiration, as that may dirty the inode too.
*/
spin_lock(&inode->i_lock);
- dirty = inode->i_state & I_DIRTY;
- inode->i_state &= ~dirty;
+ dirty = inode_state_read(inode) & I_DIRTY;
+ inode_state_clear(inode, dirty);
/*
* Paired with smp_mb() in __mark_inode_dirty(). This allows
@@ -1769,10 +1769,10 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
smp_mb();
if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
- inode->i_state |= I_DIRTY_PAGES;
- else if (unlikely(inode->i_state & I_PINNING_NETFS_WB)) {
- if (!(inode->i_state & I_DIRTY_PAGES)) {
- inode->i_state &= ~I_PINNING_NETFS_WB;
+ inode_state_set(inode, I_DIRTY_PAGES);
+ else if (unlikely(inode_state_read(inode) & I_PINNING_NETFS_WB)) {
+ if (!(inode_state_read(inode) & I_DIRTY_PAGES)) {
+ inode_state_clear(inode, I_PINNING_NETFS_WB);
wbc->unpinned_netfs_wb = true;
dirty |= I_PINNING_NETFS_WB; /* Cause write_inode */
}
@@ -1808,11 +1808,11 @@ static int writeback_single_inode(struct inode *inode,
spin_lock(&inode->i_lock);
if (!icount_read(inode))
- WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING)));
+ WARN_ON(!(inode_state_read(inode) & (I_WILL_FREE | I_FREEING)));
else
- WARN_ON(inode->i_state & I_WILL_FREE);
+ WARN_ON(inode_state_read(inode) & I_WILL_FREE);
- if (inode->i_state & I_SYNC) {
+ if (inode_state_read(inode) & I_SYNC) {
/*
* Writeback is already running on the inode. For WB_SYNC_NONE,
* that's enough and we can just return. For WB_SYNC_ALL, we
@@ -1823,7 +1823,7 @@ static int writeback_single_inode(struct inode *inode,
goto out;
inode_wait_for_writeback(inode);
}
- WARN_ON(inode->i_state & I_SYNC);
+ WARN_ON(inode_state_read(inode) & I_SYNC);
/*
* If the inode is already fully clean, then there's nothing to do.
*
@@ -1831,11 +1831,11 @@ static int writeback_single_inode(struct inode *inode,
* still under writeback, e.g. due to prior WB_SYNC_NONE writeback. If
* there are any such pages, we'll need to wait for them.
*/
- if (!(inode->i_state & I_DIRTY_ALL) &&
+ if (!(inode_state_read(inode) & I_DIRTY_ALL) &&
(wbc->sync_mode != WB_SYNC_ALL ||
!mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK)))
goto out;
- inode->i_state |= I_SYNC;
+ inode_state_set(inode, I_SYNC);
wbc_attach_and_unlock_inode(wbc, inode);
ret = __writeback_single_inode(inode, wbc);
@@ -1848,18 +1848,18 @@ static int writeback_single_inode(struct inode *inode,
* If the inode is freeing, its i_io_list shoudn't be updated
* as it can be finally deleted at this moment.
*/
- if (!(inode->i_state & I_FREEING)) {
+ if (!(inode_state_read(inode) & I_FREEING)) {
/*
* If the inode is now fully clean, then it can be safely
* removed from its writeback list (if any). Otherwise the
* flusher threads are responsible for the writeback lists.
*/
- if (!(inode->i_state & I_DIRTY_ALL))
+ if (!(inode_state_read(inode) & I_DIRTY_ALL))
inode_cgwb_move_to_attached(inode, wb);
- else if (!(inode->i_state & I_SYNC_QUEUED)) {
- if ((inode->i_state & I_DIRTY))
+ else if (!(inode_state_read(inode) & I_SYNC_QUEUED)) {
+ if ((inode_state_read(inode) & I_DIRTY))
redirty_tail_locked(inode, wb);
- else if (inode->i_state & I_DIRTY_TIME) {
+ else if (inode_state_read(inode) & I_DIRTY_TIME) {
inode->dirtied_when = jiffies;
inode_io_list_move_locked(inode,
wb,
@@ -1968,12 +1968,12 @@ static long writeback_sb_inodes(struct super_block *sb,
* kind writeout is handled by the freer.
*/
spin_lock(&inode->i_lock);
- if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+ if (inode_state_read(inode) & (I_NEW | I_FREEING | I_WILL_FREE)) {
redirty_tail_locked(inode, wb);
spin_unlock(&inode->i_lock);
continue;
}
- if ((inode->i_state & I_SYNC) && wbc.sync_mode != WB_SYNC_ALL) {
+ if ((inode_state_read(inode) & I_SYNC) && wbc.sync_mode != WB_SYNC_ALL) {
/*
* If this inode is locked for writeback and we are not
* doing writeback-for-data-integrity, move it to
@@ -1995,14 +1995,14 @@ static long writeback_sb_inodes(struct super_block *sb,
* are doing WB_SYNC_NONE writeback. So this catches only the
* WB_SYNC_ALL case.
*/
- if (inode->i_state & I_SYNC) {
+ if (inode_state_read(inode) & I_SYNC) {
/* Wait for I_SYNC. This function drops i_lock... */
inode_sleep_on_writeback(inode);
/* Inode may be gone, start again */
spin_lock(&wb->list_lock);
continue;
}
- inode->i_state |= I_SYNC;
+ inode_state_set(inode, I_SYNC);
wbc_attach_and_unlock_inode(&wbc, inode);
write_chunk = writeback_chunk_size(wb, work);
@@ -2040,7 +2040,7 @@ static long writeback_sb_inodes(struct super_block *sb,
*/
tmp_wb = inode_to_wb_and_lock_list(inode);
spin_lock(&inode->i_lock);
- if (!(inode->i_state & I_DIRTY_ALL))
+ if (!(inode_state_read(inode) & I_DIRTY_ALL))
total_wrote++;
requeue_inode(inode, tmp_wb, &wbc, dirtied_before);
inode_sync_complete(inode);
@@ -2546,10 +2546,10 @@ void __mark_inode_dirty(struct inode *inode, int flags)
* We tell ->dirty_inode callback that timestamps need to
* be updated by setting I_DIRTY_TIME in flags.
*/
- if (inode->i_state & I_DIRTY_TIME) {
+ if (inode_state_read_once(inode) & I_DIRTY_TIME) {
spin_lock(&inode->i_lock);
- if (inode->i_state & I_DIRTY_TIME) {
- inode->i_state &= ~I_DIRTY_TIME;
+ if (inode_state_read(inode) & I_DIRTY_TIME) {
+ inode_state_clear(inode, I_DIRTY_TIME);
flags |= I_DIRTY_TIME;
}
spin_unlock(&inode->i_lock);
@@ -2586,16 +2586,16 @@ void __mark_inode_dirty(struct inode *inode, int flags)
*/
smp_mb();
- if ((inode->i_state & flags) == flags)
+ if ((inode_state_read_once(inode) & flags) == flags)
return;
spin_lock(&inode->i_lock);
- if ((inode->i_state & flags) != flags) {
- const int was_dirty = inode->i_state & I_DIRTY;
+ if ((inode_state_read(inode) & flags) != flags) {
+ const int was_dirty = inode_state_read(inode) & I_DIRTY;
inode_attach_wb(inode, NULL);
- inode->i_state |= flags;
+ inode_state_set(inode, flags);
/*
* Grab inode's wb early because it requires dropping i_lock and we
@@ -2614,7 +2614,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
* the inode it will place it on the appropriate superblock
* list, based upon its state.
*/
- if (inode->i_state & I_SYNC_QUEUED)
+ if (inode_state_read(inode) & I_SYNC_QUEUED)
goto out_unlock;
/*
@@ -2625,7 +2625,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
if (inode_unhashed(inode))
goto out_unlock;
}
- if (inode->i_state & I_FREEING)
+ if (inode_state_read(inode) & I_FREEING)
goto out_unlock;
/*
@@ -2640,7 +2640,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
if (dirtytime)
inode->dirtied_time_when = jiffies;
- if (inode->i_state & I_DIRTY)
+ if (inode_state_read(inode) & I_DIRTY)
dirty_list = &wb->b_dirty;
else
dirty_list = &wb->b_dirty_time;
@@ -2737,7 +2737,7 @@ static void wait_sb_inodes(struct super_block *sb)
spin_unlock_irq(&sb->s_inode_wblist_lock);
spin_lock(&inode->i_lock);
- if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) {
+ if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) {
spin_unlock(&inode->i_lock);
spin_lock_irq(&sb->s_inode_wblist_lock);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index d1babf56f254..bbecd0e5855d 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -160,7 +160,7 @@ static void fuse_evict_inode(struct inode *inode)
struct fuse_inode *fi = get_fuse_inode(inode);
/* Will write inode on close/munmap and in all other dirtiers */
- WARN_ON(inode->i_state & I_DIRTY_INODE);
+ WARN_ON(inode_state_read_once(inode) & I_DIRTY_INODE);
if (FUSE_IS_DAX(inode))
dax_break_layout_final(inode);
@@ -505,7 +505,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
if (!inode)
return NULL;
- if ((inode->i_state & I_NEW)) {
+ if ((inode_state_read_once(inode) & I_NEW)) {
inode->i_flags |= S_NOATIME;
if (!fc->writeback_cache || !S_ISREG(attr->mode))
inode->i_flags |= S_NOCMTIME;
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 22e62fe7448b..54c20d01c342 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -42,7 +42,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
tree->inode = iget_locked(sb, id);
if (!tree->inode)
goto free_tree;
- BUG_ON(!(tree->inode->i_state & I_NEW));
+ BUG_ON(!(inode_state_read_once(tree->inode) & I_NEW));
{
struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
HFS_I(tree->inode)->flags = 0;
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 9cd449913dc8..81ad93e6312f 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -412,7 +412,7 @@ struct inode *hfs_iget(struct super_block *sb, struct hfs_cat_key *key, hfs_cat_
return NULL;
}
inode = iget5_locked(sb, cnid, hfs_test_inode, hfs_read_inode, &data);
- if (inode && (inode->i_state & I_NEW))
+ if (inode && (inode_state_read_once(inode) & I_NEW))
unlock_new_inode(inode);
return inode;
}
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 16bc4abc67e0..54e85e25a259 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -65,7 +65,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 1e1acf5775ab..76b643f7d05c 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -581,7 +581,7 @@ static struct inode *hostfs_iget(struct super_block *sb, char *name)
if (!inode)
return ERR_PTR(-ENOMEM);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
unlock_new_inode(inode);
} else {
spin_lock(&inode->i_lock);
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 49dd585c2b17..ceb50b2dc91a 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -247,7 +247,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned in
result = ERR_PTR(-ENOMEM);
goto bail1;
}
- if (result->i_state & I_NEW) {
+ if (inode_state_read_once(result) & I_NEW) {
hpfs_init_inode(result);
if (de->directory)
hpfs_read_inode(result);
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 34008442ee26..93d528f4f4f2 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -196,7 +196,7 @@ void hpfs_write_inode(struct inode *i)
parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir);
if (parent) {
hpfs_inode->i_dirty = 0;
- if (parent->i_state & I_NEW) {
+ if (inode_state_read_once(parent) & I_NEW) {
hpfs_init_inode(parent);
hpfs_read_inode(parent);
unlock_new_inode(parent);
diff --git a/fs/inode.c b/fs/inode.c
index 37fc7a72aba5..f094ed3e6f30 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -233,7 +233,7 @@ int inode_init_always_gfp(struct super_block *sb, struct inode *inode, gfp_t gfp
inode->i_sb = sb;
inode->i_blkbits = sb->s_blocksize_bits;
inode->i_flags = 0;
- inode->i_state = 0;
+ inode_state_assign_raw(inode, 0);
atomic64_set(&inode->i_sequence, 0);
atomic_set(&inode->i_count, 1);
inode->i_op = &empty_iops;
@@ -471,7 +471,7 @@ EXPORT_SYMBOL(set_nlink);
void inc_nlink(struct inode *inode)
{
if (unlikely(inode->i_nlink == 0)) {
- WARN_ON(!(inode->i_state & I_LINKABLE));
+ WARN_ON(!(inode_state_read_once(inode) & I_LINKABLE));
atomic_long_dec(&inode->i_sb->s_remove_count);
}
@@ -532,7 +532,7 @@ EXPORT_SYMBOL(ihold);
static void __inode_add_lru(struct inode *inode, bool rotate)
{
- if (inode->i_state & (I_DIRTY_ALL | I_SYNC | I_FREEING | I_WILL_FREE))
+ if (inode_state_read(inode) & (I_DIRTY_ALL | I_SYNC | I_FREEING | I_WILL_FREE))
return;
if (icount_read(inode))
return;
@@ -544,7 +544,7 @@ static void __inode_add_lru(struct inode *inode, bool rotate)
if (list_lru_add_obj(&inode->i_sb->s_inode_lru, &inode->i_lru))
this_cpu_inc(nr_unused);
else if (rotate)
- inode->i_state |= I_REFERENCED;
+ inode_state_set(inode, I_REFERENCED);
}
struct wait_queue_head *inode_bit_waitqueue(struct wait_bit_queue_entry *wqe,
@@ -577,15 +577,15 @@ static void inode_lru_list_del(struct inode *inode)
static void inode_pin_lru_isolating(struct inode *inode)
{
lockdep_assert_held(&inode->i_lock);
- WARN_ON(inode->i_state & (I_LRU_ISOLATING | I_FREEING | I_WILL_FREE));
- inode->i_state |= I_LRU_ISOLATING;
+ WARN_ON(inode_state_read(inode) & (I_LRU_ISOLATING | I_FREEING | I_WILL_FREE));
+ inode_state_set(inode, I_LRU_ISOLATING);
}
static void inode_unpin_lru_isolating(struct inode *inode)
{
spin_lock(&inode->i_lock);
- WARN_ON(!(inode->i_state & I_LRU_ISOLATING));
- inode->i_state &= ~I_LRU_ISOLATING;
+ WARN_ON(!(inode_state_read(inode) & I_LRU_ISOLATING));
+ inode_state_clear(inode, I_LRU_ISOLATING);
/* Called with inode->i_lock which ensures memory ordering. */
inode_wake_up_bit(inode, __I_LRU_ISOLATING);
spin_unlock(&inode->i_lock);
@@ -597,7 +597,7 @@ static void inode_wait_for_lru_isolating(struct inode *inode)
struct wait_queue_head *wq_head;
lockdep_assert_held(&inode->i_lock);
- if (!(inode->i_state & I_LRU_ISOLATING))
+ if (!(inode_state_read(inode) & I_LRU_ISOLATING))
return;
wq_head = inode_bit_waitqueue(&wqe, inode, __I_LRU_ISOLATING);
@@ -607,14 +607,14 @@ static void inode_wait_for_lru_isolating(struct inode *inode)
* Checking I_LRU_ISOLATING with inode->i_lock guarantees
* memory ordering.
*/
- if (!(inode->i_state & I_LRU_ISOLATING))
+ if (!(inode_state_read(inode) & I_LRU_ISOLATING))
break;
spin_unlock(&inode->i_lock);
schedule();
spin_lock(&inode->i_lock);
}
finish_wait(wq_head, &wqe.wq_entry);
- WARN_ON(inode->i_state & I_LRU_ISOLATING);
+ WARN_ON(inode_state_read(inode) & I_LRU_ISOLATING);
}
/**
@@ -761,11 +761,11 @@ void clear_inode(struct inode *inode)
*/
xa_unlock_irq(&inode->i_data.i_pages);
BUG_ON(!list_empty(&inode->i_data.i_private_list));
- BUG_ON(!(inode->i_state & I_FREEING));
- BUG_ON(inode->i_state & I_CLEAR);
+ BUG_ON(!(inode_state_read_once(inode) & I_FREEING));
+ BUG_ON(inode_state_read_once(inode) & I_CLEAR);
BUG_ON(!list_empty(&inode->i_wb_list));
/* don't need i_lock here, no concurrent mods to i_state */
- inode->i_state = I_FREEING | I_CLEAR;
+ inode_state_assign_raw(inode, I_FREEING | I_CLEAR);
}
EXPORT_SYMBOL(clear_inode);
@@ -786,7 +786,7 @@ static void evict(struct inode *inode)
{
const struct super_operations *op = inode->i_sb->s_op;
- BUG_ON(!(inode->i_state & I_FREEING));
+ BUG_ON(!(inode_state_read_once(inode) & I_FREEING));
BUG_ON(!list_empty(&inode->i_lru));
if (!list_empty(&inode->i_io_list))
@@ -879,12 +879,12 @@ void evict_inodes(struct super_block *sb)
spin_unlock(&inode->i_lock);
continue;
}
- if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+ if (inode_state_read(inode) & (I_NEW | I_FREEING | I_WILL_FREE)) {
spin_unlock(&inode->i_lock);
continue;
}
- inode->i_state |= I_FREEING;
+ inode_state_set(inode, I_FREEING);
inode_lru_list_del(inode);
spin_unlock(&inode->i_lock);
list_add(&inode->i_lru, &dispose);
@@ -938,7 +938,7 @@ static enum lru_status inode_lru_isolate(struct list_head *item,
* sync, or the last page cache deletion will requeue them.
*/
if (icount_read(inode) ||
- (inode->i_state & ~I_REFERENCED) ||
+ (inode_state_read(inode) & ~I_REFERENCED) ||
!mapping_shrinkable(&inode->i_data)) {
list_lru_isolate(lru, &inode->i_lru);
spin_unlock(&inode->i_lock);
@@ -947,8 +947,8 @@ static enum lru_status inode_lru_isolate(struct list_head *item,
}
/* Recently referenced inodes get one more pass */
- if (inode->i_state & I_REFERENCED) {
- inode->i_state &= ~I_REFERENCED;
+ if (inode_state_read(inode) & I_REFERENCED) {
+ inode_state_clear(inode, I_REFERENCED);
spin_unlock(&inode->i_lock);
return LRU_ROTATE;
}
@@ -975,8 +975,8 @@ static enum lru_status inode_lru_isolate(struct list_head *item,
return LRU_RETRY;
}
- WARN_ON(inode->i_state & I_NEW);
- inode->i_state |= I_FREEING;
+ WARN_ON(inode_state_read(inode) & I_NEW);
+ inode_state_set(inode, I_FREEING);
list_lru_isolate_move(lru, &inode->i_lru, freeable);
spin_unlock(&inode->i_lock);
@@ -1025,11 +1025,11 @@ static struct inode *find_inode(struct super_block *sb,
if (!test(inode, data))
continue;
spin_lock(&inode->i_lock);
- if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
+ if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE)) {
__wait_on_freeing_inode(inode, is_inode_hash_locked);
goto repeat;
}
- if (unlikely(inode->i_state & I_CREATING)) {
+ if (unlikely(inode_state_read(inode) & I_CREATING)) {
spin_unlock(&inode->i_lock);
rcu_read_unlock();
return ERR_PTR(-ESTALE);
@@ -1066,11 +1066,11 @@ static struct inode *find_inode_fast(struct super_block *sb,
if (inode->i_sb != sb)
continue;
spin_lock(&inode->i_lock);
- if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
+ if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE)) {
__wait_on_freeing_inode(inode, is_inode_hash_locked);
goto repeat;
}
- if (unlikely(inode->i_state & I_CREATING)) {
+ if (unlikely(inode_state_read(inode) & I_CREATING)) {
spin_unlock(&inode->i_lock);
rcu_read_unlock();
return ERR_PTR(-ESTALE);
@@ -1180,12 +1180,12 @@ 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));
+ WARN_ON(!(inode_state_read(inode) & I_NEW));
/*
* Pairs with smp_rmb in wait_on_inode().
*/
smp_wmb();
- inode->i_state &= ~I_NEW & ~I_CREATING;
+ inode_state_clear(inode, I_NEW | I_CREATING);
/*
* Pairs with the barrier in prepare_to_wait_event() to make sure
* ___wait_var_event() either sees the bit cleared or
@@ -1201,12 +1201,12 @@ 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));
+ WARN_ON(!(inode_state_read(inode) & I_NEW));
/*
* Pairs with smp_rmb in wait_on_inode().
*/
smp_wmb();
- inode->i_state &= ~I_NEW;
+ inode_state_clear(inode, I_NEW);
/*
* Pairs with the barrier in prepare_to_wait_event() to make sure
* ___wait_var_event() either sees the bit cleared or
@@ -1318,7 +1318,7 @@ struct inode *inode_insert5(struct inode *inode, unsigned long hashval,
* caller is responsible for filling in the contents
*/
spin_lock(&inode->i_lock);
- inode->i_state |= I_NEW;
+ inode_state_set(inode, I_NEW);
hlist_add_head_rcu(&inode->i_hash, head);
spin_unlock(&inode->i_lock);
@@ -1460,7 +1460,7 @@ struct inode *iget_locked(struct super_block *sb, unsigned long ino)
if (!old) {
inode->i_ino = ino;
spin_lock(&inode->i_lock);
- inode->i_state = I_NEW;
+ inode_state_assign(inode, I_NEW);
hlist_add_head_rcu(&inode->i_hash, head);
spin_unlock(&inode->i_lock);
spin_unlock(&inode_hash_lock);
@@ -1553,7 +1553,7 @@ EXPORT_SYMBOL(iunique);
struct inode *igrab(struct inode *inode)
{
spin_lock(&inode->i_lock);
- if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) {
+ if (!(inode_state_read(inode) & (I_FREEING | I_WILL_FREE))) {
__iget(inode);
spin_unlock(&inode->i_lock);
} else {
@@ -1749,7 +1749,7 @@ struct inode *find_inode_rcu(struct super_block *sb, unsigned long hashval,
hlist_for_each_entry_rcu(inode, head, i_hash) {
if (inode->i_sb == sb &&
- !(READ_ONCE(inode->i_state) & (I_FREEING | I_WILL_FREE)) &&
+ !(inode_state_read_once(inode) & (I_FREEING | I_WILL_FREE)) &&
test(inode, data))
return inode;
}
@@ -1788,7 +1788,7 @@ struct inode *find_inode_by_ino_rcu(struct super_block *sb,
hlist_for_each_entry_rcu(inode, head, i_hash) {
if (inode->i_ino == ino &&
inode->i_sb == sb &&
- !(READ_ONCE(inode->i_state) & (I_FREEING | I_WILL_FREE)))
+ !(inode_state_read_once(inode) & (I_FREEING | I_WILL_FREE)))
return inode;
}
return NULL;
@@ -1812,7 +1812,7 @@ int insert_inode_locked(struct inode *inode)
if (old->i_sb != sb)
continue;
spin_lock(&old->i_lock);
- if (old->i_state & (I_FREEING|I_WILL_FREE)) {
+ if (inode_state_read(old) & (I_FREEING | I_WILL_FREE)) {
spin_unlock(&old->i_lock);
continue;
}
@@ -1820,13 +1820,13 @@ int insert_inode_locked(struct inode *inode)
}
if (likely(!old)) {
spin_lock(&inode->i_lock);
- inode->i_state |= I_NEW | I_CREATING;
+ inode_state_set(inode, I_NEW | I_CREATING);
hlist_add_head_rcu(&inode->i_hash, head);
spin_unlock(&inode->i_lock);
spin_unlock(&inode_hash_lock);
return 0;
}
- if (unlikely(old->i_state & I_CREATING)) {
+ if (unlikely(inode_state_read(old) & I_CREATING)) {
spin_unlock(&old->i_lock);
spin_unlock(&inode_hash_lock);
return -EBUSY;
@@ -1851,7 +1851,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
might_sleep();
- inode->i_state |= I_CREATING;
+ inode_state_set_raw(inode, I_CREATING);
old = inode_insert5(inode, hashval, test, NULL, data);
if (old != inode) {
@@ -1886,7 +1886,7 @@ static void iput_final(struct inode *inode)
unsigned long state;
int drop;
- WARN_ON(inode->i_state & I_NEW);
+ WARN_ON(inode_state_read(inode) & I_NEW);
VFS_BUG_ON_INODE(atomic_read(&inode->i_count) != 0, inode);
if (op->drop_inode)
@@ -1895,7 +1895,7 @@ static void iput_final(struct inode *inode)
drop = inode_generic_drop(inode);
if (!drop &&
- !(inode->i_state & I_DONTCACHE) &&
+ !(inode_state_read(inode) & I_DONTCACHE) &&
(sb->s_flags & SB_ACTIVE)) {
__inode_add_lru(inode, true);
spin_unlock(&inode->i_lock);
@@ -1908,7 +1908,7 @@ static void iput_final(struct inode *inode)
*/
VFS_BUG_ON_INODE(atomic_read(&inode->i_count) != 0, inode);
- state = inode->i_state;
+ state = inode_state_read(inode);
if (!drop) {
WRITE_ONCE(inode->i_state, state | I_WILL_FREE);
spin_unlock(&inode->i_lock);
@@ -1916,7 +1916,7 @@ static void iput_final(struct inode *inode)
write_inode_now(inode, 1);
spin_lock(&inode->i_lock);
- state = inode->i_state;
+ state = inode_state_read(inode);
WARN_ON(state & I_NEW);
state &= ~I_WILL_FREE;
}
@@ -1946,7 +1946,7 @@ void iput(struct inode *inode)
retry:
lockdep_assert_not_held(&inode->i_lock);
- VFS_BUG_ON_INODE(inode->i_state & I_CLEAR, inode);
+ VFS_BUG_ON_INODE(inode_state_read_once(inode) & 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
@@ -1957,14 +1957,14 @@ void iput(struct inode *inode)
if (atomic_add_unless(&inode->i_count, -1, 1))
return;
- if ((inode->i_state & I_DIRTY_TIME) && inode->i_nlink) {
+ if ((inode_state_read_once(inode) & 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)) {
+ if (unlikely((inode_state_read(inode) & I_DIRTY_TIME) && inode->i_nlink)) {
spin_unlock(&inode->i_lock);
goto retry;
}
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 6f0e6b19383c..0d51f57f7ad7 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1515,7 +1515,7 @@ struct inode *__isofs_iget(struct super_block *sb,
if (!inode)
return ERR_PTR(-ENOMEM);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
ret = isofs_read_inode(inode, relocated);
if (ret < 0) {
iget_failed(inode);
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index d175cccb7c55..764bba8ba999 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -265,7 +265,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
f = JFFS2_INODE_INFO(inode);
@@ -373,7 +373,7 @@ void jffs2_dirty_inode(struct inode *inode, int flags)
{
struct iattr iattr;
- if (!(inode->i_state & I_DIRTY_DATASYNC)) {
+ if (!(inode_state_read_once(inode) & I_DIRTY_DATASYNC)) {
jffs2_dbg(2, "%s(): not calling setattr() for ino #%lu\n",
__func__, inode->i_ino);
return;
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index 2a4a288b821c..87ad042221e7 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -26,8 +26,8 @@ int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
return rc;
inode_lock(inode);
- if (!(inode->i_state & I_DIRTY_ALL) ||
- (datasync && !(inode->i_state & I_DIRTY_DATASYNC))) {
+ if (!(inode_state_read_once(inode) & I_DIRTY_ALL) ||
+ (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC))) {
/* Make sure committed changes hit the disk */
jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1);
inode_unlock(inode);
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 21f3d029da7d..4709762713ef 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -29,7 +29,7 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
ret = diRead(inode);
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 7840a03e5bcb..c16578af3a77 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -1287,7 +1287,7 @@ int txCommit(tid_t tid, /* transaction identifier */
* to verify this, only a trivial s/I_LOCK/I_SYNC/ was done.
* Joern
*/
- if (tblk->u.ip->i_state & I_SYNC)
+ if (inode_state_read_once(tblk->u.ip) & I_SYNC)
tblk->xflag &= ~COMMIT_LAZY;
}
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index 457f91c412d4..a36aaee98dce 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -251,7 +251,7 @@ struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn)
struct inode *inode;
inode = iget_locked(sb, kernfs_ino(kn));
- if (inode && (inode->i_state & I_NEW))
+ if (inode && (inode_state_read_once(inode) & I_NEW))
kernfs_init_inode(kn, inode);
return inode;
diff --git a/fs/libfs.c b/fs/libfs.c
index ce8c496a6940..96e3d7fc7fc6 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1542,9 +1542,9 @@ int __generic_file_fsync(struct file *file, loff_t start, loff_t end,
inode_lock(inode);
ret = sync_mapping_buffers(inode->i_mapping);
- if (!(inode->i_state & I_DIRTY_ALL))
+ if (!(inode_state_read_once(inode) & I_DIRTY_ALL))
goto out;
- if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ if (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC))
goto out;
err = sync_inode_metadata(inode, 1);
@@ -1664,7 +1664,7 @@ struct inode *alloc_anon_inode(struct super_block *s)
* list because mark_inode_dirty() will think
* that it already _is_ on the dirty list.
*/
- inode->i_state = I_DIRTY;
+ inode_state_assign_raw(inode, I_DIRTY);
/*
* Historically anonymous inodes don't have a type at all and
* userspace has come to rely on this.
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 32db676127a9..f220d0e4aedf 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -589,7 +589,7 @@ struct inode *minix_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
if (INODE_VERSION(inode) == MINIX_V1)
diff --git a/fs/namei.c b/fs/namei.c
index 7377020a2cba..354a9e844721 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4036,7 +4036,7 @@ int vfs_tmpfile(struct mnt_idmap *idmap,
inode = file_inode(file);
if (!(open_flag & O_EXCL)) {
spin_lock(&inode->i_lock);
- inode->i_state |= I_LINKABLE;
+ inode_state_set(inode, I_LINKABLE);
spin_unlock(&inode->i_lock);
}
security_inode_post_create_tmpfile(idmap, inode);
@@ -4931,7 +4931,7 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
inode_lock(inode);
/* Make sure we don't allow creating hardlink to an unlinked file */
- if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
+ if (inode->i_nlink == 0 && !(inode_state_read_once(inode) & I_LINKABLE))
error = -ENOENT;
else if (max_links && inode->i_nlink >= max_links)
error = -EMLINK;
@@ -4941,9 +4941,9 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
error = dir->i_op->link(old_dentry, dir, new_dentry);
}
- if (!error && (inode->i_state & I_LINKABLE)) {
+ if (!error && (inode_state_read_once(inode) & I_LINKABLE)) {
spin_lock(&inode->i_lock);
- inode->i_state &= ~I_LINKABLE;
+ inode_state_clear(inode, I_LINKABLE);
spin_unlock(&inode->i_lock);
}
inode_unlock(inode);
diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c
index 486166460e17..3b97bc35de77 100644
--- a/fs/netfs/misc.c
+++ b/fs/netfs/misc.c
@@ -147,10 +147,10 @@ bool netfs_dirty_folio(struct address_space *mapping, struct folio *folio)
if (!fscache_cookie_valid(cookie))
return true;
- if (!(inode->i_state & I_PINNING_NETFS_WB)) {
+ if (!(inode_state_read_once(inode) & I_PINNING_NETFS_WB)) {
spin_lock(&inode->i_lock);
- if (!(inode->i_state & I_PINNING_NETFS_WB)) {
- inode->i_state |= I_PINNING_NETFS_WB;
+ if (!(inode_state_read(inode) & I_PINNING_NETFS_WB)) {
+ inode_state_set(inode, I_PINNING_NETFS_WB);
need_use = true;
}
spin_unlock(&inode->i_lock);
@@ -192,7 +192,7 @@ void netfs_clear_inode_writeback(struct inode *inode, const void *aux)
{
struct fscache_cookie *cookie = netfs_i_cookie(netfs_inode(inode));
- if (inode->i_state & I_PINNING_NETFS_WB) {
+ if (inode_state_read_once(inode) & I_PINNING_NETFS_WB) {
loff_t i_size = i_size_read(inode);
fscache_unuse_cookie(cookie, aux, &i_size);
}
diff --git a/fs/netfs/read_single.c b/fs/netfs/read_single.c
index 5c0dc4efc792..8e6264f62a8f 100644
--- a/fs/netfs/read_single.c
+++ b/fs/netfs/read_single.c
@@ -36,12 +36,12 @@ void netfs_single_mark_inode_dirty(struct inode *inode)
mark_inode_dirty(inode);
- if (caching && !(inode->i_state & I_PINNING_NETFS_WB)) {
+ if (caching && !(inode_state_read_once(inode) & I_PINNING_NETFS_WB)) {
bool need_use = false;
spin_lock(&inode->i_lock);
- if (!(inode->i_state & I_PINNING_NETFS_WB)) {
- inode->i_state |= I_PINNING_NETFS_WB;
+ if (!(inode_state_read(inode) & I_PINNING_NETFS_WB)) {
+ inode_state_set(inode, I_PINNING_NETFS_WB);
need_use = true;
}
spin_unlock(&inode->i_lock);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 18b57c7c2f97..9e3b1f10ce80 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -475,7 +475,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
goto out_no_inode;
}
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
struct nfs_inode *nfsi = NFS_I(inode);
unsigned long now = jiffies;
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index a3135b5af7ee..f157d43d1312 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -317,7 +317,7 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n");
pnfs_detach_layout_hdr(lo);
/* Notify pnfs_destroy_layout_final() that we're done */
- if (inode->i_state & (I_FREEING | I_CLEAR))
+ if (inode_state_read(inode) & (I_FREEING | I_CLEAR))
wake_up_var_locked(lo, &inode->i_lock);
spin_unlock(&inode->i_lock);
pnfs_free_layout_hdr(lo);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 9cb20d4aeab1..cf4062ac092a 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1159,7 +1159,7 @@ static int wait_for_concurrent_writes(struct file *file)
dprintk("nfsd: write resume %d\n", task_pid_nr(current));
}
- if (inode->i_state & I_DIRTY) {
+ if (inode_state_read_once(inode) & I_DIRTY) {
dprintk("nfsd: write sync %d\n", task_pid_nr(current));
err = vfs_fsync(file, 0);
}
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 46bfc543f946..d27ff5e5f165 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -52,7 +52,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
* the inode cannot have any associated watches.
*/
spin_lock(&inode->i_lock);
- if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) {
+ if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) {
spin_unlock(&inode->i_lock);
continue;
}
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 3959f23c487a..08266adc42ba 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -537,7 +537,7 @@ struct inode *ntfs_iget5(struct super_block *sb, const struct MFT_REF *ref,
return ERR_PTR(-ENOMEM);
/* If this is a freshly allocated inode, need to read it now. */
- if (inode->i_state & I_NEW)
+ if (inode_state_read_once(inode) & I_NEW)
inode = ntfs_read_mft(inode, name, ref);
else if (ref->seq != ntfs_i(inode)->mi.mrec->seq) {
/*
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 92a6149da9c1..619ff03b15d6 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2487,7 +2487,7 @@ int ocfs2_inode_lock_full_nested(struct inode *inode,
* which hasn't been populated yet, so clear the refresh flag
* and let the caller handle it.
*/
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
status = 0;
if (lockres)
ocfs2_complete_lock_res_refresh(lockres, 0);
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 84115bf8b464..78f81950c9ee 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -152,8 +152,8 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
mlog_errno(PTR_ERR(inode));
goto bail;
}
- trace_ocfs2_iget5_locked(inode->i_state);
- if (inode->i_state & I_NEW) {
+ trace_ocfs2_iget5_locked(inode_state_read_once(inode));
+ if (inode_state_read_once(inode) & I_NEW) {
rc = ocfs2_read_locked_inode(inode, &args);
unlock_new_inode(inode);
}
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index 135c49c5d848..db80af312678 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -212,7 +212,7 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
bh = omfs_bread(inode->i_sb, ino);
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 26ecda0e4d19..fb8d84bdedfb 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -236,7 +236,7 @@ static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry
mutex_unlock(&op_mutex);
if (IS_ERR(inode))
return ERR_CAST(inode);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
simple_inode_init_ts(inode);
ent_oi = OP_I(inode);
ent_oi->type = ent_type;
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index a01400cd41fd..1eb4fbe35a46 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -1041,7 +1041,7 @@ struct inode *orangefs_iget(struct super_block *sb,
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
error = orangefs_inode_getattr(inode, ORANGEFS_GETATTR_NEW);
diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c
index 0fdceb00ca07..9ab1119ebd28 100644
--- a/fs/orangefs/orangefs-utils.c
+++ b/fs/orangefs/orangefs-utils.c
@@ -247,7 +247,7 @@ int orangefs_inode_getattr(struct inode *inode, int flags)
spin_lock(&inode->i_lock);
/* Must have all the attributes in the mask and be within cache time. */
if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
- orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) {
+ orangefs_inode->attr_valid || inode_state_read(inode) & I_DIRTY_PAGES) {
if (orangefs_inode->attr_valid) {
spin_unlock(&inode->i_lock);
write_inode_now(inode, 1);
@@ -281,13 +281,13 @@ int orangefs_inode_getattr(struct inode *inode, int flags)
spin_lock(&inode->i_lock);
/* Must have all the attributes in the mask and be within cache time. */
if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
- orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) {
+ orangefs_inode->attr_valid || inode_state_read(inode) & I_DIRTY_PAGES) {
if (orangefs_inode->attr_valid) {
spin_unlock(&inode->i_lock);
write_inode_now(inode, 1);
goto again2;
}
- if (inode->i_state & I_DIRTY_PAGES) {
+ if (inode_state_read(inode) & I_DIRTY_PAGES) {
ret = 0;
goto out_unlock;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index 42fead1efe52..2d0fed2ecbfd 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -908,7 +908,7 @@ static struct inode * get_pipe_inode(void)
* list because "mark_inode_dirty()" will think
* that it already _is_ on the dirty list.
*/
- inode->i_state = I_DIRTY;
+ inode_state_assign_raw(inode, I_DIRTY);
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index e399e2dd3a12..31d78da203ea 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -290,7 +290,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
qnx4_inode = qnx4_raw_inode(inode);
diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
index 3310d1ad4d0e..88d285005083 100644
--- a/fs/qnx6/inode.c
+++ b/fs/qnx6/inode.c
@@ -521,7 +521,7 @@ struct inode *qnx6_iget(struct super_block *sb, unsigned ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
ei = QNX6_I(inode);
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 6c4a6ee1fa2b..376739f6420e 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -1033,7 +1033,7 @@ static int add_dquot_ref(struct super_block *sb, int type)
spin_lock(&sb->s_inode_list_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
spin_lock(&inode->i_lock);
- if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
+ if ((inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) ||
!atomic_read(&inode->i_writecount) ||
!dqinit_needed(inode, type)) {
spin_unlock(&inode->i_lock);
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index 0addcc849ff2..360b00854115 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -302,7 +302,7 @@ static struct inode *romfs_iget(struct super_block *sb, unsigned long pos)
if (!i)
return ERR_PTR(-ENOMEM);
- if (!(i->i_state & I_NEW))
+ if (!(inode_state_read_once(i) & I_NEW))
return i;
/* precalculate the data offset */
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
index cceae3b78698..82b687414e65 100644
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -86,7 +86,7 @@ struct inode *squashfs_iget(struct super_block *sb, long long ino,
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
err = squashfs_read_inode(inode, ino);
diff --git a/fs/sync.c b/fs/sync.c
index 2955cd4c77a3..73b3efb35b26 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -182,7 +182,7 @@ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
if (!file->f_op->fsync)
return -EINVAL;
- if (!datasync && (inode->i_state & I_DIRTY_TIME))
+ if (!datasync && (inode_state_read_once(inode) & I_DIRTY_TIME))
mark_inode_dirty_sync(inode);
return file->f_op->fsync(file, start, end, datasync);
}
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index ca41ce8208c4..c3265b8804f5 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1323,7 +1323,7 @@ int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
inode_lock(inode);
/* Synchronize the inode unless this is a 'datasync()' call. */
- if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) {
+ if (!datasync || (inode_state_read_once(inode) & I_DIRTY_DATASYNC)) {
err = inode->i_sb->s_op->write_inode(inode, NULL);
if (err)
goto out;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 46952a33c4e6..f453c37cee37 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -114,7 +114,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
inode = iget_locked(sb, inum);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
ui = ubifs_inode(inode);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index a79d73f28aa7..7fae8002344a 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1962,7 +1962,7 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW)) {
+ if (!(inode_state_read_once(inode) & I_NEW)) {
if (UDF_I(inode)->i_hidden != hidden_inode) {
iput(inode);
return ERR_PTR(-EFSCORRUPTED);
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 8361c00e8fa6..e2b0a35de2a7 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -655,7 +655,7 @@ struct inode *ufs_iget(struct super_block *sb, unsigned long ino)
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
ufsi = UFS_I(inode);
diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
index 70be0b3dda49..086a31269198 100644
--- a/fs/zonefs/super.c
+++ b/fs/zonefs/super.c
@@ -644,7 +644,7 @@ static struct inode *zonefs_get_file_inode(struct inode *dir,
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW)) {
+ if (!(inode_state_read_once(inode) & I_NEW)) {
WARN_ON_ONCE(inode->i_private != z);
return inode;
}
@@ -683,7 +683,7 @@ static struct inode *zonefs_get_zgroup_inode(struct super_block *sb,
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
inode->i_ino = ino;
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 41b6c9386b69..c5740c6d37a2 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -72,7 +72,7 @@ static void collect_wb_stats(struct wb_stats *stats,
list_for_each_entry(inode, &wb->b_more_io, i_io_list)
stats->nr_more_io++;
list_for_each_entry(inode, &wb->b_dirty_time, i_io_list)
- if (inode->i_state & I_DIRTY_TIME)
+ if (inode_state_read_once(inode) & I_DIRTY_TIME)
stats->nr_dirty_time++;
spin_unlock(&wb->list_lock);
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 0bade2c5aa1d..d4d72f406d58 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1296,7 +1296,7 @@ static void hook_sb_delete(struct super_block *const sb)
* second call to iput() for the same Landlock object. Also
* checks I_NEW because such inode cannot be tied to an object.
*/
- if (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) {
+ if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) {
spin_unlock(&inode->i_lock);
continue;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 04/14] Coccinelle-based conversion to use ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 04/14] Coccinelle-based conversion to use ->i_state accessors Mateusz Guzik
@ 2025-10-10 14:07 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:07 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:18, Mateusz Guzik wrote:
> All places were patched by coccinelle with the default expecting that
> ->i_lock is held, afterwards entries got fixed up by hand to use
> unlocked variants as needed.
>
> The script:
> @@
> expression inode, flags;
> @@
>
> - inode->i_state & flags
> + inode_state_read(inode) & flags
>
> @@
> expression inode, flags;
> @@
>
> - inode->i_state &= ~flags
> + inode_state_clear(inode, flags)
>
> @@
> expression inode, flag1, flag2;
> @@
>
> - inode->i_state &= ~flag1 & ~flag2
> + inode_state_clear(inode, flag1 | flag2)
>
> @@
> expression inode, flags;
> @@
>
> - inode->i_state |= flags
> + inode_state_set(inode, flags)
>
> @@
> expression inode, flags;
> @@
>
> - inode->i_state = flags
> + inode_state_assign(inode, flags)
>
> @@
> expression inode, flags;
> @@
>
> - flags = inode->i_state
> + flags = inode_state_read(inode)
>
> @@
> expression inode, flags;
> @@
>
> - READ_ONCE(inode->i_state) & flags
> + inode_state_read(inode) & flags
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> block/bdev.c | 4 +-
> drivers/dax/super.c | 2 +-
> fs/9p/vfs_inode.c | 2 +-
> fs/9p/vfs_inode_dotl.c | 2 +-
> fs/affs/inode.c | 2 +-
> fs/afs/dynroot.c | 6 +-
> fs/afs/inode.c | 6 +-
> fs/befs/linuxvfs.c | 2 +-
> fs/bfs/inode.c | 2 +-
> fs/buffer.c | 4 +-
> fs/coda/cnode.c | 4 +-
> fs/cramfs/inode.c | 2 +-
> fs/crypto/keyring.c | 2 +-
> fs/crypto/keysetup.c | 2 +-
> fs/dcache.c | 8 +--
> fs/drop_caches.c | 2 +-
> fs/ecryptfs/inode.c | 6 +-
> fs/efs/inode.c | 2 +-
> fs/erofs/inode.c | 2 +-
> fs/ext2/inode.c | 2 +-
> fs/freevxfs/vxfs_inode.c | 2 +-
> fs/fs-writeback.c | 120 +++++++++++++++++------------------
> fs/fuse/inode.c | 4 +-
> fs/hfs/btree.c | 2 +-
> fs/hfs/inode.c | 2 +-
> fs/hfsplus/super.c | 2 +-
> fs/hostfs/hostfs_kern.c | 2 +-
> fs/hpfs/dir.c | 2 +-
> fs/hpfs/inode.c | 2 +-
> fs/inode.c | 92 +++++++++++++--------------
> fs/isofs/inode.c | 2 +-
> fs/jffs2/fs.c | 4 +-
> fs/jfs/file.c | 4 +-
> fs/jfs/inode.c | 2 +-
> fs/jfs/jfs_txnmgr.c | 2 +-
> fs/kernfs/inode.c | 2 +-
> fs/libfs.c | 6 +-
> fs/minix/inode.c | 2 +-
> fs/namei.c | 8 +--
> fs/netfs/misc.c | 8 +--
> fs/netfs/read_single.c | 6 +-
> fs/nfs/inode.c | 2 +-
> fs/nfs/pnfs.c | 2 +-
> fs/nfsd/vfs.c | 2 +-
> fs/notify/fsnotify.c | 2 +-
> fs/ntfs3/inode.c | 2 +-
> fs/ocfs2/dlmglue.c | 2 +-
> fs/ocfs2/inode.c | 4 +-
> fs/omfs/inode.c | 2 +-
> fs/openpromfs/inode.c | 2 +-
> fs/orangefs/inode.c | 2 +-
> fs/orangefs/orangefs-utils.c | 6 +-
> fs/pipe.c | 2 +-
> fs/qnx4/inode.c | 2 +-
> fs/qnx6/inode.c | 2 +-
> fs/quota/dquot.c | 2 +-
> fs/romfs/super.c | 2 +-
> fs/squashfs/inode.c | 2 +-
> fs/sync.c | 2 +-
> fs/ubifs/file.c | 2 +-
> fs/ubifs/super.c | 2 +-
> fs/udf/inode.c | 2 +-
> fs/ufs/inode.c | 2 +-
> fs/zonefs/super.c | 4 +-
> mm/backing-dev.c | 2 +-
> security/landlock/fs.c | 2 +-
> 66 files changed, 199 insertions(+), 199 deletions(-)
>
> diff --git a/block/bdev.c b/block/bdev.c
> index 810707cca970..c33667e30eb7 100644
> --- a/block/bdev.c
> +++ b/block/bdev.c
> @@ -67,7 +67,7 @@ static void bdev_write_inode(struct block_device *bdev)
> int ret;
>
> spin_lock(&inode->i_lock);
> - while (inode->i_state & I_DIRTY) {
> + while (inode_state_read(inode) & I_DIRTY) {
> spin_unlock(&inode->i_lock);
> ret = write_inode_now(inode, true);
> if (ret)
> @@ -1265,7 +1265,7 @@ void sync_bdevs(bool wait)
> struct block_device *bdev;
>
> spin_lock(&inode->i_lock);
> - if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) ||
> + if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW) ||
> mapping->nrpages == 0) {
> spin_unlock(&inode->i_lock);
> continue;
> diff --git a/drivers/dax/super.c b/drivers/dax/super.c
> index d7714d8afb0f..c00b9dff4a06 100644
> --- a/drivers/dax/super.c
> +++ b/drivers/dax/super.c
> @@ -433,7 +433,7 @@ static struct dax_device *dax_dev_get(dev_t devt)
> return NULL;
>
> dax_dev = to_dax_dev(inode);
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> set_bit(DAXDEV_ALIVE, &dax_dev->flags);
> inode->i_cdev = &dax_dev->cdev;
> inode->i_mode = S_IFCHR;
> diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
> index d0c77ec31b1d..8666c9c62258 100644
> --- a/fs/9p/vfs_inode.c
> +++ b/fs/9p/vfs_inode.c
> @@ -422,7 +422,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
> inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode, st);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
> /*
> * initialize the inode with the stat info
> diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
> index be297e335468..1661a25f2772 100644
> --- a/fs/9p/vfs_inode_dotl.c
> +++ b/fs/9p/vfs_inode_dotl.c
> @@ -112,7 +112,7 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
> inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode_dotl, st);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
> /*
> * initialize the inode with the stat info
> diff --git a/fs/affs/inode.c b/fs/affs/inode.c
> index 0210df8d3500..0bfc7d151dcd 100644
> --- a/fs/affs/inode.c
> +++ b/fs/affs/inode.c
> @@ -29,7 +29,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> pr_debug("affs_iget(%lu)\n", inode->i_ino);
> diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
> index 8c6130789fde..475012555100 100644
> --- a/fs/afs/dynroot.c
> +++ b/fs/afs/dynroot.c
> @@ -64,7 +64,7 @@ static struct inode *afs_iget_pseudo_dir(struct super_block *sb, ino_t ino)
>
> vnode = AFS_FS_I(inode);
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> netfs_inode_init(&vnode->netfs, NULL, false);
> simple_inode_init_ts(inode);
> set_nlink(inode, 2);
> @@ -258,7 +258,7 @@ static struct dentry *afs_lookup_atcell(struct inode *dir, struct dentry *dentry
>
> vnode = AFS_FS_I(inode);
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> netfs_inode_init(&vnode->netfs, NULL, false);
> simple_inode_init_ts(inode);
> set_nlink(inode, 1);
> @@ -383,7 +383,7 @@ struct inode *afs_dynroot_iget_root(struct super_block *sb)
> vnode = AFS_FS_I(inode);
>
> /* there shouldn't be an existing inode */
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> netfs_inode_init(&vnode->netfs, NULL, false);
> simple_inode_init_ts(inode);
> set_nlink(inode, 2);
> diff --git a/fs/afs/inode.c b/fs/afs/inode.c
> index e1cb17b85791..2fe2ccf59c7a 100644
> --- a/fs/afs/inode.c
> +++ b/fs/afs/inode.c
> @@ -579,7 +579,7 @@ struct inode *afs_iget(struct afs_operation *op, struct afs_vnode_param *vp)
> inode, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
>
> /* deal with an existing inode */
> - if (!(inode->i_state & I_NEW)) {
> + if (!(inode_state_read_once(inode) & I_NEW)) {
> _leave(" = %p", inode);
> return inode;
> }
> @@ -639,7 +639,7 @@ struct inode *afs_root_iget(struct super_block *sb, struct key *key)
>
> _debug("GOT ROOT INODE %p { vl=%llx }", inode, as->volume->vid);
>
> - BUG_ON(!(inode->i_state & I_NEW));
> + BUG_ON(!(inode_state_read_once(inode) & I_NEW));
>
> vnode = AFS_FS_I(inode);
> vnode->cb_v_check = atomic_read(&as->volume->cb_v_break);
> @@ -748,7 +748,7 @@ void afs_evict_inode(struct inode *inode)
>
> if ((S_ISDIR(inode->i_mode) ||
> S_ISLNK(inode->i_mode)) &&
> - (inode->i_state & I_DIRTY) &&
> + (inode_state_read_once(inode) & I_DIRTY) &&
> !sbi->dyn_root) {
> struct writeback_control wbc = {
> .sync_mode = WB_SYNC_ALL,
> diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
> index 8f430ff8e445..9fcfdd6b8189 100644
> --- a/fs/befs/linuxvfs.c
> +++ b/fs/befs/linuxvfs.c
> @@ -307,7 +307,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> befs_ino = BEFS_I(inode);
> diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
> index 1d41ce477df5..cb406a6ee811 100644
> --- a/fs/bfs/inode.c
> +++ b/fs/bfs/inode.c
> @@ -42,7 +42,7 @@ struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {
> diff --git a/fs/buffer.c b/fs/buffer.c
> index 6a8752f7bbed..17b8ce567cc3 100644
> --- a/fs/buffer.c
> +++ b/fs/buffer.c
> @@ -611,9 +611,9 @@ int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end,
> return err;
>
> ret = sync_mapping_buffers(inode->i_mapping);
> - if (!(inode->i_state & I_DIRTY_ALL))
> + if (!(inode_state_read_once(inode) & I_DIRTY_ALL))
> goto out;
> - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
> + if (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC))
> goto out;
>
> err = sync_inode_metadata(inode, 1);
> diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
> index 62a3d2565c26..70bb0579b40c 100644
> --- a/fs/coda/cnode.c
> +++ b/fs/coda/cnode.c
> @@ -70,7 +70,7 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> cii = ITOC(inode);
> /* we still need to set i_ino for things like stat(2) */
> inode->i_ino = hash;
> @@ -148,7 +148,7 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
>
> /* we should never see newly created inodes because we intentionally
> * fail in the initialization callback */
> - BUG_ON(inode->i_state & I_NEW);
> + BUG_ON(inode_state_read_once(inode) & I_NEW);
>
> return inode;
> }
> diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
> index ca54bf24b719..e54ebe402df7 100644
> --- a/fs/cramfs/inode.c
> +++ b/fs/cramfs/inode.c
> @@ -95,7 +95,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb,
> inode = iget_locked(sb, cramino(cramfs_inode, offset));
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> switch (cramfs_inode->mode & S_IFMT) {
> diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
> index 3adbd7167055..5e939ea3ac28 100644
> --- a/fs/crypto/keyring.c
> +++ b/fs/crypto/keyring.c
> @@ -945,7 +945,7 @@ static void evict_dentries_for_decrypted_inodes(struct fscrypt_master_key *mk)
> list_for_each_entry(ci, &mk->mk_decrypted_inodes, ci_master_key_link) {
> inode = ci->ci_inode;
> spin_lock(&inode->i_lock);
> - if (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) {
> + if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) {
> spin_unlock(&inode->i_lock);
> continue;
> }
> diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
> index 4bd3918f50e3..40fa05688d3a 100644
> --- a/fs/crypto/keysetup.c
> +++ b/fs/crypto/keysetup.c
> @@ -834,7 +834,7 @@ int fscrypt_drop_inode(struct inode *inode)
> * userspace is still using the files, inodes can be dirtied between
> * then and now. We mustn't lose any writes, so skip dirty inodes here.
> */
> - if (inode->i_state & I_DIRTY_ALL)
> + if (inode_state_read(inode) & I_DIRTY_ALL)
> return 0;
>
> /*
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 806d6a665124..78ffa7b7e824 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -794,7 +794,7 @@ void d_mark_dontcache(struct inode *inode)
> de->d_flags |= DCACHE_DONTCACHE;
> spin_unlock(&de->d_lock);
> }
> - inode->i_state |= I_DONTCACHE;
> + inode_state_set(inode, I_DONTCACHE);
> spin_unlock(&inode->i_lock);
> }
> EXPORT_SYMBOL(d_mark_dontcache);
> @@ -1073,7 +1073,7 @@ struct dentry *d_find_alias_rcu(struct inode *inode)
> spin_lock(&inode->i_lock);
> // ->i_dentry and ->i_rcu are colocated, but the latter won't be
> // used without having I_FREEING set, which means no aliases left
> - if (likely(!(inode->i_state & I_FREEING) && !hlist_empty(l))) {
> + if (likely(!(inode_state_read(inode) & I_FREEING) && !hlist_empty(l))) {
> if (S_ISDIR(inode->i_mode)) {
> de = hlist_entry(l->first, struct dentry, d_u.d_alias);
> } else {
> @@ -1980,12 +1980,12 @@ void d_instantiate_new(struct dentry *entry, struct inode *inode)
> security_d_instantiate(entry, inode);
> spin_lock(&inode->i_lock);
> __d_instantiate(entry, inode);
> - WARN_ON(!(inode->i_state & I_NEW));
> + WARN_ON(!(inode_state_read(inode) & I_NEW));
> /*
> * Pairs with smp_rmb in wait_on_inode().
> */
> smp_wmb();
> - inode->i_state &= ~I_NEW & ~I_CREATING;
> + inode_state_clear(inode, I_NEW | I_CREATING);
> /*
> * Pairs with the barrier in prepare_to_wait_event() to make sure
> * ___wait_var_event() either sees the bit cleared or
> diff --git a/fs/drop_caches.c b/fs/drop_caches.c
> index 019a8b4eaaf9..49f56a598ecb 100644
> --- a/fs/drop_caches.c
> +++ b/fs/drop_caches.c
> @@ -28,7 +28,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
> * inodes without pages but we deliberately won't in case
> * we need to reschedule to avoid softlockups.
> */
> - if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
> + if ((inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) ||
> (mapping_empty(inode->i_mapping) && !need_resched())) {
> spin_unlock(&inode->i_lock);
> continue;
> diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
> index ed1394da8d6b..f3c68ef0271f 100644
> --- a/fs/ecryptfs/inode.c
> +++ b/fs/ecryptfs/inode.c
> @@ -95,7 +95,7 @@ static struct inode *__ecryptfs_get_inode(struct inode *lower_inode,
> iput(lower_inode);
> return ERR_PTR(-EACCES);
> }
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> iput(lower_inode);
>
> return inode;
> @@ -106,7 +106,7 @@ struct inode *ecryptfs_get_inode(struct inode *lower_inode,
> {
> struct inode *inode = __ecryptfs_get_inode(lower_inode, sb);
>
> - if (!IS_ERR(inode) && (inode->i_state & I_NEW))
> + if (!IS_ERR(inode) && (inode_state_read_once(inode) & I_NEW))
> unlock_new_inode(inode);
>
> return inode;
> @@ -364,7 +364,7 @@ static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry,
> }
> }
>
> - if (inode->i_state & I_NEW)
> + if (inode_state_read_once(inode) & I_NEW)
> unlock_new_inode(inode);
> return d_splice_alias(inode, dentry);
> }
> diff --git a/fs/efs/inode.c b/fs/efs/inode.c
> index 462619e59766..28407578f83a 100644
> --- a/fs/efs/inode.c
> +++ b/fs/efs/inode.c
> @@ -62,7 +62,7 @@ struct inode *efs_iget(struct super_block *super, unsigned long ino)
> inode = iget_locked(super, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> in = INODE_INFO(inode);
> diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
> index cb780c095d28..bce98c845a18 100644
> --- a/fs/erofs/inode.c
> +++ b/fs/erofs/inode.c
> @@ -295,7 +295,7 @@ struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid)
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> int err = erofs_fill_inode(inode);
>
> if (err) {
> diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
> index e10c376843d7..dbfe9098a124 100644
> --- a/fs/ext2/inode.c
> +++ b/fs/ext2/inode.c
> @@ -1398,7 +1398,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> ei = EXT2_I(inode);
> diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
> index 20600e9ea202..21fc94b98209 100644
> --- a/fs/freevxfs/vxfs_inode.c
> +++ b/fs/freevxfs/vxfs_inode.c
> @@ -258,7 +258,7 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
> ip = iget_locked(sbp, ino);
> if (!ip)
> return ERR_PTR(-ENOMEM);
> - if (!(ip->i_state & I_NEW))
> + if (!(inode_state_read_once(ip) & I_NEW))
> return ip;
>
> vip = VXFS_INO(ip);
> diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
> index 9cda19a40ca2..f784d8b09b04 100644
> --- a/fs/fs-writeback.c
> +++ b/fs/fs-writeback.c
> @@ -121,7 +121,7 @@ static bool inode_io_list_move_locked(struct inode *inode,
> {
> assert_spin_locked(&wb->list_lock);
> assert_spin_locked(&inode->i_lock);
> - WARN_ON_ONCE(inode->i_state & I_FREEING);
> + WARN_ON_ONCE(inode_state_read(inode) & I_FREEING);
>
> list_move(&inode->i_io_list, head);
>
> @@ -304,9 +304,9 @@ static void inode_cgwb_move_to_attached(struct inode *inode,
> {
> assert_spin_locked(&wb->list_lock);
> assert_spin_locked(&inode->i_lock);
> - WARN_ON_ONCE(inode->i_state & I_FREEING);
> + WARN_ON_ONCE(inode_state_read(inode) & I_FREEING);
>
> - inode->i_state &= ~I_SYNC_QUEUED;
> + inode_state_clear(inode, I_SYNC_QUEUED);
> if (wb != &wb->bdi->wb)
> list_move(&inode->i_io_list, &wb->b_attached);
> else
> @@ -408,7 +408,7 @@ static bool inode_do_switch_wbs(struct inode *inode,
> * Once I_FREEING or I_WILL_FREE are visible under i_lock, the eviction
> * path owns the inode and we shouldn't modify ->i_io_list.
> */
> - if (unlikely(inode->i_state & (I_FREEING | I_WILL_FREE)))
> + if (unlikely(inode_state_read(inode) & (I_FREEING | I_WILL_FREE)))
> goto skip_switch;
>
> trace_inode_switch_wbs(inode, old_wb, new_wb);
> @@ -451,7 +451,7 @@ static bool inode_do_switch_wbs(struct inode *inode,
> if (!list_empty(&inode->i_io_list)) {
> inode->i_wb = new_wb;
>
> - if (inode->i_state & I_DIRTY_ALL) {
> + if (inode_state_read(inode) & I_DIRTY_ALL) {
> /*
> * We need to keep b_dirty list sorted by
> * dirtied_time_when. However properly sorting the
> @@ -480,7 +480,7 @@ static bool inode_do_switch_wbs(struct inode *inode,
> * ensures that the new wb is visible if they see !I_WB_SWITCH.
> */
> smp_wmb();
> - inode->i_state &= ~I_WB_SWITCH;
> + inode_state_clear(inode, I_WB_SWITCH);
>
> xa_unlock_irq(&mapping->i_pages);
> spin_unlock(&inode->i_lock);
> @@ -601,12 +601,12 @@ static bool inode_prepare_wbs_switch(struct inode *inode,
> /* while holding I_WB_SWITCH, no one else can update the association */
> spin_lock(&inode->i_lock);
> if (!(inode->i_sb->s_flags & SB_ACTIVE) ||
> - inode->i_state & (I_WB_SWITCH | I_FREEING | I_WILL_FREE) ||
> + inode_state_read(inode) & (I_WB_SWITCH | I_FREEING | I_WILL_FREE) ||
> inode_to_wb(inode) == new_wb) {
> spin_unlock(&inode->i_lock);
> return false;
> }
> - inode->i_state |= I_WB_SWITCH;
> + inode_state_set(inode, I_WB_SWITCH);
> __iget(inode);
> spin_unlock(&inode->i_lock);
>
> @@ -636,7 +636,7 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
> struct bdi_writeback *new_wb = NULL;
>
> /* noop if seems to be already in progress */
> - if (inode->i_state & I_WB_SWITCH)
> + if (inode_state_read_once(inode) & I_WB_SWITCH)
> return;
>
> /* avoid queueing a new switch if too many are already in flight */
> @@ -1237,9 +1237,9 @@ static void inode_cgwb_move_to_attached(struct inode *inode,
> {
> assert_spin_locked(&wb->list_lock);
> assert_spin_locked(&inode->i_lock);
> - WARN_ON_ONCE(inode->i_state & I_FREEING);
> + WARN_ON_ONCE(inode_state_read(inode) & I_FREEING);
>
> - inode->i_state &= ~I_SYNC_QUEUED;
> + inode_state_clear(inode, I_SYNC_QUEUED);
> list_del_init(&inode->i_io_list);
> wb_io_lists_depopulated(wb);
> }
> @@ -1352,7 +1352,7 @@ void inode_io_list_del(struct inode *inode)
> wb = inode_to_wb_and_lock_list(inode);
> spin_lock(&inode->i_lock);
>
> - inode->i_state &= ~I_SYNC_QUEUED;
> + inode_state_clear(inode, I_SYNC_QUEUED);
> list_del_init(&inode->i_io_list);
> wb_io_lists_depopulated(wb);
>
> @@ -1410,13 +1410,13 @@ static void redirty_tail_locked(struct inode *inode, struct bdi_writeback *wb)
> {
> assert_spin_locked(&inode->i_lock);
>
> - inode->i_state &= ~I_SYNC_QUEUED;
> + inode_state_clear(inode, I_SYNC_QUEUED);
> /*
> * When the inode is being freed just don't bother with dirty list
> * tracking. Flush worker will ignore this inode anyway and it will
> * trigger assertions in inode_io_list_move_locked().
> */
> - if (inode->i_state & I_FREEING) {
> + if (inode_state_read(inode) & I_FREEING) {
> list_del_init(&inode->i_io_list);
> wb_io_lists_depopulated(wb);
> return;
> @@ -1450,7 +1450,7 @@ static void inode_sync_complete(struct inode *inode)
> {
> assert_spin_locked(&inode->i_lock);
>
> - inode->i_state &= ~I_SYNC;
> + inode_state_clear(inode, I_SYNC);
> /* If inode is clean an unused, put it into LRU now... */
> inode_add_lru(inode);
> /* Called with inode->i_lock which ensures memory ordering. */
> @@ -1494,7 +1494,7 @@ static int move_expired_inodes(struct list_head *delaying_queue,
> spin_lock(&inode->i_lock);
> list_move(&inode->i_io_list, &tmp);
> moved++;
> - inode->i_state |= I_SYNC_QUEUED;
> + inode_state_set(inode, I_SYNC_QUEUED);
> spin_unlock(&inode->i_lock);
> if (sb_is_blkdev_sb(inode->i_sb))
> continue;
> @@ -1580,14 +1580,14 @@ void inode_wait_for_writeback(struct inode *inode)
>
> assert_spin_locked(&inode->i_lock);
>
> - if (!(inode->i_state & I_SYNC))
> + if (!(inode_state_read(inode) & I_SYNC))
> return;
>
> wq_head = inode_bit_waitqueue(&wqe, inode, __I_SYNC);
> for (;;) {
> prepare_to_wait_event(wq_head, &wqe.wq_entry, TASK_UNINTERRUPTIBLE);
> /* Checking I_SYNC with inode->i_lock guarantees memory ordering. */
> - if (!(inode->i_state & I_SYNC))
> + if (!(inode_state_read(inode) & I_SYNC))
> break;
> spin_unlock(&inode->i_lock);
> schedule();
> @@ -1613,7 +1613,7 @@ static void inode_sleep_on_writeback(struct inode *inode)
> wq_head = inode_bit_waitqueue(&wqe, inode, __I_SYNC);
> prepare_to_wait_event(wq_head, &wqe.wq_entry, TASK_UNINTERRUPTIBLE);
> /* Checking I_SYNC with inode->i_lock guarantees memory ordering. */
> - sleep = !!(inode->i_state & I_SYNC);
> + sleep = !!(inode_state_read(inode) & I_SYNC);
> spin_unlock(&inode->i_lock);
> if (sleep)
> schedule();
> @@ -1632,7 +1632,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
> struct writeback_control *wbc,
> unsigned long dirtied_before)
> {
> - if (inode->i_state & I_FREEING)
> + if (inode_state_read(inode) & I_FREEING)
> return;
>
> /*
> @@ -1640,7 +1640,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
> * shot. If still dirty, it will be redirty_tail()'ed below. Update
> * the dirty time to prevent enqueue and sync it again.
> */
> - if ((inode->i_state & I_DIRTY) &&
> + if ((inode_state_read(inode) & I_DIRTY) &&
> (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages))
> inode->dirtied_when = jiffies;
>
> @@ -1651,7 +1651,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
> * is odd for clean inodes, it can happen for some
> * filesystems so handle that gracefully.
> */
> - if (inode->i_state & I_DIRTY_ALL)
> + if (inode_state_read(inode) & I_DIRTY_ALL)
> redirty_tail_locked(inode, wb);
> else
> inode_cgwb_move_to_attached(inode, wb);
> @@ -1677,17 +1677,17 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
> */
> redirty_tail_locked(inode, wb);
> }
> - } else if (inode->i_state & I_DIRTY) {
> + } else if (inode_state_read(inode) & I_DIRTY) {
> /*
> * Filesystems can dirty the inode during writeback operations,
> * such as delayed allocation during submission or metadata
> * updates after data IO completion.
> */
> redirty_tail_locked(inode, wb);
> - } else if (inode->i_state & I_DIRTY_TIME) {
> + } else if (inode_state_read(inode) & I_DIRTY_TIME) {
> inode->dirtied_when = jiffies;
> inode_io_list_move_locked(inode, wb, &wb->b_dirty_time);
> - inode->i_state &= ~I_SYNC_QUEUED;
> + inode_state_clear(inode, I_SYNC_QUEUED);
> } else {
> /* The inode is clean. Remove from writeback lists. */
> inode_cgwb_move_to_attached(inode, wb);
> @@ -1713,7 +1713,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
> unsigned dirty;
> int ret;
>
> - WARN_ON(!(inode->i_state & I_SYNC));
> + WARN_ON(!(inode_state_read_once(inode) & I_SYNC));
>
> trace_writeback_single_inode_start(inode, wbc, nr_to_write);
>
> @@ -1737,7 +1737,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
> * mark_inode_dirty_sync() to notify the filesystem about it and to
> * change I_DIRTY_TIME into I_DIRTY_SYNC.
> */
> - if ((inode->i_state & I_DIRTY_TIME) &&
> + if ((inode_state_read_once(inode) & I_DIRTY_TIME) &&
> (wbc->sync_mode == WB_SYNC_ALL ||
> time_after(jiffies, inode->dirtied_time_when +
> dirtytime_expire_interval * HZ))) {
> @@ -1752,8 +1752,8 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
> * after handling timestamp expiration, as that may dirty the inode too.
> */
> spin_lock(&inode->i_lock);
> - dirty = inode->i_state & I_DIRTY;
> - inode->i_state &= ~dirty;
> + dirty = inode_state_read(inode) & I_DIRTY;
> + inode_state_clear(inode, dirty);
>
> /*
> * Paired with smp_mb() in __mark_inode_dirty(). This allows
> @@ -1769,10 +1769,10 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
> smp_mb();
>
> if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
> - inode->i_state |= I_DIRTY_PAGES;
> - else if (unlikely(inode->i_state & I_PINNING_NETFS_WB)) {
> - if (!(inode->i_state & I_DIRTY_PAGES)) {
> - inode->i_state &= ~I_PINNING_NETFS_WB;
> + inode_state_set(inode, I_DIRTY_PAGES);
> + else if (unlikely(inode_state_read(inode) & I_PINNING_NETFS_WB)) {
> + if (!(inode_state_read(inode) & I_DIRTY_PAGES)) {
> + inode_state_clear(inode, I_PINNING_NETFS_WB);
> wbc->unpinned_netfs_wb = true;
> dirty |= I_PINNING_NETFS_WB; /* Cause write_inode */
> }
> @@ -1808,11 +1808,11 @@ static int writeback_single_inode(struct inode *inode,
>
> spin_lock(&inode->i_lock);
> if (!icount_read(inode))
> - WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING)));
> + WARN_ON(!(inode_state_read(inode) & (I_WILL_FREE | I_FREEING)));
> else
> - WARN_ON(inode->i_state & I_WILL_FREE);
> + WARN_ON(inode_state_read(inode) & I_WILL_FREE);
>
> - if (inode->i_state & I_SYNC) {
> + if (inode_state_read(inode) & I_SYNC) {
> /*
> * Writeback is already running on the inode. For WB_SYNC_NONE,
> * that's enough and we can just return. For WB_SYNC_ALL, we
> @@ -1823,7 +1823,7 @@ static int writeback_single_inode(struct inode *inode,
> goto out;
> inode_wait_for_writeback(inode);
> }
> - WARN_ON(inode->i_state & I_SYNC);
> + WARN_ON(inode_state_read(inode) & I_SYNC);
> /*
> * If the inode is already fully clean, then there's nothing to do.
> *
> @@ -1831,11 +1831,11 @@ static int writeback_single_inode(struct inode *inode,
> * still under writeback, e.g. due to prior WB_SYNC_NONE writeback. If
> * there are any such pages, we'll need to wait for them.
> */
> - if (!(inode->i_state & I_DIRTY_ALL) &&
> + if (!(inode_state_read(inode) & I_DIRTY_ALL) &&
> (wbc->sync_mode != WB_SYNC_ALL ||
> !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK)))
> goto out;
> - inode->i_state |= I_SYNC;
> + inode_state_set(inode, I_SYNC);
> wbc_attach_and_unlock_inode(wbc, inode);
>
> ret = __writeback_single_inode(inode, wbc);
> @@ -1848,18 +1848,18 @@ static int writeback_single_inode(struct inode *inode,
> * If the inode is freeing, its i_io_list shoudn't be updated
> * as it can be finally deleted at this moment.
> */
> - if (!(inode->i_state & I_FREEING)) {
> + if (!(inode_state_read(inode) & I_FREEING)) {
> /*
> * If the inode is now fully clean, then it can be safely
> * removed from its writeback list (if any). Otherwise the
> * flusher threads are responsible for the writeback lists.
> */
> - if (!(inode->i_state & I_DIRTY_ALL))
> + if (!(inode_state_read(inode) & I_DIRTY_ALL))
> inode_cgwb_move_to_attached(inode, wb);
> - else if (!(inode->i_state & I_SYNC_QUEUED)) {
> - if ((inode->i_state & I_DIRTY))
> + else if (!(inode_state_read(inode) & I_SYNC_QUEUED)) {
> + if ((inode_state_read(inode) & I_DIRTY))
> redirty_tail_locked(inode, wb);
> - else if (inode->i_state & I_DIRTY_TIME) {
> + else if (inode_state_read(inode) & I_DIRTY_TIME) {
> inode->dirtied_when = jiffies;
> inode_io_list_move_locked(inode,
> wb,
> @@ -1968,12 +1968,12 @@ static long writeback_sb_inodes(struct super_block *sb,
> * kind writeout is handled by the freer.
> */
> spin_lock(&inode->i_lock);
> - if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
> + if (inode_state_read(inode) & (I_NEW | I_FREEING | I_WILL_FREE)) {
> redirty_tail_locked(inode, wb);
> spin_unlock(&inode->i_lock);
> continue;
> }
> - if ((inode->i_state & I_SYNC) && wbc.sync_mode != WB_SYNC_ALL) {
> + if ((inode_state_read(inode) & I_SYNC) && wbc.sync_mode != WB_SYNC_ALL) {
> /*
> * If this inode is locked for writeback and we are not
> * doing writeback-for-data-integrity, move it to
> @@ -1995,14 +1995,14 @@ static long writeback_sb_inodes(struct super_block *sb,
> * are doing WB_SYNC_NONE writeback. So this catches only the
> * WB_SYNC_ALL case.
> */
> - if (inode->i_state & I_SYNC) {
> + if (inode_state_read(inode) & I_SYNC) {
> /* Wait for I_SYNC. This function drops i_lock... */
> inode_sleep_on_writeback(inode);
> /* Inode may be gone, start again */
> spin_lock(&wb->list_lock);
> continue;
> }
> - inode->i_state |= I_SYNC;
> + inode_state_set(inode, I_SYNC);
> wbc_attach_and_unlock_inode(&wbc, inode);
>
> write_chunk = writeback_chunk_size(wb, work);
> @@ -2040,7 +2040,7 @@ static long writeback_sb_inodes(struct super_block *sb,
> */
> tmp_wb = inode_to_wb_and_lock_list(inode);
> spin_lock(&inode->i_lock);
> - if (!(inode->i_state & I_DIRTY_ALL))
> + if (!(inode_state_read(inode) & I_DIRTY_ALL))
> total_wrote++;
> requeue_inode(inode, tmp_wb, &wbc, dirtied_before);
> inode_sync_complete(inode);
> @@ -2546,10 +2546,10 @@ void __mark_inode_dirty(struct inode *inode, int flags)
> * We tell ->dirty_inode callback that timestamps need to
> * be updated by setting I_DIRTY_TIME in flags.
> */
> - if (inode->i_state & I_DIRTY_TIME) {
> + if (inode_state_read_once(inode) & I_DIRTY_TIME) {
> spin_lock(&inode->i_lock);
> - if (inode->i_state & I_DIRTY_TIME) {
> - inode->i_state &= ~I_DIRTY_TIME;
> + if (inode_state_read(inode) & I_DIRTY_TIME) {
> + inode_state_clear(inode, I_DIRTY_TIME);
> flags |= I_DIRTY_TIME;
> }
> spin_unlock(&inode->i_lock);
> @@ -2586,16 +2586,16 @@ void __mark_inode_dirty(struct inode *inode, int flags)
> */
> smp_mb();
>
> - if ((inode->i_state & flags) == flags)
> + if ((inode_state_read_once(inode) & flags) == flags)
> return;
>
> spin_lock(&inode->i_lock);
> - if ((inode->i_state & flags) != flags) {
> - const int was_dirty = inode->i_state & I_DIRTY;
> + if ((inode_state_read(inode) & flags) != flags) {
> + const int was_dirty = inode_state_read(inode) & I_DIRTY;
>
> inode_attach_wb(inode, NULL);
>
> - inode->i_state |= flags;
> + inode_state_set(inode, flags);
>
> /*
> * Grab inode's wb early because it requires dropping i_lock and we
> @@ -2614,7 +2614,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
> * the inode it will place it on the appropriate superblock
> * list, based upon its state.
> */
> - if (inode->i_state & I_SYNC_QUEUED)
> + if (inode_state_read(inode) & I_SYNC_QUEUED)
> goto out_unlock;
>
> /*
> @@ -2625,7 +2625,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
> if (inode_unhashed(inode))
> goto out_unlock;
> }
> - if (inode->i_state & I_FREEING)
> + if (inode_state_read(inode) & I_FREEING)
> goto out_unlock;
>
> /*
> @@ -2640,7 +2640,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
> if (dirtytime)
> inode->dirtied_time_when = jiffies;
>
> - if (inode->i_state & I_DIRTY)
> + if (inode_state_read(inode) & I_DIRTY)
> dirty_list = &wb->b_dirty;
> else
> dirty_list = &wb->b_dirty_time;
> @@ -2737,7 +2737,7 @@ static void wait_sb_inodes(struct super_block *sb)
> spin_unlock_irq(&sb->s_inode_wblist_lock);
>
> spin_lock(&inode->i_lock);
> - if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) {
> + if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) {
> spin_unlock(&inode->i_lock);
>
> spin_lock_irq(&sb->s_inode_wblist_lock);
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index d1babf56f254..bbecd0e5855d 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -160,7 +160,7 @@ static void fuse_evict_inode(struct inode *inode)
> struct fuse_inode *fi = get_fuse_inode(inode);
>
> /* Will write inode on close/munmap and in all other dirtiers */
> - WARN_ON(inode->i_state & I_DIRTY_INODE);
> + WARN_ON(inode_state_read_once(inode) & I_DIRTY_INODE);
>
> if (FUSE_IS_DAX(inode))
> dax_break_layout_final(inode);
> @@ -505,7 +505,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
> if (!inode)
> return NULL;
>
> - if ((inode->i_state & I_NEW)) {
> + if ((inode_state_read_once(inode) & I_NEW)) {
> inode->i_flags |= S_NOATIME;
> if (!fc->writeback_cache || !S_ISREG(attr->mode))
> inode->i_flags |= S_NOCMTIME;
> diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
> index 22e62fe7448b..54c20d01c342 100644
> --- a/fs/hfs/btree.c
> +++ b/fs/hfs/btree.c
> @@ -42,7 +42,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
> tree->inode = iget_locked(sb, id);
> if (!tree->inode)
> goto free_tree;
> - BUG_ON(!(tree->inode->i_state & I_NEW));
> + BUG_ON(!(inode_state_read_once(tree->inode) & I_NEW));
> {
> struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
> HFS_I(tree->inode)->flags = 0;
> diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
> index 9cd449913dc8..81ad93e6312f 100644
> --- a/fs/hfs/inode.c
> +++ b/fs/hfs/inode.c
> @@ -412,7 +412,7 @@ struct inode *hfs_iget(struct super_block *sb, struct hfs_cat_key *key, hfs_cat_
> return NULL;
> }
> inode = iget5_locked(sb, cnid, hfs_test_inode, hfs_read_inode, &data);
> - if (inode && (inode->i_state & I_NEW))
> + if (inode && (inode_state_read_once(inode) & I_NEW))
> unlock_new_inode(inode);
> return inode;
> }
> diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
> index 16bc4abc67e0..54e85e25a259 100644
> --- a/fs/hfsplus/super.c
> +++ b/fs/hfsplus/super.c
> @@ -65,7 +65,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
> diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
> index 1e1acf5775ab..76b643f7d05c 100644
> --- a/fs/hostfs/hostfs_kern.c
> +++ b/fs/hostfs/hostfs_kern.c
> @@ -581,7 +581,7 @@ static struct inode *hostfs_iget(struct super_block *sb, char *name)
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> unlock_new_inode(inode);
> } else {
> spin_lock(&inode->i_lock);
> diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
> index 49dd585c2b17..ceb50b2dc91a 100644
> --- a/fs/hpfs/dir.c
> +++ b/fs/hpfs/dir.c
> @@ -247,7 +247,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned in
> result = ERR_PTR(-ENOMEM);
> goto bail1;
> }
> - if (result->i_state & I_NEW) {
> + if (inode_state_read_once(result) & I_NEW) {
> hpfs_init_inode(result);
> if (de->directory)
> hpfs_read_inode(result);
> diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
> index 34008442ee26..93d528f4f4f2 100644
> --- a/fs/hpfs/inode.c
> +++ b/fs/hpfs/inode.c
> @@ -196,7 +196,7 @@ void hpfs_write_inode(struct inode *i)
> parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir);
> if (parent) {
> hpfs_inode->i_dirty = 0;
> - if (parent->i_state & I_NEW) {
> + if (inode_state_read_once(parent) & I_NEW) {
> hpfs_init_inode(parent);
> hpfs_read_inode(parent);
> unlock_new_inode(parent);
> diff --git a/fs/inode.c b/fs/inode.c
> index 37fc7a72aba5..f094ed3e6f30 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -233,7 +233,7 @@ int inode_init_always_gfp(struct super_block *sb, struct inode *inode, gfp_t gfp
> inode->i_sb = sb;
> inode->i_blkbits = sb->s_blocksize_bits;
> inode->i_flags = 0;
> - inode->i_state = 0;
> + inode_state_assign_raw(inode, 0);
> atomic64_set(&inode->i_sequence, 0);
> atomic_set(&inode->i_count, 1);
> inode->i_op = &empty_iops;
> @@ -471,7 +471,7 @@ EXPORT_SYMBOL(set_nlink);
> void inc_nlink(struct inode *inode)
> {
> if (unlikely(inode->i_nlink == 0)) {
> - WARN_ON(!(inode->i_state & I_LINKABLE));
> + WARN_ON(!(inode_state_read_once(inode) & I_LINKABLE));
> atomic_long_dec(&inode->i_sb->s_remove_count);
> }
>
> @@ -532,7 +532,7 @@ EXPORT_SYMBOL(ihold);
>
> static void __inode_add_lru(struct inode *inode, bool rotate)
> {
> - if (inode->i_state & (I_DIRTY_ALL | I_SYNC | I_FREEING | I_WILL_FREE))
> + if (inode_state_read(inode) & (I_DIRTY_ALL | I_SYNC | I_FREEING | I_WILL_FREE))
> return;
> if (icount_read(inode))
> return;
> @@ -544,7 +544,7 @@ static void __inode_add_lru(struct inode *inode, bool rotate)
> if (list_lru_add_obj(&inode->i_sb->s_inode_lru, &inode->i_lru))
> this_cpu_inc(nr_unused);
> else if (rotate)
> - inode->i_state |= I_REFERENCED;
> + inode_state_set(inode, I_REFERENCED);
> }
>
> struct wait_queue_head *inode_bit_waitqueue(struct wait_bit_queue_entry *wqe,
> @@ -577,15 +577,15 @@ static void inode_lru_list_del(struct inode *inode)
> static void inode_pin_lru_isolating(struct inode *inode)
> {
> lockdep_assert_held(&inode->i_lock);
> - WARN_ON(inode->i_state & (I_LRU_ISOLATING | I_FREEING | I_WILL_FREE));
> - inode->i_state |= I_LRU_ISOLATING;
> + WARN_ON(inode_state_read(inode) & (I_LRU_ISOLATING | I_FREEING | I_WILL_FREE));
> + inode_state_set(inode, I_LRU_ISOLATING);
> }
>
> static void inode_unpin_lru_isolating(struct inode *inode)
> {
> spin_lock(&inode->i_lock);
> - WARN_ON(!(inode->i_state & I_LRU_ISOLATING));
> - inode->i_state &= ~I_LRU_ISOLATING;
> + WARN_ON(!(inode_state_read(inode) & I_LRU_ISOLATING));
> + inode_state_clear(inode, I_LRU_ISOLATING);
> /* Called with inode->i_lock which ensures memory ordering. */
> inode_wake_up_bit(inode, __I_LRU_ISOLATING);
> spin_unlock(&inode->i_lock);
> @@ -597,7 +597,7 @@ static void inode_wait_for_lru_isolating(struct inode *inode)
> struct wait_queue_head *wq_head;
>
> lockdep_assert_held(&inode->i_lock);
> - if (!(inode->i_state & I_LRU_ISOLATING))
> + if (!(inode_state_read(inode) & I_LRU_ISOLATING))
> return;
>
> wq_head = inode_bit_waitqueue(&wqe, inode, __I_LRU_ISOLATING);
> @@ -607,14 +607,14 @@ static void inode_wait_for_lru_isolating(struct inode *inode)
> * Checking I_LRU_ISOLATING with inode->i_lock guarantees
> * memory ordering.
> */
> - if (!(inode->i_state & I_LRU_ISOLATING))
> + if (!(inode_state_read(inode) & I_LRU_ISOLATING))
> break;
> spin_unlock(&inode->i_lock);
> schedule();
> spin_lock(&inode->i_lock);
> }
> finish_wait(wq_head, &wqe.wq_entry);
> - WARN_ON(inode->i_state & I_LRU_ISOLATING);
> + WARN_ON(inode_state_read(inode) & I_LRU_ISOLATING);
> }
>
> /**
> @@ -761,11 +761,11 @@ void clear_inode(struct inode *inode)
> */
> xa_unlock_irq(&inode->i_data.i_pages);
> BUG_ON(!list_empty(&inode->i_data.i_private_list));
> - BUG_ON(!(inode->i_state & I_FREEING));
> - BUG_ON(inode->i_state & I_CLEAR);
> + BUG_ON(!(inode_state_read_once(inode) & I_FREEING));
> + BUG_ON(inode_state_read_once(inode) & I_CLEAR);
> BUG_ON(!list_empty(&inode->i_wb_list));
> /* don't need i_lock here, no concurrent mods to i_state */
> - inode->i_state = I_FREEING | I_CLEAR;
> + inode_state_assign_raw(inode, I_FREEING | I_CLEAR);
> }
> EXPORT_SYMBOL(clear_inode);
>
> @@ -786,7 +786,7 @@ static void evict(struct inode *inode)
> {
> const struct super_operations *op = inode->i_sb->s_op;
>
> - BUG_ON(!(inode->i_state & I_FREEING));
> + BUG_ON(!(inode_state_read_once(inode) & I_FREEING));
> BUG_ON(!list_empty(&inode->i_lru));
>
> if (!list_empty(&inode->i_io_list))
> @@ -879,12 +879,12 @@ void evict_inodes(struct super_block *sb)
> spin_unlock(&inode->i_lock);
> continue;
> }
> - if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
> + if (inode_state_read(inode) & (I_NEW | I_FREEING | I_WILL_FREE)) {
> spin_unlock(&inode->i_lock);
> continue;
> }
>
> - inode->i_state |= I_FREEING;
> + inode_state_set(inode, I_FREEING);
> inode_lru_list_del(inode);
> spin_unlock(&inode->i_lock);
> list_add(&inode->i_lru, &dispose);
> @@ -938,7 +938,7 @@ static enum lru_status inode_lru_isolate(struct list_head *item,
> * sync, or the last page cache deletion will requeue them.
> */
> if (icount_read(inode) ||
> - (inode->i_state & ~I_REFERENCED) ||
> + (inode_state_read(inode) & ~I_REFERENCED) ||
> !mapping_shrinkable(&inode->i_data)) {
> list_lru_isolate(lru, &inode->i_lru);
> spin_unlock(&inode->i_lock);
> @@ -947,8 +947,8 @@ static enum lru_status inode_lru_isolate(struct list_head *item,
> }
>
> /* Recently referenced inodes get one more pass */
> - if (inode->i_state & I_REFERENCED) {
> - inode->i_state &= ~I_REFERENCED;
> + if (inode_state_read(inode) & I_REFERENCED) {
> + inode_state_clear(inode, I_REFERENCED);
> spin_unlock(&inode->i_lock);
> return LRU_ROTATE;
> }
> @@ -975,8 +975,8 @@ static enum lru_status inode_lru_isolate(struct list_head *item,
> return LRU_RETRY;
> }
>
> - WARN_ON(inode->i_state & I_NEW);
> - inode->i_state |= I_FREEING;
> + WARN_ON(inode_state_read(inode) & I_NEW);
> + inode_state_set(inode, I_FREEING);
> list_lru_isolate_move(lru, &inode->i_lru, freeable);
> spin_unlock(&inode->i_lock);
>
> @@ -1025,11 +1025,11 @@ static struct inode *find_inode(struct super_block *sb,
> if (!test(inode, data))
> continue;
> spin_lock(&inode->i_lock);
> - if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
> + if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE)) {
> __wait_on_freeing_inode(inode, is_inode_hash_locked);
> goto repeat;
> }
> - if (unlikely(inode->i_state & I_CREATING)) {
> + if (unlikely(inode_state_read(inode) & I_CREATING)) {
> spin_unlock(&inode->i_lock);
> rcu_read_unlock();
> return ERR_PTR(-ESTALE);
> @@ -1066,11 +1066,11 @@ static struct inode *find_inode_fast(struct super_block *sb,
> if (inode->i_sb != sb)
> continue;
> spin_lock(&inode->i_lock);
> - if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
> + if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE)) {
> __wait_on_freeing_inode(inode, is_inode_hash_locked);
> goto repeat;
> }
> - if (unlikely(inode->i_state & I_CREATING)) {
> + if (unlikely(inode_state_read(inode) & I_CREATING)) {
> spin_unlock(&inode->i_lock);
> rcu_read_unlock();
> return ERR_PTR(-ESTALE);
> @@ -1180,12 +1180,12 @@ 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));
> + WARN_ON(!(inode_state_read(inode) & I_NEW));
> /*
> * Pairs with smp_rmb in wait_on_inode().
> */
> smp_wmb();
> - inode->i_state &= ~I_NEW & ~I_CREATING;
> + inode_state_clear(inode, I_NEW | I_CREATING);
> /*
> * Pairs with the barrier in prepare_to_wait_event() to make sure
> * ___wait_var_event() either sees the bit cleared or
> @@ -1201,12 +1201,12 @@ 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));
> + WARN_ON(!(inode_state_read(inode) & I_NEW));
> /*
> * Pairs with smp_rmb in wait_on_inode().
> */
> smp_wmb();
> - inode->i_state &= ~I_NEW;
> + inode_state_clear(inode, I_NEW);
> /*
> * Pairs with the barrier in prepare_to_wait_event() to make sure
> * ___wait_var_event() either sees the bit cleared or
> @@ -1318,7 +1318,7 @@ struct inode *inode_insert5(struct inode *inode, unsigned long hashval,
> * caller is responsible for filling in the contents
> */
> spin_lock(&inode->i_lock);
> - inode->i_state |= I_NEW;
> + inode_state_set(inode, I_NEW);
> hlist_add_head_rcu(&inode->i_hash, head);
> spin_unlock(&inode->i_lock);
>
> @@ -1460,7 +1460,7 @@ struct inode *iget_locked(struct super_block *sb, unsigned long ino)
> if (!old) {
> inode->i_ino = ino;
> spin_lock(&inode->i_lock);
> - inode->i_state = I_NEW;
> + inode_state_assign(inode, I_NEW);
> hlist_add_head_rcu(&inode->i_hash, head);
> spin_unlock(&inode->i_lock);
> spin_unlock(&inode_hash_lock);
> @@ -1553,7 +1553,7 @@ EXPORT_SYMBOL(iunique);
> struct inode *igrab(struct inode *inode)
> {
> spin_lock(&inode->i_lock);
> - if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) {
> + if (!(inode_state_read(inode) & (I_FREEING | I_WILL_FREE))) {
> __iget(inode);
> spin_unlock(&inode->i_lock);
> } else {
> @@ -1749,7 +1749,7 @@ struct inode *find_inode_rcu(struct super_block *sb, unsigned long hashval,
>
> hlist_for_each_entry_rcu(inode, head, i_hash) {
> if (inode->i_sb == sb &&
> - !(READ_ONCE(inode->i_state) & (I_FREEING | I_WILL_FREE)) &&
> + !(inode_state_read_once(inode) & (I_FREEING | I_WILL_FREE)) &&
> test(inode, data))
> return inode;
> }
> @@ -1788,7 +1788,7 @@ struct inode *find_inode_by_ino_rcu(struct super_block *sb,
> hlist_for_each_entry_rcu(inode, head, i_hash) {
> if (inode->i_ino == ino &&
> inode->i_sb == sb &&
> - !(READ_ONCE(inode->i_state) & (I_FREEING | I_WILL_FREE)))
> + !(inode_state_read_once(inode) & (I_FREEING | I_WILL_FREE)))
> return inode;
> }
> return NULL;
> @@ -1812,7 +1812,7 @@ int insert_inode_locked(struct inode *inode)
> if (old->i_sb != sb)
> continue;
> spin_lock(&old->i_lock);
> - if (old->i_state & (I_FREEING|I_WILL_FREE)) {
> + if (inode_state_read(old) & (I_FREEING | I_WILL_FREE)) {
> spin_unlock(&old->i_lock);
> continue;
> }
> @@ -1820,13 +1820,13 @@ int insert_inode_locked(struct inode *inode)
> }
> if (likely(!old)) {
> spin_lock(&inode->i_lock);
> - inode->i_state |= I_NEW | I_CREATING;
> + inode_state_set(inode, I_NEW | I_CREATING);
> hlist_add_head_rcu(&inode->i_hash, head);
> spin_unlock(&inode->i_lock);
> spin_unlock(&inode_hash_lock);
> return 0;
> }
> - if (unlikely(old->i_state & I_CREATING)) {
> + if (unlikely(inode_state_read(old) & I_CREATING)) {
> spin_unlock(&old->i_lock);
> spin_unlock(&inode_hash_lock);
> return -EBUSY;
> @@ -1851,7 +1851,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
>
> might_sleep();
>
> - inode->i_state |= I_CREATING;
> + inode_state_set_raw(inode, I_CREATING);
> old = inode_insert5(inode, hashval, test, NULL, data);
>
> if (old != inode) {
> @@ -1886,7 +1886,7 @@ static void iput_final(struct inode *inode)
> unsigned long state;
> int drop;
>
> - WARN_ON(inode->i_state & I_NEW);
> + WARN_ON(inode_state_read(inode) & I_NEW);
> VFS_BUG_ON_INODE(atomic_read(&inode->i_count) != 0, inode);
>
> if (op->drop_inode)
> @@ -1895,7 +1895,7 @@ static void iput_final(struct inode *inode)
> drop = inode_generic_drop(inode);
>
> if (!drop &&
> - !(inode->i_state & I_DONTCACHE) &&
> + !(inode_state_read(inode) & I_DONTCACHE) &&
> (sb->s_flags & SB_ACTIVE)) {
> __inode_add_lru(inode, true);
> spin_unlock(&inode->i_lock);
> @@ -1908,7 +1908,7 @@ static void iput_final(struct inode *inode)
> */
> VFS_BUG_ON_INODE(atomic_read(&inode->i_count) != 0, inode);
>
> - state = inode->i_state;
> + state = inode_state_read(inode);
> if (!drop) {
> WRITE_ONCE(inode->i_state, state | I_WILL_FREE);
> spin_unlock(&inode->i_lock);
> @@ -1916,7 +1916,7 @@ static void iput_final(struct inode *inode)
> write_inode_now(inode, 1);
>
> spin_lock(&inode->i_lock);
> - state = inode->i_state;
> + state = inode_state_read(inode);
> WARN_ON(state & I_NEW);
> state &= ~I_WILL_FREE;
> }
> @@ -1946,7 +1946,7 @@ void iput(struct inode *inode)
>
> retry:
> lockdep_assert_not_held(&inode->i_lock);
> - VFS_BUG_ON_INODE(inode->i_state & I_CLEAR, inode);
> + VFS_BUG_ON_INODE(inode_state_read_once(inode) & 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
> @@ -1957,14 +1957,14 @@ void iput(struct inode *inode)
> if (atomic_add_unless(&inode->i_count, -1, 1))
> return;
>
> - if ((inode->i_state & I_DIRTY_TIME) && inode->i_nlink) {
> + if ((inode_state_read_once(inode) & 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)) {
> + if (unlikely((inode_state_read(inode) & I_DIRTY_TIME) && inode->i_nlink)) {
> spin_unlock(&inode->i_lock);
> goto retry;
> }
> diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
> index 6f0e6b19383c..0d51f57f7ad7 100644
> --- a/fs/isofs/inode.c
> +++ b/fs/isofs/inode.c
> @@ -1515,7 +1515,7 @@ struct inode *__isofs_iget(struct super_block *sb,
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> ret = isofs_read_inode(inode, relocated);
> if (ret < 0) {
> iget_failed(inode);
> diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
> index d175cccb7c55..764bba8ba999 100644
> --- a/fs/jffs2/fs.c
> +++ b/fs/jffs2/fs.c
> @@ -265,7 +265,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> f = JFFS2_INODE_INFO(inode);
> @@ -373,7 +373,7 @@ void jffs2_dirty_inode(struct inode *inode, int flags)
> {
> struct iattr iattr;
>
> - if (!(inode->i_state & I_DIRTY_DATASYNC)) {
> + if (!(inode_state_read_once(inode) & I_DIRTY_DATASYNC)) {
> jffs2_dbg(2, "%s(): not calling setattr() for ino #%lu\n",
> __func__, inode->i_ino);
> return;
> diff --git a/fs/jfs/file.c b/fs/jfs/file.c
> index 2a4a288b821c..87ad042221e7 100644
> --- a/fs/jfs/file.c
> +++ b/fs/jfs/file.c
> @@ -26,8 +26,8 @@ int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
> return rc;
>
> inode_lock(inode);
> - if (!(inode->i_state & I_DIRTY_ALL) ||
> - (datasync && !(inode->i_state & I_DIRTY_DATASYNC))) {
> + if (!(inode_state_read_once(inode) & I_DIRTY_ALL) ||
> + (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC))) {
> /* Make sure committed changes hit the disk */
> jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1);
> inode_unlock(inode);
> diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
> index 21f3d029da7d..4709762713ef 100644
> --- a/fs/jfs/inode.c
> +++ b/fs/jfs/inode.c
> @@ -29,7 +29,7 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> ret = diRead(inode);
> diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
> index 7840a03e5bcb..c16578af3a77 100644
> --- a/fs/jfs/jfs_txnmgr.c
> +++ b/fs/jfs/jfs_txnmgr.c
> @@ -1287,7 +1287,7 @@ int txCommit(tid_t tid, /* transaction identifier */
> * to verify this, only a trivial s/I_LOCK/I_SYNC/ was done.
> * Joern
> */
> - if (tblk->u.ip->i_state & I_SYNC)
> + if (inode_state_read_once(tblk->u.ip) & I_SYNC)
> tblk->xflag &= ~COMMIT_LAZY;
> }
>
> diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
> index 457f91c412d4..a36aaee98dce 100644
> --- a/fs/kernfs/inode.c
> +++ b/fs/kernfs/inode.c
> @@ -251,7 +251,7 @@ struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn)
> struct inode *inode;
>
> inode = iget_locked(sb, kernfs_ino(kn));
> - if (inode && (inode->i_state & I_NEW))
> + if (inode && (inode_state_read_once(inode) & I_NEW))
> kernfs_init_inode(kn, inode);
>
> return inode;
> diff --git a/fs/libfs.c b/fs/libfs.c
> index ce8c496a6940..96e3d7fc7fc6 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -1542,9 +1542,9 @@ int __generic_file_fsync(struct file *file, loff_t start, loff_t end,
>
> inode_lock(inode);
> ret = sync_mapping_buffers(inode->i_mapping);
> - if (!(inode->i_state & I_DIRTY_ALL))
> + if (!(inode_state_read_once(inode) & I_DIRTY_ALL))
> goto out;
> - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
> + if (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC))
> goto out;
>
> err = sync_inode_metadata(inode, 1);
> @@ -1664,7 +1664,7 @@ struct inode *alloc_anon_inode(struct super_block *s)
> * list because mark_inode_dirty() will think
> * that it already _is_ on the dirty list.
> */
> - inode->i_state = I_DIRTY;
> + inode_state_assign_raw(inode, I_DIRTY);
> /*
> * Historically anonymous inodes don't have a type at all and
> * userspace has come to rely on this.
> diff --git a/fs/minix/inode.c b/fs/minix/inode.c
> index 32db676127a9..f220d0e4aedf 100644
> --- a/fs/minix/inode.c
> +++ b/fs/minix/inode.c
> @@ -589,7 +589,7 @@ struct inode *minix_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> if (INODE_VERSION(inode) == MINIX_V1)
> diff --git a/fs/namei.c b/fs/namei.c
> index 7377020a2cba..354a9e844721 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -4036,7 +4036,7 @@ int vfs_tmpfile(struct mnt_idmap *idmap,
> inode = file_inode(file);
> if (!(open_flag & O_EXCL)) {
> spin_lock(&inode->i_lock);
> - inode->i_state |= I_LINKABLE;
> + inode_state_set(inode, I_LINKABLE);
> spin_unlock(&inode->i_lock);
> }
> security_inode_post_create_tmpfile(idmap, inode);
> @@ -4931,7 +4931,7 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
>
> inode_lock(inode);
> /* Make sure we don't allow creating hardlink to an unlinked file */
> - if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
> + if (inode->i_nlink == 0 && !(inode_state_read_once(inode) & I_LINKABLE))
> error = -ENOENT;
> else if (max_links && inode->i_nlink >= max_links)
> error = -EMLINK;
> @@ -4941,9 +4941,9 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
> error = dir->i_op->link(old_dentry, dir, new_dentry);
> }
>
> - if (!error && (inode->i_state & I_LINKABLE)) {
> + if (!error && (inode_state_read_once(inode) & I_LINKABLE)) {
> spin_lock(&inode->i_lock);
> - inode->i_state &= ~I_LINKABLE;
> + inode_state_clear(inode, I_LINKABLE);
> spin_unlock(&inode->i_lock);
> }
> inode_unlock(inode);
> diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c
> index 486166460e17..3b97bc35de77 100644
> --- a/fs/netfs/misc.c
> +++ b/fs/netfs/misc.c
> @@ -147,10 +147,10 @@ bool netfs_dirty_folio(struct address_space *mapping, struct folio *folio)
> if (!fscache_cookie_valid(cookie))
> return true;
>
> - if (!(inode->i_state & I_PINNING_NETFS_WB)) {
> + if (!(inode_state_read_once(inode) & I_PINNING_NETFS_WB)) {
> spin_lock(&inode->i_lock);
> - if (!(inode->i_state & I_PINNING_NETFS_WB)) {
> - inode->i_state |= I_PINNING_NETFS_WB;
> + if (!(inode_state_read(inode) & I_PINNING_NETFS_WB)) {
> + inode_state_set(inode, I_PINNING_NETFS_WB);
> need_use = true;
> }
> spin_unlock(&inode->i_lock);
> @@ -192,7 +192,7 @@ void netfs_clear_inode_writeback(struct inode *inode, const void *aux)
> {
> struct fscache_cookie *cookie = netfs_i_cookie(netfs_inode(inode));
>
> - if (inode->i_state & I_PINNING_NETFS_WB) {
> + if (inode_state_read_once(inode) & I_PINNING_NETFS_WB) {
> loff_t i_size = i_size_read(inode);
> fscache_unuse_cookie(cookie, aux, &i_size);
> }
> diff --git a/fs/netfs/read_single.c b/fs/netfs/read_single.c
> index 5c0dc4efc792..8e6264f62a8f 100644
> --- a/fs/netfs/read_single.c
> +++ b/fs/netfs/read_single.c
> @@ -36,12 +36,12 @@ void netfs_single_mark_inode_dirty(struct inode *inode)
>
> mark_inode_dirty(inode);
>
> - if (caching && !(inode->i_state & I_PINNING_NETFS_WB)) {
> + if (caching && !(inode_state_read_once(inode) & I_PINNING_NETFS_WB)) {
> bool need_use = false;
>
> spin_lock(&inode->i_lock);
> - if (!(inode->i_state & I_PINNING_NETFS_WB)) {
> - inode->i_state |= I_PINNING_NETFS_WB;
> + if (!(inode_state_read(inode) & I_PINNING_NETFS_WB)) {
> + inode_state_set(inode, I_PINNING_NETFS_WB);
> need_use = true;
> }
> spin_unlock(&inode->i_lock);
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 18b57c7c2f97..9e3b1f10ce80 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -475,7 +475,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
> goto out_no_inode;
> }
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> struct nfs_inode *nfsi = NFS_I(inode);
> unsigned long now = jiffies;
>
> diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
> index a3135b5af7ee..f157d43d1312 100644
> --- a/fs/nfs/pnfs.c
> +++ b/fs/nfs/pnfs.c
> @@ -317,7 +317,7 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
> WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n");
> pnfs_detach_layout_hdr(lo);
> /* Notify pnfs_destroy_layout_final() that we're done */
> - if (inode->i_state & (I_FREEING | I_CLEAR))
> + if (inode_state_read(inode) & (I_FREEING | I_CLEAR))
> wake_up_var_locked(lo, &inode->i_lock);
> spin_unlock(&inode->i_lock);
> pnfs_free_layout_hdr(lo);
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index 9cb20d4aeab1..cf4062ac092a 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -1159,7 +1159,7 @@ static int wait_for_concurrent_writes(struct file *file)
> dprintk("nfsd: write resume %d\n", task_pid_nr(current));
> }
>
> - if (inode->i_state & I_DIRTY) {
> + if (inode_state_read_once(inode) & I_DIRTY) {
> dprintk("nfsd: write sync %d\n", task_pid_nr(current));
> err = vfs_fsync(file, 0);
> }
> diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
> index 46bfc543f946..d27ff5e5f165 100644
> --- a/fs/notify/fsnotify.c
> +++ b/fs/notify/fsnotify.c
> @@ -52,7 +52,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
> * the inode cannot have any associated watches.
> */
> spin_lock(&inode->i_lock);
> - if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) {
> + if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) {
> spin_unlock(&inode->i_lock);
> continue;
> }
> diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
> index 3959f23c487a..08266adc42ba 100644
> --- a/fs/ntfs3/inode.c
> +++ b/fs/ntfs3/inode.c
> @@ -537,7 +537,7 @@ struct inode *ntfs_iget5(struct super_block *sb, const struct MFT_REF *ref,
> return ERR_PTR(-ENOMEM);
>
> /* If this is a freshly allocated inode, need to read it now. */
> - if (inode->i_state & I_NEW)
> + if (inode_state_read_once(inode) & I_NEW)
> inode = ntfs_read_mft(inode, name, ref);
> else if (ref->seq != ntfs_i(inode)->mi.mrec->seq) {
> /*
> diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
> index 92a6149da9c1..619ff03b15d6 100644
> --- a/fs/ocfs2/dlmglue.c
> +++ b/fs/ocfs2/dlmglue.c
> @@ -2487,7 +2487,7 @@ int ocfs2_inode_lock_full_nested(struct inode *inode,
> * which hasn't been populated yet, so clear the refresh flag
> * and let the caller handle it.
> */
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> status = 0;
> if (lockres)
> ocfs2_complete_lock_res_refresh(lockres, 0);
> diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
> index 84115bf8b464..78f81950c9ee 100644
> --- a/fs/ocfs2/inode.c
> +++ b/fs/ocfs2/inode.c
> @@ -152,8 +152,8 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
> mlog_errno(PTR_ERR(inode));
> goto bail;
> }
> - trace_ocfs2_iget5_locked(inode->i_state);
> - if (inode->i_state & I_NEW) {
> + trace_ocfs2_iget5_locked(inode_state_read_once(inode));
> + if (inode_state_read_once(inode) & I_NEW) {
> rc = ocfs2_read_locked_inode(inode, &args);
> unlock_new_inode(inode);
> }
> diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
> index 135c49c5d848..db80af312678 100644
> --- a/fs/omfs/inode.c
> +++ b/fs/omfs/inode.c
> @@ -212,7 +212,7 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> bh = omfs_bread(inode->i_sb, ino);
> diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
> index 26ecda0e4d19..fb8d84bdedfb 100644
> --- a/fs/openpromfs/inode.c
> +++ b/fs/openpromfs/inode.c
> @@ -236,7 +236,7 @@ static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry
> mutex_unlock(&op_mutex);
> if (IS_ERR(inode))
> return ERR_CAST(inode);
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> simple_inode_init_ts(inode);
> ent_oi = OP_I(inode);
> ent_oi->type = ent_type;
> diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
> index a01400cd41fd..1eb4fbe35a46 100644
> --- a/fs/orangefs/inode.c
> +++ b/fs/orangefs/inode.c
> @@ -1041,7 +1041,7 @@ struct inode *orangefs_iget(struct super_block *sb,
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> error = orangefs_inode_getattr(inode, ORANGEFS_GETATTR_NEW);
> diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c
> index 0fdceb00ca07..9ab1119ebd28 100644
> --- a/fs/orangefs/orangefs-utils.c
> +++ b/fs/orangefs/orangefs-utils.c
> @@ -247,7 +247,7 @@ int orangefs_inode_getattr(struct inode *inode, int flags)
> spin_lock(&inode->i_lock);
> /* Must have all the attributes in the mask and be within cache time. */
> if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
> - orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) {
> + orangefs_inode->attr_valid || inode_state_read(inode) & I_DIRTY_PAGES) {
> if (orangefs_inode->attr_valid) {
> spin_unlock(&inode->i_lock);
> write_inode_now(inode, 1);
> @@ -281,13 +281,13 @@ int orangefs_inode_getattr(struct inode *inode, int flags)
> spin_lock(&inode->i_lock);
> /* Must have all the attributes in the mask and be within cache time. */
> if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
> - orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) {
> + orangefs_inode->attr_valid || inode_state_read(inode) & I_DIRTY_PAGES) {
> if (orangefs_inode->attr_valid) {
> spin_unlock(&inode->i_lock);
> write_inode_now(inode, 1);
> goto again2;
> }
> - if (inode->i_state & I_DIRTY_PAGES) {
> + if (inode_state_read(inode) & I_DIRTY_PAGES) {
> ret = 0;
> goto out_unlock;
> }
> diff --git a/fs/pipe.c b/fs/pipe.c
> index 42fead1efe52..2d0fed2ecbfd 100644
> --- a/fs/pipe.c
> +++ b/fs/pipe.c
> @@ -908,7 +908,7 @@ static struct inode * get_pipe_inode(void)
> * list because "mark_inode_dirty()" will think
> * that it already _is_ on the dirty list.
> */
> - inode->i_state = I_DIRTY;
> + inode_state_assign_raw(inode, I_DIRTY);
> inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
> inode->i_uid = current_fsuid();
> inode->i_gid = current_fsgid();
> diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
> index e399e2dd3a12..31d78da203ea 100644
> --- a/fs/qnx4/inode.c
> +++ b/fs/qnx4/inode.c
> @@ -290,7 +290,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> qnx4_inode = qnx4_raw_inode(inode);
> diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
> index 3310d1ad4d0e..88d285005083 100644
> --- a/fs/qnx6/inode.c
> +++ b/fs/qnx6/inode.c
> @@ -521,7 +521,7 @@ struct inode *qnx6_iget(struct super_block *sb, unsigned ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> ei = QNX6_I(inode);
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 6c4a6ee1fa2b..376739f6420e 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -1033,7 +1033,7 @@ static int add_dquot_ref(struct super_block *sb, int type)
> spin_lock(&sb->s_inode_list_lock);
> list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
> spin_lock(&inode->i_lock);
> - if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
> + if ((inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) ||
> !atomic_read(&inode->i_writecount) ||
> !dqinit_needed(inode, type)) {
> spin_unlock(&inode->i_lock);
> diff --git a/fs/romfs/super.c b/fs/romfs/super.c
> index 0addcc849ff2..360b00854115 100644
> --- a/fs/romfs/super.c
> +++ b/fs/romfs/super.c
> @@ -302,7 +302,7 @@ static struct inode *romfs_iget(struct super_block *sb, unsigned long pos)
> if (!i)
> return ERR_PTR(-ENOMEM);
>
> - if (!(i->i_state & I_NEW))
> + if (!(inode_state_read_once(i) & I_NEW))
> return i;
>
> /* precalculate the data offset */
> diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
> index cceae3b78698..82b687414e65 100644
> --- a/fs/squashfs/inode.c
> +++ b/fs/squashfs/inode.c
> @@ -86,7 +86,7 @@ struct inode *squashfs_iget(struct super_block *sb, long long ino,
>
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> err = squashfs_read_inode(inode, ino);
> diff --git a/fs/sync.c b/fs/sync.c
> index 2955cd4c77a3..73b3efb35b26 100644
> --- a/fs/sync.c
> +++ b/fs/sync.c
> @@ -182,7 +182,7 @@ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
>
> if (!file->f_op->fsync)
> return -EINVAL;
> - if (!datasync && (inode->i_state & I_DIRTY_TIME))
> + if (!datasync && (inode_state_read_once(inode) & I_DIRTY_TIME))
> mark_inode_dirty_sync(inode);
> return file->f_op->fsync(file, start, end, datasync);
> }
> diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
> index ca41ce8208c4..c3265b8804f5 100644
> --- a/fs/ubifs/file.c
> +++ b/fs/ubifs/file.c
> @@ -1323,7 +1323,7 @@ int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
> inode_lock(inode);
>
> /* Synchronize the inode unless this is a 'datasync()' call. */
> - if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) {
> + if (!datasync || (inode_state_read_once(inode) & I_DIRTY_DATASYNC)) {
> err = inode->i_sb->s_op->write_inode(inode, NULL);
> if (err)
> goto out;
> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
> index 46952a33c4e6..f453c37cee37 100644
> --- a/fs/ubifs/super.c
> +++ b/fs/ubifs/super.c
> @@ -114,7 +114,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
> inode = iget_locked(sb, inum);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
> ui = ubifs_inode(inode);
>
> diff --git a/fs/udf/inode.c b/fs/udf/inode.c
> index a79d73f28aa7..7fae8002344a 100644
> --- a/fs/udf/inode.c
> +++ b/fs/udf/inode.c
> @@ -1962,7 +1962,7 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (!(inode->i_state & I_NEW)) {
> + if (!(inode_state_read_once(inode) & I_NEW)) {
> if (UDF_I(inode)->i_hidden != hidden_inode) {
> iput(inode);
> return ERR_PTR(-EFSCORRUPTED);
> diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
> index 8361c00e8fa6..e2b0a35de2a7 100644
> --- a/fs/ufs/inode.c
> +++ b/fs/ufs/inode.c
> @@ -655,7 +655,7 @@ struct inode *ufs_iget(struct super_block *sb, unsigned long ino)
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> ufsi = UFS_I(inode);
> diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
> index 70be0b3dda49..086a31269198 100644
> --- a/fs/zonefs/super.c
> +++ b/fs/zonefs/super.c
> @@ -644,7 +644,7 @@ static struct inode *zonefs_get_file_inode(struct inode *dir,
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW)) {
> + if (!(inode_state_read_once(inode) & I_NEW)) {
> WARN_ON_ONCE(inode->i_private != z);
> return inode;
> }
> @@ -683,7 +683,7 @@ static struct inode *zonefs_get_zgroup_inode(struct super_block *sb,
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> inode->i_ino = ino;
> diff --git a/mm/backing-dev.c b/mm/backing-dev.c
> index 41b6c9386b69..c5740c6d37a2 100644
> --- a/mm/backing-dev.c
> +++ b/mm/backing-dev.c
> @@ -72,7 +72,7 @@ static void collect_wb_stats(struct wb_stats *stats,
> list_for_each_entry(inode, &wb->b_more_io, i_io_list)
> stats->nr_more_io++;
> list_for_each_entry(inode, &wb->b_dirty_time, i_io_list)
> - if (inode->i_state & I_DIRTY_TIME)
> + if (inode_state_read_once(inode) & I_DIRTY_TIME)
> stats->nr_dirty_time++;
> spin_unlock(&wb->list_lock);
>
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index 0bade2c5aa1d..d4d72f406d58 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -1296,7 +1296,7 @@ static void hook_sb_delete(struct super_block *const sb)
> * second call to iput() for the same Landlock object. Also
> * checks I_NEW because such inode cannot be tied to an object.
> */
> - if (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) {
> + if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) {
> spin_unlock(&inode->i_lock);
> continue;
> }
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 05/14] Manual conversion to use ->i_state accessors of all places not covered by coccinelle
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (3 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 04/14] Coccinelle-based conversion to use ->i_state accessors Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:10 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 06/14] btrfs: use the new ->i_state accessors Mateusz Guzik
` (10 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Nothing to look at apart from iput_final().
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
Documentation/filesystems/porting.rst | 2 +-
fs/afs/inode.c | 2 +-
fs/ext4/inode.c | 10 +++++-----
fs/ext4/orphan.c | 4 ++--
fs/inode.c | 18 ++++++++----------
include/linux/backing-dev.h | 2 +-
include/linux/fs.h | 6 +++---
include/linux/writeback.h | 2 +-
include/trace/events/writeback.h | 8 ++++----
9 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
index 7233b04668fc..35f027981b21 100644
--- a/Documentation/filesystems/porting.rst
+++ b/Documentation/filesystems/porting.rst
@@ -211,7 +211,7 @@ test and set for you.
e.g.::
inode = iget_locked(sb, ino);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
err = read_inode_from_disk(inode);
if (err < 0) {
iget_failed(inode);
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 2fe2ccf59c7a..dde1857fcabb 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -427,7 +427,7 @@ static void afs_fetch_status_success(struct afs_operation *op)
struct afs_vnode *vnode = vp->vnode;
int ret;
- if (vnode->netfs.inode.i_state & I_NEW) {
+ if (inode_state_read_once(&vnode->netfs.inode) & I_NEW) {
ret = afs_inode_init_from_status(op, vp, vnode);
afs_op_set_error(op, ret);
if (ret == 0)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index f9e4ac87211e..b864e9645f85 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -425,7 +425,7 @@ void ext4_check_map_extents_env(struct inode *inode)
if (!S_ISREG(inode->i_mode) ||
IS_NOQUOTA(inode) || IS_VERITY(inode) ||
is_special_ino(inode->i_sb, inode->i_ino) ||
- (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) ||
+ (inode_state_read_once(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) ||
ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) ||
ext4_verity_in_progress(inode))
return;
@@ -3473,7 +3473,7 @@ static bool ext4_inode_datasync_dirty(struct inode *inode)
/* Any metadata buffers to write? */
if (!list_empty(&inode->i_mapping->i_private_list))
return true;
- return inode->i_state & I_DIRTY_DATASYNC;
+ return inode_state_read_once(inode) & I_DIRTY_DATASYNC;
}
static void ext4_set_iomap(struct inode *inode, struct iomap *iomap,
@@ -4552,7 +4552,7 @@ int ext4_truncate(struct inode *inode)
* or it's a completely new inode. In those cases we might not
* have i_rwsem locked because it's not necessary.
*/
- if (!(inode->i_state & (I_NEW|I_FREEING)))
+ if (!(inode_state_read_once(inode) & (I_NEW | I_FREEING)))
WARN_ON(!inode_is_locked(inode));
trace_ext4_truncate_enter(inode);
@@ -5210,7 +5210,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW)) {
+ if (!(inode_state_read_once(inode) & I_NEW)) {
ret = check_igot_inode(inode, flags, function, line);
if (ret) {
iput(inode);
@@ -5541,7 +5541,7 @@ static void __ext4_update_other_inode_time(struct super_block *sb,
if (inode_is_dirtytime_only(inode)) {
struct ext4_inode_info *ei = EXT4_I(inode);
- inode->i_state &= ~I_DIRTY_TIME;
+ inode_state_clear(inode, I_DIRTY_TIME);
spin_unlock(&inode->i_lock);
spin_lock(&ei->i_raw_lock);
diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c
index 33c3a89396b1..c4903d98ff81 100644
--- a/fs/ext4/orphan.c
+++ b/fs/ext4/orphan.c
@@ -107,7 +107,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
if (!sbi->s_journal || is_bad_inode(inode))
return 0;
- WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) &&
+ WARN_ON_ONCE(!(inode_state_read_once(inode) & (I_NEW | I_FREEING)) &&
!inode_is_locked(inode));
if (ext4_inode_orphan_tracked(inode))
return 0;
@@ -232,7 +232,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
if (!sbi->s_journal && !(sbi->s_mount_state & EXT4_ORPHAN_FS))
return 0;
- WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) &&
+ WARN_ON_ONCE(!(inode_state_read_once(inode) & (I_NEW | I_FREEING)) &&
!inode_is_locked(inode));
if (ext4_test_inode_state(inode, EXT4_STATE_ORPHAN_FILE))
return ext4_orphan_file_del(handle, inode);
diff --git a/fs/inode.c b/fs/inode.c
index f094ed3e6f30..3153d725859c 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -829,7 +829,7 @@ static void evict(struct inode *inode)
* This also means we don't need any fences for the call below.
*/
inode_wake_up_bit(inode, __I_NEW);
- BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
+ BUG_ON(inode_state_read_once(inode) != (I_FREEING | I_CLEAR));
destroy_inode(inode);
}
@@ -1883,7 +1883,6 @@ static void iput_final(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
const struct super_operations *op = inode->i_sb->s_op;
- unsigned long state;
int drop;
WARN_ON(inode_state_read(inode) & I_NEW);
@@ -1908,20 +1907,19 @@ static void iput_final(struct inode *inode)
*/
VFS_BUG_ON_INODE(atomic_read(&inode->i_count) != 0, inode);
- state = inode_state_read(inode);
- if (!drop) {
- WRITE_ONCE(inode->i_state, state | I_WILL_FREE);
+ if (drop) {
+ inode_state_set(inode, I_FREEING);
+ } else {
+ inode_state_set(inode, I_WILL_FREE);
spin_unlock(&inode->i_lock);
write_inode_now(inode, 1);
spin_lock(&inode->i_lock);
- state = inode_state_read(inode);
- WARN_ON(state & I_NEW);
- state &= ~I_WILL_FREE;
+ WARN_ON(inode_state_read(inode) & I_NEW);
+ inode_state_replace(inode, I_WILL_FREE, I_FREEING);
}
- WRITE_ONCE(inode->i_state, state | I_FREEING);
if (!list_empty(&inode->i_lru))
inode_lru_list_del(inode);
spin_unlock(&inode->i_lock);
@@ -2985,7 +2983,7 @@ void dump_inode(struct inode *inode, const char *reason)
pr_warn("%s encountered for inode %px\n"
"fs %s mode %ho opflags 0x%hx flags 0x%x state 0x%x count %d\n",
reason, inode, sb->s_type->name, inode->i_mode, inode->i_opflags,
- inode->i_flags, inode->i_state, atomic_read(&inode->i_count));
+ inode->i_flags, inode_state_read_once(inode), atomic_read(&inode->i_count));
}
EXPORT_SYMBOL(dump_inode);
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 065cba5dc111..0c8342747cab 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -280,7 +280,7 @@ unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
* Paired with a release fence in inode_do_switch_wbs() and
* ensures that we see the new wb if we see cleared I_WB_SWITCH.
*/
- cookie->locked = inode->i_state & I_WB_SWITCH;
+ cookie->locked = inode_state_read_once(inode) & I_WB_SWITCH;
smp_rmb();
if (unlikely(cookie->locked))
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 909eb1e68637..77b6486dcae7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1026,7 +1026,7 @@ static inline void inode_fake_hash(struct inode *inode)
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));
+ !(inode_state_read_once(inode) & I_NEW));
/*
* Pairs with routines clearing I_NEW.
*/
@@ -2719,8 +2719,8 @@ static inline int icount_read(const struct inode *inode)
*/
static inline bool inode_is_dirtytime_only(struct inode *inode)
{
- return (inode->i_state & (I_DIRTY_TIME | I_NEW |
- I_FREEING | I_WILL_FREE)) == I_DIRTY_TIME;
+ return (inode_state_read_once(inode) &
+ (I_DIRTY_TIME | I_NEW | I_FREEING | I_WILL_FREE)) == I_DIRTY_TIME;
}
extern void inc_nlink(struct inode *inode);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 06195c2a535b..102071ffedcb 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -227,7 +227,7 @@ static inline void inode_attach_wb(struct inode *inode, struct folio *folio)
static inline void inode_detach_wb(struct inode *inode)
{
if (inode->i_wb) {
- WARN_ON_ONCE(!(inode->i_state & I_CLEAR));
+ WARN_ON_ONCE(!(inode_state_read_once(inode) & I_CLEAR));
wb_put(inode->i_wb);
inode->i_wb = NULL;
}
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
index c08aff044e80..311a341e6fe4 100644
--- a/include/trace/events/writeback.h
+++ b/include/trace/events/writeback.h
@@ -120,7 +120,7 @@ DECLARE_EVENT_CLASS(writeback_dirty_inode_template,
/* may be called for files on pseudo FSes w/ unregistered bdi */
strscpy_pad(__entry->name, bdi_dev_name(bdi), 32);
__entry->ino = inode->i_ino;
- __entry->state = inode->i_state;
+ __entry->state = inode_state_read_once(inode);
__entry->flags = flags;
),
@@ -748,7 +748,7 @@ TRACE_EVENT(writeback_sb_inodes_requeue,
strscpy_pad(__entry->name,
bdi_dev_name(inode_to_bdi(inode)), 32);
__entry->ino = inode->i_ino;
- __entry->state = inode->i_state;
+ __entry->state = inode_state_read_once(inode);
__entry->dirtied_when = inode->dirtied_when;
__entry->cgroup_ino = __trace_wb_assign_cgroup(inode_to_wb(inode));
),
@@ -787,7 +787,7 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template,
strscpy_pad(__entry->name,
bdi_dev_name(inode_to_bdi(inode)), 32);
__entry->ino = inode->i_ino;
- __entry->state = inode->i_state;
+ __entry->state = inode_state_read_once(inode);
__entry->dirtied_when = inode->dirtied_when;
__entry->writeback_index = inode->i_mapping->writeback_index;
__entry->nr_to_write = nr_to_write;
@@ -839,7 +839,7 @@ DECLARE_EVENT_CLASS(writeback_inode_template,
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
- __entry->state = inode->i_state;
+ __entry->state = inode_state_read_once(inode);
__entry->mode = inode->i_mode;
__entry->dirtied_when = inode->dirtied_when;
),
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 05/14] Manual conversion to use ->i_state accessors of all places not covered by coccinelle
2025-10-09 7:59 ` [PATCH v7 05/14] Manual conversion to use ->i_state accessors of all places not covered by coccinelle Mateusz Guzik
@ 2025-10-10 14:10 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:10 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:19, Mateusz Guzik wrote:
> Nothing to look at apart from iput_final().
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> Documentation/filesystems/porting.rst | 2 +-
> fs/afs/inode.c | 2 +-
> fs/ext4/inode.c | 10 +++++-----
> fs/ext4/orphan.c | 4 ++--
> fs/inode.c | 18 ++++++++----------
> include/linux/backing-dev.h | 2 +-
> include/linux/fs.h | 6 +++---
> include/linux/writeback.h | 2 +-
> include/trace/events/writeback.h | 8 ++++----
> 9 files changed, 26 insertions(+), 28 deletions(-)
>
> diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
> index 7233b04668fc..35f027981b21 100644
> --- a/Documentation/filesystems/porting.rst
> +++ b/Documentation/filesystems/porting.rst
> @@ -211,7 +211,7 @@ test and set for you.
> e.g.::
>
> inode = iget_locked(sb, ino);
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> err = read_inode_from_disk(inode);
> if (err < 0) {
> iget_failed(inode);
> diff --git a/fs/afs/inode.c b/fs/afs/inode.c
> index 2fe2ccf59c7a..dde1857fcabb 100644
> --- a/fs/afs/inode.c
> +++ b/fs/afs/inode.c
> @@ -427,7 +427,7 @@ static void afs_fetch_status_success(struct afs_operation *op)
> struct afs_vnode *vnode = vp->vnode;
> int ret;
>
> - if (vnode->netfs.inode.i_state & I_NEW) {
> + if (inode_state_read_once(&vnode->netfs.inode) & I_NEW) {
> ret = afs_inode_init_from_status(op, vp, vnode);
> afs_op_set_error(op, ret);
> if (ret == 0)
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index f9e4ac87211e..b864e9645f85 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -425,7 +425,7 @@ void ext4_check_map_extents_env(struct inode *inode)
> if (!S_ISREG(inode->i_mode) ||
> IS_NOQUOTA(inode) || IS_VERITY(inode) ||
> is_special_ino(inode->i_sb, inode->i_ino) ||
> - (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) ||
> + (inode_state_read_once(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) ||
> ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) ||
> ext4_verity_in_progress(inode))
> return;
> @@ -3473,7 +3473,7 @@ static bool ext4_inode_datasync_dirty(struct inode *inode)
> /* Any metadata buffers to write? */
> if (!list_empty(&inode->i_mapping->i_private_list))
> return true;
> - return inode->i_state & I_DIRTY_DATASYNC;
> + return inode_state_read_once(inode) & I_DIRTY_DATASYNC;
> }
>
> static void ext4_set_iomap(struct inode *inode, struct iomap *iomap,
> @@ -4552,7 +4552,7 @@ int ext4_truncate(struct inode *inode)
> * or it's a completely new inode. In those cases we might not
> * have i_rwsem locked because it's not necessary.
> */
> - if (!(inode->i_state & (I_NEW|I_FREEING)))
> + if (!(inode_state_read_once(inode) & (I_NEW | I_FREEING)))
> WARN_ON(!inode_is_locked(inode));
> trace_ext4_truncate_enter(inode);
>
> @@ -5210,7 +5210,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
> inode = iget_locked(sb, ino);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW)) {
> + if (!(inode_state_read_once(inode) & I_NEW)) {
> ret = check_igot_inode(inode, flags, function, line);
> if (ret) {
> iput(inode);
> @@ -5541,7 +5541,7 @@ static void __ext4_update_other_inode_time(struct super_block *sb,
> if (inode_is_dirtytime_only(inode)) {
> struct ext4_inode_info *ei = EXT4_I(inode);
>
> - inode->i_state &= ~I_DIRTY_TIME;
> + inode_state_clear(inode, I_DIRTY_TIME);
> spin_unlock(&inode->i_lock);
>
> spin_lock(&ei->i_raw_lock);
> diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c
> index 33c3a89396b1..c4903d98ff81 100644
> --- a/fs/ext4/orphan.c
> +++ b/fs/ext4/orphan.c
> @@ -107,7 +107,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
> if (!sbi->s_journal || is_bad_inode(inode))
> return 0;
>
> - WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) &&
> + WARN_ON_ONCE(!(inode_state_read_once(inode) & (I_NEW | I_FREEING)) &&
> !inode_is_locked(inode));
> if (ext4_inode_orphan_tracked(inode))
> return 0;
> @@ -232,7 +232,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
> if (!sbi->s_journal && !(sbi->s_mount_state & EXT4_ORPHAN_FS))
> return 0;
>
> - WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) &&
> + WARN_ON_ONCE(!(inode_state_read_once(inode) & (I_NEW | I_FREEING)) &&
> !inode_is_locked(inode));
> if (ext4_test_inode_state(inode, EXT4_STATE_ORPHAN_FILE))
> return ext4_orphan_file_del(handle, inode);
> diff --git a/fs/inode.c b/fs/inode.c
> index f094ed3e6f30..3153d725859c 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -829,7 +829,7 @@ static void evict(struct inode *inode)
> * This also means we don't need any fences for the call below.
> */
> inode_wake_up_bit(inode, __I_NEW);
> - BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
> + BUG_ON(inode_state_read_once(inode) != (I_FREEING | I_CLEAR));
>
> destroy_inode(inode);
> }
> @@ -1883,7 +1883,6 @@ static void iput_final(struct inode *inode)
> {
> struct super_block *sb = inode->i_sb;
> const struct super_operations *op = inode->i_sb->s_op;
> - unsigned long state;
> int drop;
>
> WARN_ON(inode_state_read(inode) & I_NEW);
> @@ -1908,20 +1907,19 @@ static void iput_final(struct inode *inode)
> */
> VFS_BUG_ON_INODE(atomic_read(&inode->i_count) != 0, inode);
>
> - state = inode_state_read(inode);
> - if (!drop) {
> - WRITE_ONCE(inode->i_state, state | I_WILL_FREE);
> + if (drop) {
> + inode_state_set(inode, I_FREEING);
> + } else {
> + inode_state_set(inode, I_WILL_FREE);
> spin_unlock(&inode->i_lock);
>
> write_inode_now(inode, 1);
>
> spin_lock(&inode->i_lock);
> - state = inode_state_read(inode);
> - WARN_ON(state & I_NEW);
> - state &= ~I_WILL_FREE;
> + WARN_ON(inode_state_read(inode) & I_NEW);
> + inode_state_replace(inode, I_WILL_FREE, I_FREEING);
> }
>
> - WRITE_ONCE(inode->i_state, state | I_FREEING);
> if (!list_empty(&inode->i_lru))
> inode_lru_list_del(inode);
> spin_unlock(&inode->i_lock);
> @@ -2985,7 +2983,7 @@ void dump_inode(struct inode *inode, const char *reason)
> pr_warn("%s encountered for inode %px\n"
> "fs %s mode %ho opflags 0x%hx flags 0x%x state 0x%x count %d\n",
> reason, inode, sb->s_type->name, inode->i_mode, inode->i_opflags,
> - inode->i_flags, inode->i_state, atomic_read(&inode->i_count));
> + inode->i_flags, inode_state_read_once(inode), atomic_read(&inode->i_count));
> }
>
> EXPORT_SYMBOL(dump_inode);
> diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
> index 065cba5dc111..0c8342747cab 100644
> --- a/include/linux/backing-dev.h
> +++ b/include/linux/backing-dev.h
> @@ -280,7 +280,7 @@ unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
> * Paired with a release fence in inode_do_switch_wbs() and
> * ensures that we see the new wb if we see cleared I_WB_SWITCH.
> */
> - cookie->locked = inode->i_state & I_WB_SWITCH;
> + cookie->locked = inode_state_read_once(inode) & I_WB_SWITCH;
> smp_rmb();
>
> if (unlikely(cookie->locked))
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 909eb1e68637..77b6486dcae7 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1026,7 +1026,7 @@ static inline void inode_fake_hash(struct inode *inode)
> 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));
> + !(inode_state_read_once(inode) & I_NEW));
> /*
> * Pairs with routines clearing I_NEW.
> */
> @@ -2719,8 +2719,8 @@ static inline int icount_read(const struct inode *inode)
> */
> static inline bool inode_is_dirtytime_only(struct inode *inode)
> {
> - return (inode->i_state & (I_DIRTY_TIME | I_NEW |
> - I_FREEING | I_WILL_FREE)) == I_DIRTY_TIME;
> + return (inode_state_read_once(inode) &
> + (I_DIRTY_TIME | I_NEW | I_FREEING | I_WILL_FREE)) == I_DIRTY_TIME;
> }
>
> extern void inc_nlink(struct inode *inode);
> diff --git a/include/linux/writeback.h b/include/linux/writeback.h
> index 06195c2a535b..102071ffedcb 100644
> --- a/include/linux/writeback.h
> +++ b/include/linux/writeback.h
> @@ -227,7 +227,7 @@ static inline void inode_attach_wb(struct inode *inode, struct folio *folio)
> static inline void inode_detach_wb(struct inode *inode)
> {
> if (inode->i_wb) {
> - WARN_ON_ONCE(!(inode->i_state & I_CLEAR));
> + WARN_ON_ONCE(!(inode_state_read_once(inode) & I_CLEAR));
> wb_put(inode->i_wb);
> inode->i_wb = NULL;
> }
> diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
> index c08aff044e80..311a341e6fe4 100644
> --- a/include/trace/events/writeback.h
> +++ b/include/trace/events/writeback.h
> @@ -120,7 +120,7 @@ DECLARE_EVENT_CLASS(writeback_dirty_inode_template,
> /* may be called for files on pseudo FSes w/ unregistered bdi */
> strscpy_pad(__entry->name, bdi_dev_name(bdi), 32);
> __entry->ino = inode->i_ino;
> - __entry->state = inode->i_state;
> + __entry->state = inode_state_read_once(inode);
> __entry->flags = flags;
> ),
>
> @@ -748,7 +748,7 @@ TRACE_EVENT(writeback_sb_inodes_requeue,
> strscpy_pad(__entry->name,
> bdi_dev_name(inode_to_bdi(inode)), 32);
> __entry->ino = inode->i_ino;
> - __entry->state = inode->i_state;
> + __entry->state = inode_state_read_once(inode);
> __entry->dirtied_when = inode->dirtied_when;
> __entry->cgroup_ino = __trace_wb_assign_cgroup(inode_to_wb(inode));
> ),
> @@ -787,7 +787,7 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template,
> strscpy_pad(__entry->name,
> bdi_dev_name(inode_to_bdi(inode)), 32);
> __entry->ino = inode->i_ino;
> - __entry->state = inode->i_state;
> + __entry->state = inode_state_read_once(inode);
> __entry->dirtied_when = inode->dirtied_when;
> __entry->writeback_index = inode->i_mapping->writeback_index;
> __entry->nr_to_write = nr_to_write;
> @@ -839,7 +839,7 @@ DECLARE_EVENT_CLASS(writeback_inode_template,
> TP_fast_assign(
> __entry->dev = inode->i_sb->s_dev;
> __entry->ino = inode->i_ino;
> - __entry->state = inode->i_state;
> + __entry->state = inode_state_read_once(inode);
> __entry->mode = inode->i_mode;
> __entry->dirtied_when = inode->dirtied_when;
> ),
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 06/14] btrfs: use the new ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (4 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 05/14] Manual conversion to use ->i_state accessors of all places not covered by coccinelle Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:11 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 07/14] ceph: " Mateusz Guzik
` (9 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Change generated with coccinelle and fixed up by hand as appropriate.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
cheat sheet:
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
fs/btrfs/inode.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3b1b3a0553ee..433ffe231546 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3884,7 +3884,7 @@ static int btrfs_add_inode_to_root(struct btrfs_inode *inode, bool prealloc)
ASSERT(ret != -ENOMEM);
return ret;
} else if (existing) {
- WARN_ON(!(existing->vfs_inode.i_state & (I_WILL_FREE | I_FREEING)));
+ WARN_ON(!(inode_state_read_once(&existing->vfs_inode) & (I_WILL_FREE | I_FREEING)));
}
return 0;
@@ -5361,7 +5361,7 @@ static void evict_inode_truncate_pages(struct inode *inode)
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct rb_node *node;
- ASSERT(inode->i_state & I_FREEING);
+ ASSERT(inode_state_read_once(inode) & I_FREEING);
truncate_inode_pages_final(&inode->i_data);
btrfs_drop_extent_map_range(BTRFS_I(inode), 0, (u64)-1, false);
@@ -5799,7 +5799,7 @@ struct btrfs_inode *btrfs_iget_path(u64 ino, struct btrfs_root *root,
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->vfs_inode.i_state & I_NEW))
+ if (!(inode_state_read_once(&inode->vfs_inode) & I_NEW))
return inode;
ret = btrfs_read_locked_inode(inode, path);
@@ -5823,7 +5823,7 @@ struct btrfs_inode *btrfs_iget(u64 ino, struct btrfs_root *root)
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->vfs_inode.i_state & I_NEW))
+ if (!(inode_state_read_once(&inode->vfs_inode) & I_NEW))
return inode;
path = btrfs_alloc_path();
@@ -7480,7 +7480,7 @@ static void btrfs_invalidate_folio(struct folio *folio, size_t offset,
u64 page_start = folio_pos(folio);
u64 page_end = page_start + folio_size(folio) - 1;
u64 cur;
- int inode_evicting = inode->vfs_inode.i_state & I_FREEING;
+ int inode_evicting = inode_state_read_once(&inode->vfs_inode) & I_FREEING;
/*
* We have folio locked so no new ordered extent can be created on this
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 06/14] btrfs: use the new ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 06/14] btrfs: use the new ->i_state accessors Mateusz Guzik
@ 2025-10-10 14:11 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:11 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:20, Mateusz Guzik wrote:
> Change generated with coccinelle and fixed up by hand as appropriate.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
>
> cheat sheet:
>
> If ->i_lock is held, then:
>
> state = inode->i_state => state = inode_state_read(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
>
> If ->i_lock is not held or only held conditionally:
>
> state = inode->i_state => state = inode_state_read_once(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
>
> fs/btrfs/inode.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index 3b1b3a0553ee..433ffe231546 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -3884,7 +3884,7 @@ static int btrfs_add_inode_to_root(struct btrfs_inode *inode, bool prealloc)
> ASSERT(ret != -ENOMEM);
> return ret;
> } else if (existing) {
> - WARN_ON(!(existing->vfs_inode.i_state & (I_WILL_FREE | I_FREEING)));
> + WARN_ON(!(inode_state_read_once(&existing->vfs_inode) & (I_WILL_FREE | I_FREEING)));
> }
>
> return 0;
> @@ -5361,7 +5361,7 @@ static void evict_inode_truncate_pages(struct inode *inode)
> struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
> struct rb_node *node;
>
> - ASSERT(inode->i_state & I_FREEING);
> + ASSERT(inode_state_read_once(inode) & I_FREEING);
> truncate_inode_pages_final(&inode->i_data);
>
> btrfs_drop_extent_map_range(BTRFS_I(inode), 0, (u64)-1, false);
> @@ -5799,7 +5799,7 @@ struct btrfs_inode *btrfs_iget_path(u64 ino, struct btrfs_root *root,
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (!(inode->vfs_inode.i_state & I_NEW))
> + if (!(inode_state_read_once(&inode->vfs_inode) & I_NEW))
> return inode;
>
> ret = btrfs_read_locked_inode(inode, path);
> @@ -5823,7 +5823,7 @@ struct btrfs_inode *btrfs_iget(u64 ino, struct btrfs_root *root)
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (!(inode->vfs_inode.i_state & I_NEW))
> + if (!(inode_state_read_once(&inode->vfs_inode) & I_NEW))
> return inode;
>
> path = btrfs_alloc_path();
> @@ -7480,7 +7480,7 @@ static void btrfs_invalidate_folio(struct folio *folio, size_t offset,
> u64 page_start = folio_pos(folio);
> u64 page_end = page_start + folio_size(folio) - 1;
> u64 cur;
> - int inode_evicting = inode->vfs_inode.i_state & I_FREEING;
> + int inode_evicting = inode_state_read_once(&inode->vfs_inode) & I_FREEING;
>
> /*
> * We have folio locked so no new ordered extent can be created on this
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 07/14] ceph: use the new ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (5 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 06/14] btrfs: use the new ->i_state accessors Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:12 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 08/14] smb: " Mateusz Guzik
` (8 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Change generated with coccinelle and fixed up by hand as appropriate.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
cheat sheet:
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
fs/ceph/cache.c | 2 +-
fs/ceph/crypto.c | 4 ++--
fs/ceph/file.c | 4 ++--
fs/ceph/inode.c | 28 ++++++++++++++--------------
4 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
index 930fbd54d2c8..f678bab189d8 100644
--- a/fs/ceph/cache.c
+++ b/fs/ceph/cache.c
@@ -26,7 +26,7 @@ void ceph_fscache_register_inode_cookie(struct inode *inode)
return;
/* Only new inodes! */
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return;
WARN_ON_ONCE(ci->netfs.cache);
diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
index 7026e794813c..928746b92512 100644
--- a/fs/ceph/crypto.c
+++ b/fs/ceph/crypto.c
@@ -329,7 +329,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen)
out:
kfree(cryptbuf);
if (dir != parent) {
- if ((dir->i_state & I_NEW))
+ if ((inode_state_read_once(dir) & I_NEW))
discard_new_inode(dir);
else
iput(dir);
@@ -438,7 +438,7 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
fscrypt_fname_free_buffer(&_tname);
out_inode:
if (dir != fname->dir) {
- if ((dir->i_state & I_NEW))
+ if ((inode_state_read_once(dir) & I_NEW))
discard_new_inode(dir);
else
iput(dir);
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 978acd3d4b32..1c9d73523b88 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -741,7 +741,7 @@ static int ceph_finish_async_create(struct inode *dir, struct inode *inode,
vino.ino, ceph_ino(dir), dentry->d_name.name);
ceph_dir_clear_ordered(dir);
ceph_init_inode_acls(inode, as_ctx);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
/*
* If it's not I_NEW, then someone created this before
* we got here. Assume the server is aware of it at
@@ -903,7 +903,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
new_inode = NULL;
goto out_req;
}
- WARN_ON_ONCE(!(new_inode->i_state & I_NEW));
+ WARN_ON_ONCE(!(inode_state_read_once(new_inode) & I_NEW));
spin_lock(&dentry->d_lock);
di->flags |= CEPH_DENTRY_ASYNC_CREATE;
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 949f0badc944..4044a13969ad 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -132,7 +132,7 @@ struct inode *ceph_new_inode(struct inode *dir, struct dentry *dentry,
goto out_err;
}
- inode->i_state = 0;
+ inode_state_assign_raw(inode, 0);
inode->i_mode = *mode;
err = ceph_security_init_secctx(dentry, *mode, as_ctx);
@@ -201,7 +201,7 @@ struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino,
doutc(cl, "on %llx=%llx.%llx got %p new %d\n",
ceph_present_inode(inode), ceph_vinop(inode), inode,
- !!(inode->i_state & I_NEW));
+ !!(inode_state_read_once(inode) & I_NEW));
return inode;
}
@@ -228,7 +228,7 @@ struct inode *ceph_get_snapdir(struct inode *parent)
goto err;
}
- if (!(inode->i_state & I_NEW) && !S_ISDIR(inode->i_mode)) {
+ if (!(inode_state_read_once(inode) & I_NEW) && !S_ISDIR(inode->i_mode)) {
pr_warn_once_client(cl, "bad snapdir inode type (mode=0%o)\n",
inode->i_mode);
goto err;
@@ -261,7 +261,7 @@ struct inode *ceph_get_snapdir(struct inode *parent)
}
}
#endif
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
inode->i_op = &ceph_snapdir_iops;
inode->i_fop = &ceph_snapdir_fops;
ci->i_snap_caps = CEPH_CAP_PIN; /* so we can open */
@@ -270,7 +270,7 @@ struct inode *ceph_get_snapdir(struct inode *parent)
return inode;
err:
- if ((inode->i_state & I_NEW))
+ if ((inode_state_read_once(inode) & I_NEW))
discard_new_inode(inode);
else
iput(inode);
@@ -744,7 +744,7 @@ void ceph_evict_inode(struct inode *inode)
netfs_wait_for_outstanding_io(inode);
truncate_inode_pages_final(&inode->i_data);
- if (inode->i_state & I_PINNING_NETFS_WB)
+ if (inode_state_read_once(inode) & I_PINNING_NETFS_WB)
ceph_fscache_unuse_cookie(inode, true);
clear_inode(inode);
@@ -1013,7 +1013,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
le64_to_cpu(info->version), ci->i_version);
/* Once I_NEW is cleared, we can't change type or dev numbers */
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
inode->i_mode = mode;
} else {
if (inode_wrong_type(inode, mode)) {
@@ -1090,7 +1090,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
#ifdef CONFIG_FS_ENCRYPTION
if (iinfo->fscrypt_auth_len &&
- ((inode->i_state & I_NEW) || (ci->fscrypt_auth_len == 0))) {
+ ((inode_state_read_once(inode) & I_NEW) || (ci->fscrypt_auth_len == 0))) {
kfree(ci->fscrypt_auth);
ci->fscrypt_auth_len = iinfo->fscrypt_auth_len;
ci->fscrypt_auth = iinfo->fscrypt_auth;
@@ -1692,13 +1692,13 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
pr_err_client(cl, "badness %p %llx.%llx\n", in,
ceph_vinop(in));
req->r_target_inode = NULL;
- if (in->i_state & I_NEW)
+ if (inode_state_read_once(in) & I_NEW)
discard_new_inode(in);
else
iput(in);
goto done;
}
- if (in->i_state & I_NEW)
+ if (inode_state_read_once(in) & I_NEW)
unlock_new_inode(in);
}
@@ -1887,11 +1887,11 @@ static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req,
pr_err_client(cl, "inode badness on %p got %d\n", in,
rc);
err = rc;
- if (in->i_state & I_NEW) {
+ if (inode_state_read_once(in) & I_NEW) {
ihold(in);
discard_new_inode(in);
}
- } else if (in->i_state & I_NEW) {
+ } else if (inode_state_read_once(in) & I_NEW) {
unlock_new_inode(in);
}
@@ -2103,7 +2103,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
pr_err_client(cl, "badness on %p %llx.%llx\n", in,
ceph_vinop(in));
if (d_really_is_negative(dn)) {
- if (in->i_state & I_NEW) {
+ if (inode_state_read_once(in) & I_NEW) {
ihold(in);
discard_new_inode(in);
}
@@ -2113,7 +2113,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
err = ret;
goto next_item;
}
- if (in->i_state & I_NEW)
+ if (inode_state_read_once(in) & I_NEW)
unlock_new_inode(in);
if (d_really_is_negative(dn)) {
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 07/14] ceph: use the new ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 07/14] ceph: " Mateusz Guzik
@ 2025-10-10 14:12 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:12 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:21, Mateusz Guzik wrote:
> Change generated with coccinelle and fixed up by hand as appropriate.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
>
> cheat sheet:
>
> If ->i_lock is held, then:
>
> state = inode->i_state => state = inode_state_read(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
>
> If ->i_lock is not held or only held conditionally:
>
> state = inode->i_state => state = inode_state_read_once(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
>
> fs/ceph/cache.c | 2 +-
> fs/ceph/crypto.c | 4 ++--
> fs/ceph/file.c | 4 ++--
> fs/ceph/inode.c | 28 ++++++++++++++--------------
> 4 files changed, 19 insertions(+), 19 deletions(-)
>
> diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
> index 930fbd54d2c8..f678bab189d8 100644
> --- a/fs/ceph/cache.c
> +++ b/fs/ceph/cache.c
> @@ -26,7 +26,7 @@ void ceph_fscache_register_inode_cookie(struct inode *inode)
> return;
>
> /* Only new inodes! */
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return;
>
> WARN_ON_ONCE(ci->netfs.cache);
> diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
> index 7026e794813c..928746b92512 100644
> --- a/fs/ceph/crypto.c
> +++ b/fs/ceph/crypto.c
> @@ -329,7 +329,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen)
> out:
> kfree(cryptbuf);
> if (dir != parent) {
> - if ((dir->i_state & I_NEW))
> + if ((inode_state_read_once(dir) & I_NEW))
> discard_new_inode(dir);
> else
> iput(dir);
> @@ -438,7 +438,7 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
> fscrypt_fname_free_buffer(&_tname);
> out_inode:
> if (dir != fname->dir) {
> - if ((dir->i_state & I_NEW))
> + if ((inode_state_read_once(dir) & I_NEW))
> discard_new_inode(dir);
> else
> iput(dir);
> diff --git a/fs/ceph/file.c b/fs/ceph/file.c
> index 978acd3d4b32..1c9d73523b88 100644
> --- a/fs/ceph/file.c
> +++ b/fs/ceph/file.c
> @@ -741,7 +741,7 @@ static int ceph_finish_async_create(struct inode *dir, struct inode *inode,
> vino.ino, ceph_ino(dir), dentry->d_name.name);
> ceph_dir_clear_ordered(dir);
> ceph_init_inode_acls(inode, as_ctx);
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> /*
> * If it's not I_NEW, then someone created this before
> * we got here. Assume the server is aware of it at
> @@ -903,7 +903,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
> new_inode = NULL;
> goto out_req;
> }
> - WARN_ON_ONCE(!(new_inode->i_state & I_NEW));
> + WARN_ON_ONCE(!(inode_state_read_once(new_inode) & I_NEW));
>
> spin_lock(&dentry->d_lock);
> di->flags |= CEPH_DENTRY_ASYNC_CREATE;
> diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
> index 949f0badc944..4044a13969ad 100644
> --- a/fs/ceph/inode.c
> +++ b/fs/ceph/inode.c
> @@ -132,7 +132,7 @@ struct inode *ceph_new_inode(struct inode *dir, struct dentry *dentry,
> goto out_err;
> }
>
> - inode->i_state = 0;
> + inode_state_assign_raw(inode, 0);
> inode->i_mode = *mode;
>
> err = ceph_security_init_secctx(dentry, *mode, as_ctx);
> @@ -201,7 +201,7 @@ struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino,
>
> doutc(cl, "on %llx=%llx.%llx got %p new %d\n",
> ceph_present_inode(inode), ceph_vinop(inode), inode,
> - !!(inode->i_state & I_NEW));
> + !!(inode_state_read_once(inode) & I_NEW));
> return inode;
> }
>
> @@ -228,7 +228,7 @@ struct inode *ceph_get_snapdir(struct inode *parent)
> goto err;
> }
>
> - if (!(inode->i_state & I_NEW) && !S_ISDIR(inode->i_mode)) {
> + if (!(inode_state_read_once(inode) & I_NEW) && !S_ISDIR(inode->i_mode)) {
> pr_warn_once_client(cl, "bad snapdir inode type (mode=0%o)\n",
> inode->i_mode);
> goto err;
> @@ -261,7 +261,7 @@ struct inode *ceph_get_snapdir(struct inode *parent)
> }
> }
> #endif
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> inode->i_op = &ceph_snapdir_iops;
> inode->i_fop = &ceph_snapdir_fops;
> ci->i_snap_caps = CEPH_CAP_PIN; /* so we can open */
> @@ -270,7 +270,7 @@ struct inode *ceph_get_snapdir(struct inode *parent)
>
> return inode;
> err:
> - if ((inode->i_state & I_NEW))
> + if ((inode_state_read_once(inode) & I_NEW))
> discard_new_inode(inode);
> else
> iput(inode);
> @@ -744,7 +744,7 @@ void ceph_evict_inode(struct inode *inode)
>
> netfs_wait_for_outstanding_io(inode);
> truncate_inode_pages_final(&inode->i_data);
> - if (inode->i_state & I_PINNING_NETFS_WB)
> + if (inode_state_read_once(inode) & I_PINNING_NETFS_WB)
> ceph_fscache_unuse_cookie(inode, true);
> clear_inode(inode);
>
> @@ -1013,7 +1013,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
> le64_to_cpu(info->version), ci->i_version);
>
> /* Once I_NEW is cleared, we can't change type or dev numbers */
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> inode->i_mode = mode;
> } else {
> if (inode_wrong_type(inode, mode)) {
> @@ -1090,7 +1090,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
>
> #ifdef CONFIG_FS_ENCRYPTION
> if (iinfo->fscrypt_auth_len &&
> - ((inode->i_state & I_NEW) || (ci->fscrypt_auth_len == 0))) {
> + ((inode_state_read_once(inode) & I_NEW) || (ci->fscrypt_auth_len == 0))) {
> kfree(ci->fscrypt_auth);
> ci->fscrypt_auth_len = iinfo->fscrypt_auth_len;
> ci->fscrypt_auth = iinfo->fscrypt_auth;
> @@ -1692,13 +1692,13 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
> pr_err_client(cl, "badness %p %llx.%llx\n", in,
> ceph_vinop(in));
> req->r_target_inode = NULL;
> - if (in->i_state & I_NEW)
> + if (inode_state_read_once(in) & I_NEW)
> discard_new_inode(in);
> else
> iput(in);
> goto done;
> }
> - if (in->i_state & I_NEW)
> + if (inode_state_read_once(in) & I_NEW)
> unlock_new_inode(in);
> }
>
> @@ -1887,11 +1887,11 @@ static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req,
> pr_err_client(cl, "inode badness on %p got %d\n", in,
> rc);
> err = rc;
> - if (in->i_state & I_NEW) {
> + if (inode_state_read_once(in) & I_NEW) {
> ihold(in);
> discard_new_inode(in);
> }
> - } else if (in->i_state & I_NEW) {
> + } else if (inode_state_read_once(in) & I_NEW) {
> unlock_new_inode(in);
> }
>
> @@ -2103,7 +2103,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
> pr_err_client(cl, "badness on %p %llx.%llx\n", in,
> ceph_vinop(in));
> if (d_really_is_negative(dn)) {
> - if (in->i_state & I_NEW) {
> + if (inode_state_read_once(in) & I_NEW) {
> ihold(in);
> discard_new_inode(in);
> }
> @@ -2113,7 +2113,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
> err = ret;
> goto next_item;
> }
> - if (in->i_state & I_NEW)
> + if (inode_state_read_once(in) & I_NEW)
> unlock_new_inode(in);
>
> if (d_really_is_negative(dn)) {
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 08/14] smb: use the new ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (6 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 07/14] ceph: " Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:15 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 09/14] f2fs: " Mateusz Guzik
` (7 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Change generated with coccinelle and fixed up by hand as appropriate.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
cheat sheet:
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
fs/smb/client/cifsfs.c | 2 +-
fs/smb/client/inode.c | 14 +++++++-------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 1775c2b7528f..103289451bd7 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -484,7 +484,7 @@ cifs_evict_inode(struct inode *inode)
{
netfs_wait_for_outstanding_io(inode);
truncate_inode_pages_final(&inode->i_data);
- if (inode->i_state & I_PINNING_NETFS_WB)
+ if (inode_state_read_once(inode) & I_PINNING_NETFS_WB)
cifs_fscache_unuse_inode_cookie(inode, true);
cifs_fscache_release_inode_cookie(inode);
clear_inode(inode);
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 8bb544be401e..32d9054a77fc 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -101,7 +101,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
cifs_dbg(FYI, "%s: revalidating inode %llu\n",
__func__, cifs_i->uniqueid);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
cifs_dbg(FYI, "%s: inode %llu is new\n",
__func__, cifs_i->uniqueid);
return;
@@ -146,7 +146,7 @@ cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
*/
if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) {
/* only provide fake values on a new inode */
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
if (fattr->cf_cifsattrs & ATTR_DIRECTORY)
set_nlink(inode, 2);
else
@@ -167,12 +167,12 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
- if (!(inode->i_state & I_NEW) &&
+ if (!(inode_state_read_once(inode) & I_NEW) &&
unlikely(inode_wrong_type(inode, fattr->cf_mode))) {
CIFS_I(inode)->time = 0; /* force reval */
return -ESTALE;
}
- if (inode->i_state & I_NEW)
+ if (inode_state_read_once(inode) & I_NEW)
CIFS_I(inode)->netfs.zero_point = fattr->cf_eof;
cifs_revalidate_cache(inode, fattr);
@@ -194,7 +194,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
inode->i_gid = fattr->cf_gid;
/* if dynperm is set, don't clobber existing mode */
- if (inode->i_state & I_NEW ||
+ if (inode_state_read(inode) & I_NEW ||
!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
inode->i_mode = fattr->cf_mode;
@@ -236,7 +236,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
inode->i_flags |= S_AUTOMOUNT;
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
cifs_set_netfs_context(inode);
cifs_set_ops(inode);
}
@@ -1638,7 +1638,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
cifs_fattr_to_inode(inode, fattr, false);
if (sb->s_flags & SB_NOATIME)
inode->i_flags |= S_NOATIME | S_NOCMTIME;
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
inode->i_ino = hash;
cifs_fscache_get_inode_cookie(inode);
unlock_new_inode(inode);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 08/14] smb: use the new ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 08/14] smb: " Mateusz Guzik
@ 2025-10-10 14:15 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:15 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:22, Mateusz Guzik wrote:
> Change generated with coccinelle and fixed up by hand as appropriate.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
>
> cheat sheet:
>
> If ->i_lock is held, then:
>
> state = inode->i_state => state = inode_state_read(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
>
> If ->i_lock is not held or only held conditionally:
>
> state = inode->i_state => state = inode_state_read_once(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
>
> fs/smb/client/cifsfs.c | 2 +-
> fs/smb/client/inode.c | 14 +++++++-------
> 2 files changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
> index 1775c2b7528f..103289451bd7 100644
> --- a/fs/smb/client/cifsfs.c
> +++ b/fs/smb/client/cifsfs.c
> @@ -484,7 +484,7 @@ cifs_evict_inode(struct inode *inode)
> {
> netfs_wait_for_outstanding_io(inode);
> truncate_inode_pages_final(&inode->i_data);
> - if (inode->i_state & I_PINNING_NETFS_WB)
> + if (inode_state_read_once(inode) & I_PINNING_NETFS_WB)
> cifs_fscache_unuse_inode_cookie(inode, true);
> cifs_fscache_release_inode_cookie(inode);
> clear_inode(inode);
> diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
> index 8bb544be401e..32d9054a77fc 100644
> --- a/fs/smb/client/inode.c
> +++ b/fs/smb/client/inode.c
> @@ -101,7 +101,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
> cifs_dbg(FYI, "%s: revalidating inode %llu\n",
> __func__, cifs_i->uniqueid);
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> cifs_dbg(FYI, "%s: inode %llu is new\n",
> __func__, cifs_i->uniqueid);
> return;
> @@ -146,7 +146,7 @@ cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
> */
> if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) {
> /* only provide fake values on a new inode */
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> if (fattr->cf_cifsattrs & ATTR_DIRECTORY)
> set_nlink(inode, 2);
> else
> @@ -167,12 +167,12 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
> struct cifsInodeInfo *cifs_i = CIFS_I(inode);
> struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
>
> - if (!(inode->i_state & I_NEW) &&
> + if (!(inode_state_read_once(inode) & I_NEW) &&
> unlikely(inode_wrong_type(inode, fattr->cf_mode))) {
> CIFS_I(inode)->time = 0; /* force reval */
> return -ESTALE;
> }
> - if (inode->i_state & I_NEW)
> + if (inode_state_read_once(inode) & I_NEW)
> CIFS_I(inode)->netfs.zero_point = fattr->cf_eof;
>
> cifs_revalidate_cache(inode, fattr);
> @@ -194,7 +194,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
> inode->i_gid = fattr->cf_gid;
>
> /* if dynperm is set, don't clobber existing mode */
> - if (inode->i_state & I_NEW ||
> + if (inode_state_read(inode) & I_NEW ||
> !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
> inode->i_mode = fattr->cf_mode;
>
> @@ -236,7 +236,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
>
> if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
> inode->i_flags |= S_AUTOMOUNT;
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> cifs_set_netfs_context(inode);
> cifs_set_ops(inode);
> }
> @@ -1638,7 +1638,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
> cifs_fattr_to_inode(inode, fattr, false);
> if (sb->s_flags & SB_NOATIME)
> inode->i_flags |= S_NOATIME | S_NOCMTIME;
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> inode->i_ino = hash;
> cifs_fscache_get_inode_cookie(inode);
> unlock_new_inode(inode);
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 09/14] f2fs: use the new ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (7 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 08/14] smb: " Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:16 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 10/14] gfs2: " Mateusz Guzik
` (6 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Change generated with coccinelle and fixed up by hand as appropriate.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
cheat sheet:
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
fs/f2fs/data.c | 2 +-
fs/f2fs/inode.c | 2 +-
fs/f2fs/namei.c | 4 ++--
fs/f2fs/super.c | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index ef38e62cda8f..c5319864e4ff 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -4222,7 +4222,7 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
if (map.m_flags & F2FS_MAP_NEW)
iomap->flags |= IOMAP_F_NEW;
- if ((inode->i_state & I_DIRTY_DATASYNC) ||
+ if ((inode_state_read_once(inode) & I_DIRTY_DATASYNC) ||
offset + length > i_size_read(inode))
iomap->flags |= IOMAP_F_DIRTY;
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 8c4eafe9ffac..f1cda1900658 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -569,7 +569,7 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
if (!inode)
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW)) {
+ if (!(inode_state_read_once(inode) & I_NEW)) {
if (is_meta_ino(sbi, ino)) {
f2fs_err(sbi, "inaccessible inode: %lu, run fsck to repair", ino);
set_sbi_flag(sbi, SBI_NEED_FSCK);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index b882771e4699..af40282a6948 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -844,7 +844,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
f2fs_i_links_write(inode, false);
spin_lock(&inode->i_lock);
- inode->i_state |= I_LINKABLE;
+ inode_state_set(inode, I_LINKABLE);
spin_unlock(&inode->i_lock);
} else {
if (file)
@@ -1057,7 +1057,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
goto put_out_dir;
spin_lock(&whiteout->i_lock);
- whiteout->i_state &= ~I_LINKABLE;
+ inode_state_clear(whiteout, I_LINKABLE);
spin_unlock(&whiteout->i_lock);
iput(whiteout);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index fd8e7b0b2166..8806a1f221cf 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1798,7 +1798,7 @@ static int f2fs_drop_inode(struct inode *inode)
* - f2fs_gc -> iput -> evict
* - inode_wait_for_writeback(inode)
*/
- if ((!inode_unhashed(inode) && inode->i_state & I_SYNC)) {
+ if ((!inode_unhashed(inode) && inode_state_read(inode) & I_SYNC)) {
if (!inode->i_nlink && !is_bad_inode(inode)) {
/* to avoid evict_inode call simultaneously */
__iget(inode);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 09/14] f2fs: use the new ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 09/14] f2fs: " Mateusz Guzik
@ 2025-10-10 14:16 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:16 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:23, Mateusz Guzik wrote:
> Change generated with coccinelle and fixed up by hand as appropriate.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
>
> cheat sheet:
>
> If ->i_lock is held, then:
>
> state = inode->i_state => state = inode_state_read(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
>
> If ->i_lock is not held or only held conditionally:
>
> state = inode->i_state => state = inode_state_read_once(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
>
> fs/f2fs/data.c | 2 +-
> fs/f2fs/inode.c | 2 +-
> fs/f2fs/namei.c | 4 ++--
> fs/f2fs/super.c | 2 +-
> 4 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index ef38e62cda8f..c5319864e4ff 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -4222,7 +4222,7 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
>
> if (map.m_flags & F2FS_MAP_NEW)
> iomap->flags |= IOMAP_F_NEW;
> - if ((inode->i_state & I_DIRTY_DATASYNC) ||
> + if ((inode_state_read_once(inode) & I_DIRTY_DATASYNC) ||
> offset + length > i_size_read(inode))
> iomap->flags |= IOMAP_F_DIRTY;
>
> diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
> index 8c4eafe9ffac..f1cda1900658 100644
> --- a/fs/f2fs/inode.c
> +++ b/fs/f2fs/inode.c
> @@ -569,7 +569,7 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> if (!inode)
> return ERR_PTR(-ENOMEM);
>
> - if (!(inode->i_state & I_NEW)) {
> + if (!(inode_state_read_once(inode) & I_NEW)) {
> if (is_meta_ino(sbi, ino)) {
> f2fs_err(sbi, "inaccessible inode: %lu, run fsck to repair", ino);
> set_sbi_flag(sbi, SBI_NEED_FSCK);
> diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
> index b882771e4699..af40282a6948 100644
> --- a/fs/f2fs/namei.c
> +++ b/fs/f2fs/namei.c
> @@ -844,7 +844,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
> f2fs_i_links_write(inode, false);
>
> spin_lock(&inode->i_lock);
> - inode->i_state |= I_LINKABLE;
> + inode_state_set(inode, I_LINKABLE);
> spin_unlock(&inode->i_lock);
> } else {
> if (file)
> @@ -1057,7 +1057,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
> goto put_out_dir;
>
> spin_lock(&whiteout->i_lock);
> - whiteout->i_state &= ~I_LINKABLE;
> + inode_state_clear(whiteout, I_LINKABLE);
> spin_unlock(&whiteout->i_lock);
>
> iput(whiteout);
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index fd8e7b0b2166..8806a1f221cf 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -1798,7 +1798,7 @@ static int f2fs_drop_inode(struct inode *inode)
> * - f2fs_gc -> iput -> evict
> * - inode_wait_for_writeback(inode)
> */
> - if ((!inode_unhashed(inode) && inode->i_state & I_SYNC)) {
> + if ((!inode_unhashed(inode) && inode_state_read(inode) & I_SYNC)) {
> if (!inode->i_nlink && !is_bad_inode(inode)) {
> /* to avoid evict_inode call simultaneously */
> __iget(inode);
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 10/14] gfs2: use the new ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (8 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 09/14] f2fs: " Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:17 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 11/14] overlayfs: " Mateusz Guzik
` (5 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Change generated with coccinelle and fixed up by hand as appropriate.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
cheat sheet:
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
fs/gfs2/file.c | 2 +-
fs/gfs2/glops.c | 2 +-
fs/gfs2/inode.c | 4 ++--
fs/gfs2/ops_fstype.c | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index bc67fa058c84..ee92f5910ae1 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -744,7 +744,7 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
{
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
- int sync_state = inode->i_state & I_DIRTY;
+ int sync_state = inode_state_read_once(inode) & I_DIRTY;
struct gfs2_inode *ip = GFS2_I(inode);
int ret = 0, ret1 = 0;
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 0c0a80b3baca..c94e42b0c94d 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -394,7 +394,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
u16 height, depth;
umode_t mode = be32_to_cpu(str->di_mode);
struct inode *inode = &ip->i_inode;
- bool is_new = inode->i_state & I_NEW;
+ bool is_new = inode_state_read_once(inode) & I_NEW;
if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) {
gfs2_consist_inode(ip);
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 8a7ed80d9f2d..890c87e3e365 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -127,7 +127,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
ip = GFS2_I(inode);
- if (inode->i_state & I_NEW) {
+ if (inode_state_read_once(inode) & I_NEW) {
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_glock *io_gl;
int extra_flags = 0;
@@ -924,7 +924,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
gfs2_dir_no_add(&da);
gfs2_glock_dq_uninit(&d_gh);
if (!IS_ERR_OR_NULL(inode)) {
- if (inode->i_state & I_NEW)
+ if (inode_state_read_once(inode) & I_NEW)
iget_failed(inode);
else
iput(inode);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index aa15183f9a16..889682f051ea 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1751,7 +1751,7 @@ static void gfs2_evict_inodes(struct super_block *sb)
spin_lock(&sb->s_inode_list_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
spin_lock(&inode->i_lock);
- if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) &&
+ if ((inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) &&
!need_resched()) {
spin_unlock(&inode->i_lock);
continue;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 10/14] gfs2: use the new ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 10/14] gfs2: " Mateusz Guzik
@ 2025-10-10 14:17 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:17 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:24, Mateusz Guzik wrote:
> Change generated with coccinelle and fixed up by hand as appropriate.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
>
> cheat sheet:
>
> If ->i_lock is held, then:
>
> state = inode->i_state => state = inode_state_read(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
>
> If ->i_lock is not held or only held conditionally:
>
> state = inode->i_state => state = inode_state_read_once(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
>
> fs/gfs2/file.c | 2 +-
> fs/gfs2/glops.c | 2 +-
> fs/gfs2/inode.c | 4 ++--
> fs/gfs2/ops_fstype.c | 2 +-
> 4 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> index bc67fa058c84..ee92f5910ae1 100644
> --- a/fs/gfs2/file.c
> +++ b/fs/gfs2/file.c
> @@ -744,7 +744,7 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
> {
> struct address_space *mapping = file->f_mapping;
> struct inode *inode = mapping->host;
> - int sync_state = inode->i_state & I_DIRTY;
> + int sync_state = inode_state_read_once(inode) & I_DIRTY;
> struct gfs2_inode *ip = GFS2_I(inode);
> int ret = 0, ret1 = 0;
>
> diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
> index 0c0a80b3baca..c94e42b0c94d 100644
> --- a/fs/gfs2/glops.c
> +++ b/fs/gfs2/glops.c
> @@ -394,7 +394,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
> u16 height, depth;
> umode_t mode = be32_to_cpu(str->di_mode);
> struct inode *inode = &ip->i_inode;
> - bool is_new = inode->i_state & I_NEW;
> + bool is_new = inode_state_read_once(inode) & I_NEW;
>
> if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) {
> gfs2_consist_inode(ip);
> diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
> index 8a7ed80d9f2d..890c87e3e365 100644
> --- a/fs/gfs2/inode.c
> +++ b/fs/gfs2/inode.c
> @@ -127,7 +127,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
>
> ip = GFS2_I(inode);
>
> - if (inode->i_state & I_NEW) {
> + if (inode_state_read_once(inode) & I_NEW) {
> struct gfs2_sbd *sdp = GFS2_SB(inode);
> struct gfs2_glock *io_gl;
> int extra_flags = 0;
> @@ -924,7 +924,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
> gfs2_dir_no_add(&da);
> gfs2_glock_dq_uninit(&d_gh);
> if (!IS_ERR_OR_NULL(inode)) {
> - if (inode->i_state & I_NEW)
> + if (inode_state_read_once(inode) & I_NEW)
> iget_failed(inode);
> else
> iput(inode);
> diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
> index aa15183f9a16..889682f051ea 100644
> --- a/fs/gfs2/ops_fstype.c
> +++ b/fs/gfs2/ops_fstype.c
> @@ -1751,7 +1751,7 @@ static void gfs2_evict_inodes(struct super_block *sb)
> spin_lock(&sb->s_inode_list_lock);
> list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
> spin_lock(&inode->i_lock);
> - if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) &&
> + if ((inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) &&
> !need_resched()) {
> spin_unlock(&inode->i_lock);
> continue;
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 11/14] overlayfs: use the new ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (9 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 10/14] gfs2: " Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:18 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 12/14] nilfs2: " Mateusz Guzik
` (4 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Change generated with coccinelle and fixed up by hand as appropriate.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
cheat sheet:
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
fs/overlayfs/dir.c | 2 +-
fs/overlayfs/inode.c | 6 +++---
fs/overlayfs/util.c | 10 +++++-----
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index a5e9ddf3023b..83b955a1d55c 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -686,7 +686,7 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
goto out_drop_write;
spin_lock(&inode->i_lock);
- inode->i_state |= I_CREATING;
+ inode_state_set(inode, I_CREATING);
spin_unlock(&inode->i_lock);
inode_init_owner(&nop_mnt_idmap, inode, dentry->d_parent->d_inode, mode);
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index aaa4cf579561..b7938dd43b95 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -1149,7 +1149,7 @@ struct inode *ovl_get_trap_inode(struct super_block *sb, struct dentry *dir)
if (!trap)
return ERR_PTR(-ENOMEM);
- if (!(trap->i_state & I_NEW)) {
+ if (!(inode_state_read_once(trap) & I_NEW)) {
/* Conflicting layer roots? */
iput(trap);
return ERR_PTR(-ELOOP);
@@ -1240,7 +1240,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
inode = ovl_iget5(sb, oip->newinode, key);
if (!inode)
goto out_err;
- if (!(inode->i_state & I_NEW)) {
+ if (!(inode_state_read_once(inode) & I_NEW)) {
/*
* Verify that the underlying files stored in the inode
* match those in the dentry.
@@ -1300,7 +1300,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
if (upperdentry)
ovl_check_protattr(inode, upperdentry);
- if (inode->i_state & I_NEW)
+ if (inode_state_read_once(inode) & I_NEW)
unlock_new_inode(inode);
out:
return inode;
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index f76672f2e686..2da1c035f716 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -1019,8 +1019,8 @@ bool ovl_inuse_trylock(struct dentry *dentry)
bool locked = false;
spin_lock(&inode->i_lock);
- if (!(inode->i_state & I_OVL_INUSE)) {
- inode->i_state |= I_OVL_INUSE;
+ if (!(inode_state_read(inode) & I_OVL_INUSE)) {
+ inode_state_set(inode, I_OVL_INUSE);
locked = true;
}
spin_unlock(&inode->i_lock);
@@ -1034,8 +1034,8 @@ void ovl_inuse_unlock(struct dentry *dentry)
struct inode *inode = d_inode(dentry);
spin_lock(&inode->i_lock);
- WARN_ON(!(inode->i_state & I_OVL_INUSE));
- inode->i_state &= ~I_OVL_INUSE;
+ WARN_ON(!(inode_state_read(inode) & I_OVL_INUSE));
+ inode_state_clear(inode, I_OVL_INUSE);
spin_unlock(&inode->i_lock);
}
}
@@ -1046,7 +1046,7 @@ bool ovl_is_inuse(struct dentry *dentry)
bool inuse;
spin_lock(&inode->i_lock);
- inuse = (inode->i_state & I_OVL_INUSE);
+ inuse = (inode_state_read(inode) & I_OVL_INUSE);
spin_unlock(&inode->i_lock);
return inuse;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 11/14] overlayfs: use the new ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 11/14] overlayfs: " Mateusz Guzik
@ 2025-10-10 14:18 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:18 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:25, Mateusz Guzik wrote:
> Change generated with coccinelle and fixed up by hand as appropriate.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
>
> cheat sheet:
>
> If ->i_lock is held, then:
>
> state = inode->i_state => state = inode_state_read(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
>
> If ->i_lock is not held or only held conditionally:
>
> state = inode->i_state => state = inode_state_read_once(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
>
> fs/overlayfs/dir.c | 2 +-
> fs/overlayfs/inode.c | 6 +++---
> fs/overlayfs/util.c | 10 +++++-----
> 3 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> index a5e9ddf3023b..83b955a1d55c 100644
> --- a/fs/overlayfs/dir.c
> +++ b/fs/overlayfs/dir.c
> @@ -686,7 +686,7 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
> goto out_drop_write;
>
> spin_lock(&inode->i_lock);
> - inode->i_state |= I_CREATING;
> + inode_state_set(inode, I_CREATING);
> spin_unlock(&inode->i_lock);
>
> inode_init_owner(&nop_mnt_idmap, inode, dentry->d_parent->d_inode, mode);
> diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
> index aaa4cf579561..b7938dd43b95 100644
> --- a/fs/overlayfs/inode.c
> +++ b/fs/overlayfs/inode.c
> @@ -1149,7 +1149,7 @@ struct inode *ovl_get_trap_inode(struct super_block *sb, struct dentry *dir)
> if (!trap)
> return ERR_PTR(-ENOMEM);
>
> - if (!(trap->i_state & I_NEW)) {
> + if (!(inode_state_read_once(trap) & I_NEW)) {
> /* Conflicting layer roots? */
> iput(trap);
> return ERR_PTR(-ELOOP);
> @@ -1240,7 +1240,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
> inode = ovl_iget5(sb, oip->newinode, key);
> if (!inode)
> goto out_err;
> - if (!(inode->i_state & I_NEW)) {
> + if (!(inode_state_read_once(inode) & I_NEW)) {
> /*
> * Verify that the underlying files stored in the inode
> * match those in the dentry.
> @@ -1300,7 +1300,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
> if (upperdentry)
> ovl_check_protattr(inode, upperdentry);
>
> - if (inode->i_state & I_NEW)
> + if (inode_state_read_once(inode) & I_NEW)
> unlock_new_inode(inode);
> out:
> return inode;
> diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
> index f76672f2e686..2da1c035f716 100644
> --- a/fs/overlayfs/util.c
> +++ b/fs/overlayfs/util.c
> @@ -1019,8 +1019,8 @@ bool ovl_inuse_trylock(struct dentry *dentry)
> bool locked = false;
>
> spin_lock(&inode->i_lock);
> - if (!(inode->i_state & I_OVL_INUSE)) {
> - inode->i_state |= I_OVL_INUSE;
> + if (!(inode_state_read(inode) & I_OVL_INUSE)) {
> + inode_state_set(inode, I_OVL_INUSE);
> locked = true;
> }
> spin_unlock(&inode->i_lock);
> @@ -1034,8 +1034,8 @@ void ovl_inuse_unlock(struct dentry *dentry)
> struct inode *inode = d_inode(dentry);
>
> spin_lock(&inode->i_lock);
> - WARN_ON(!(inode->i_state & I_OVL_INUSE));
> - inode->i_state &= ~I_OVL_INUSE;
> + WARN_ON(!(inode_state_read(inode) & I_OVL_INUSE));
> + inode_state_clear(inode, I_OVL_INUSE);
> spin_unlock(&inode->i_lock);
> }
> }
> @@ -1046,7 +1046,7 @@ bool ovl_is_inuse(struct dentry *dentry)
> bool inuse;
>
> spin_lock(&inode->i_lock);
> - inuse = (inode->i_state & I_OVL_INUSE);
> + inuse = (inode_state_read(inode) & I_OVL_INUSE);
> spin_unlock(&inode->i_lock);
>
> return inuse;
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 12/14] nilfs2: use the new ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (10 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 11/14] overlayfs: " Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:18 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 13/14] xfs: " Mateusz Guzik
` (3 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Change generated with coccinelle and fixed up by hand as appropriate.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
cheat sheet:
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
fs/nilfs2/cpfile.c | 2 +-
fs/nilfs2/dat.c | 2 +-
fs/nilfs2/ifile.c | 2 +-
fs/nilfs2/inode.c | 10 +++++-----
fs/nilfs2/sufile.c | 2 +-
5 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c
index bcc7d76269ac..4bbdc832d7f2 100644
--- a/fs/nilfs2/cpfile.c
+++ b/fs/nilfs2/cpfile.c
@@ -1148,7 +1148,7 @@ int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,
cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);
if (unlikely(!cpfile))
return -ENOMEM;
- if (!(cpfile->i_state & I_NEW))
+ if (!(inode_state_read_once(cpfile) & I_NEW))
goto out;
err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0);
diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c
index c664daba56ae..674380837ab9 100644
--- a/fs/nilfs2/dat.c
+++ b/fs/nilfs2/dat.c
@@ -506,7 +506,7 @@ int nilfs_dat_read(struct super_block *sb, size_t entry_size,
dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO);
if (unlikely(!dat))
return -ENOMEM;
- if (!(dat->i_state & I_NEW))
+ if (!(inode_state_read_once(dat) & I_NEW))
goto out;
err = nilfs_mdt_init(dat, NILFS_MDT_GFP, sizeof(*di));
diff --git a/fs/nilfs2/ifile.c b/fs/nilfs2/ifile.c
index c4cd4a4dedd0..99eb8a59009e 100644
--- a/fs/nilfs2/ifile.c
+++ b/fs/nilfs2/ifile.c
@@ -188,7 +188,7 @@ int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
ifile = nilfs_iget_locked(sb, root, NILFS_IFILE_INO);
if (unlikely(!ifile))
return -ENOMEM;
- if (!(ifile->i_state & I_NEW))
+ if (!(inode_state_read_once(ifile) & I_NEW))
goto out;
err = nilfs_mdt_init(ifile, NILFS_MDT_GFP,
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 87ddde159f0c..51bde45d5865 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -365,7 +365,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
failed_after_creation:
clear_nlink(inode);
- if (inode->i_state & I_NEW)
+ if (inode_state_read_once(inode) & I_NEW)
unlock_new_inode(inode);
iput(inode); /*
* raw_inode will be deleted through
@@ -562,7 +562,7 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
if (unlikely(!inode))
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW)) {
+ if (!(inode_state_read_once(inode) & I_NEW)) {
if (!inode->i_nlink) {
iput(inode);
return ERR_PTR(-ESTALE);
@@ -591,7 +591,7 @@ struct inode *nilfs_iget_for_gc(struct super_block *sb, unsigned long ino,
inode = iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args);
if (unlikely(!inode))
return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
+ if (!(inode_state_read_once(inode) & I_NEW))
return inode;
err = nilfs_init_gcinode(inode);
@@ -631,7 +631,7 @@ int nilfs_attach_btree_node_cache(struct inode *inode)
nilfs_iget_set, &args);
if (unlikely(!btnc_inode))
return -ENOMEM;
- if (btnc_inode->i_state & I_NEW) {
+ if (inode_state_read_once(btnc_inode) & I_NEW) {
nilfs_init_btnc_inode(btnc_inode);
unlock_new_inode(btnc_inode);
}
@@ -686,7 +686,7 @@ struct inode *nilfs_iget_for_shadow(struct inode *inode)
nilfs_iget_set, &args);
if (unlikely(!s_inode))
return ERR_PTR(-ENOMEM);
- if (!(s_inode->i_state & I_NEW))
+ if (!(inode_state_read_once(s_inode) & I_NEW))
return inode;
NILFS_I(s_inode)->i_flags = 0;
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c
index 330f269abedf..83f93337c01b 100644
--- a/fs/nilfs2/sufile.c
+++ b/fs/nilfs2/sufile.c
@@ -1226,7 +1226,7 @@ int nilfs_sufile_read(struct super_block *sb, size_t susize,
sufile = nilfs_iget_locked(sb, NULL, NILFS_SUFILE_INO);
if (unlikely(!sufile))
return -ENOMEM;
- if (!(sufile->i_state & I_NEW))
+ if (!(inode_state_read_once(sufile) & I_NEW))
goto out;
err = nilfs_mdt_init(sufile, NILFS_MDT_GFP, sizeof(*sui));
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 12/14] nilfs2: use the new ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 12/14] nilfs2: " Mateusz Guzik
@ 2025-10-10 14:18 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:18 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:26, Mateusz Guzik wrote:
> Change generated with coccinelle and fixed up by hand as appropriate.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
>
> cheat sheet:
>
> If ->i_lock is held, then:
>
> state = inode->i_state => state = inode_state_read(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
>
> If ->i_lock is not held or only held conditionally:
>
> state = inode->i_state => state = inode_state_read_once(inode)
> inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
> inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
> inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
>
> fs/nilfs2/cpfile.c | 2 +-
> fs/nilfs2/dat.c | 2 +-
> fs/nilfs2/ifile.c | 2 +-
> fs/nilfs2/inode.c | 10 +++++-----
> fs/nilfs2/sufile.c | 2 +-
> 5 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c
> index bcc7d76269ac..4bbdc832d7f2 100644
> --- a/fs/nilfs2/cpfile.c
> +++ b/fs/nilfs2/cpfile.c
> @@ -1148,7 +1148,7 @@ int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,
> cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);
> if (unlikely(!cpfile))
> return -ENOMEM;
> - if (!(cpfile->i_state & I_NEW))
> + if (!(inode_state_read_once(cpfile) & I_NEW))
> goto out;
>
> err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0);
> diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c
> index c664daba56ae..674380837ab9 100644
> --- a/fs/nilfs2/dat.c
> +++ b/fs/nilfs2/dat.c
> @@ -506,7 +506,7 @@ int nilfs_dat_read(struct super_block *sb, size_t entry_size,
> dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO);
> if (unlikely(!dat))
> return -ENOMEM;
> - if (!(dat->i_state & I_NEW))
> + if (!(inode_state_read_once(dat) & I_NEW))
> goto out;
>
> err = nilfs_mdt_init(dat, NILFS_MDT_GFP, sizeof(*di));
> diff --git a/fs/nilfs2/ifile.c b/fs/nilfs2/ifile.c
> index c4cd4a4dedd0..99eb8a59009e 100644
> --- a/fs/nilfs2/ifile.c
> +++ b/fs/nilfs2/ifile.c
> @@ -188,7 +188,7 @@ int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
> ifile = nilfs_iget_locked(sb, root, NILFS_IFILE_INO);
> if (unlikely(!ifile))
> return -ENOMEM;
> - if (!(ifile->i_state & I_NEW))
> + if (!(inode_state_read_once(ifile) & I_NEW))
> goto out;
>
> err = nilfs_mdt_init(ifile, NILFS_MDT_GFP,
> diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
> index 87ddde159f0c..51bde45d5865 100644
> --- a/fs/nilfs2/inode.c
> +++ b/fs/nilfs2/inode.c
> @@ -365,7 +365,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
>
> failed_after_creation:
> clear_nlink(inode);
> - if (inode->i_state & I_NEW)
> + if (inode_state_read_once(inode) & I_NEW)
> unlock_new_inode(inode);
> iput(inode); /*
> * raw_inode will be deleted through
> @@ -562,7 +562,7 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
> if (unlikely(!inode))
> return ERR_PTR(-ENOMEM);
>
> - if (!(inode->i_state & I_NEW)) {
> + if (!(inode_state_read_once(inode) & I_NEW)) {
> if (!inode->i_nlink) {
> iput(inode);
> return ERR_PTR(-ESTALE);
> @@ -591,7 +591,7 @@ struct inode *nilfs_iget_for_gc(struct super_block *sb, unsigned long ino,
> inode = iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args);
> if (unlikely(!inode))
> return ERR_PTR(-ENOMEM);
> - if (!(inode->i_state & I_NEW))
> + if (!(inode_state_read_once(inode) & I_NEW))
> return inode;
>
> err = nilfs_init_gcinode(inode);
> @@ -631,7 +631,7 @@ int nilfs_attach_btree_node_cache(struct inode *inode)
> nilfs_iget_set, &args);
> if (unlikely(!btnc_inode))
> return -ENOMEM;
> - if (btnc_inode->i_state & I_NEW) {
> + if (inode_state_read_once(btnc_inode) & I_NEW) {
> nilfs_init_btnc_inode(btnc_inode);
> unlock_new_inode(btnc_inode);
> }
> @@ -686,7 +686,7 @@ struct inode *nilfs_iget_for_shadow(struct inode *inode)
> nilfs_iget_set, &args);
> if (unlikely(!s_inode))
> return ERR_PTR(-ENOMEM);
> - if (!(s_inode->i_state & I_NEW))
> + if (!(inode_state_read_once(s_inode) & I_NEW))
> return inode;
>
> NILFS_I(s_inode)->i_flags = 0;
> diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c
> index 330f269abedf..83f93337c01b 100644
> --- a/fs/nilfs2/sufile.c
> +++ b/fs/nilfs2/sufile.c
> @@ -1226,7 +1226,7 @@ int nilfs_sufile_read(struct super_block *sb, size_t susize,
> sufile = nilfs_iget_locked(sb, NULL, NILFS_SUFILE_INO);
> if (unlikely(!sufile))
> return -ENOMEM;
> - if (!(sufile->i_state & I_NEW))
> + if (!(inode_state_read_once(sufile) & I_NEW))
> goto out;
>
> err = nilfs_mdt_init(sufile, NILFS_MDT_GFP, sizeof(*sui));
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 13/14] xfs: use the new ->i_state accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (11 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 12/14] nilfs2: " Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:41 ` Jan Kara
2025-10-09 7:59 ` [PATCH v7 14/14] fs: make plain ->i_state access fail to compile Mateusz Guzik
` (2 subsequent siblings)
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
Change generated with coccinelle and fixed up by hand as appropriate.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
cheat sheet:
If ->i_lock is held, then:
state = inode->i_state => state = inode_state_read(inode)
inode->i_state |= (I_A | I_B) => inode_state_set(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign(inode, I_A | I_B)
If ->i_lock is not held or only held conditionally:
state = inode->i_state => state = inode_state_read_once(inode)
inode->i_state |= (I_A | I_B) => inode_state_set_raw(inode, I_A | I_B)
inode->i_state &= ~(I_A | I_B) => inode_state_clear_raw(inode, I_A | I_B)
inode->i_state = I_A | I_B => inode_state_assign_raw(inode, I_A | I_B)
fs/xfs/scrub/common.c | 2 +-
fs/xfs/scrub/inode_repair.c | 2 +-
fs/xfs/scrub/parent.c | 2 +-
fs/xfs/xfs_bmap_util.c | 2 +-
fs/xfs/xfs_health.c | 4 ++--
fs/xfs/xfs_icache.c | 6 +++---
fs/xfs/xfs_inode.c | 6 +++---
fs/xfs/xfs_inode_item.c | 4 ++--
fs/xfs/xfs_iops.c | 2 +-
fs/xfs/xfs_reflink.h | 2 +-
10 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 2ef7742be7d3..7bfa37c99480 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -1249,7 +1249,7 @@ xchk_irele(
* hits do not clear DONTCACHE, so we must do it here.
*/
spin_lock(&VFS_I(ip)->i_lock);
- VFS_I(ip)->i_state &= ~I_DONTCACHE;
+ inode_state_clear(VFS_I(ip), I_DONTCACHE);
spin_unlock(&VFS_I(ip)->i_lock);
}
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index a90a011c7e5f..4f7040c9ddf0 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -1933,7 +1933,7 @@ xrep_inode_pptr(
* Unlinked inodes that cannot be added to the directory tree will not
* have a parent pointer.
*/
- if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
+ if (inode->i_nlink == 0 && !(inode_state_read_once(inode) & I_LINKABLE))
return 0;
/* Children of the superblock do not have parent pointers. */
diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c
index 3b692c4acc1e..11d5de10fd56 100644
--- a/fs/xfs/scrub/parent.c
+++ b/fs/xfs/scrub/parent.c
@@ -915,7 +915,7 @@ xchk_pptr_looks_zapped(
* Temporary files that cannot be linked into the directory tree do not
* have attr forks because they cannot ever have parents.
*/
- if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
+ if (inode->i_nlink == 0 && !(inode_state_read_once(inode) & I_LINKABLE))
return false;
/*
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 06ca11731e43..2208a720ec3f 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -514,7 +514,7 @@ xfs_can_free_eofblocks(
* Caller must either hold the exclusive io lock; or be inactivating
* the inode, which guarantees there are no other users of the inode.
*/
- if (!(VFS_I(ip)->i_state & I_FREEING))
+ if (!(inode_state_read_once(VFS_I(ip)) & I_FREEING))
xfs_assert_ilocked(ip, XFS_IOLOCK_EXCL);
/* prealloc/delalloc exists only on regular files */
diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
index 7c541fb373d5..3c1557fb1cf0 100644
--- a/fs/xfs/xfs_health.c
+++ b/fs/xfs/xfs_health.c
@@ -285,7 +285,7 @@ xfs_inode_mark_sick(
* is not the case here.
*/
spin_lock(&VFS_I(ip)->i_lock);
- VFS_I(ip)->i_state &= ~I_DONTCACHE;
+ inode_state_clear(VFS_I(ip), I_DONTCACHE);
spin_unlock(&VFS_I(ip)->i_lock);
}
@@ -309,7 +309,7 @@ xfs_inode_mark_corrupt(
* is not the case here.
*/
spin_lock(&VFS_I(ip)->i_lock);
- VFS_I(ip)->i_state &= ~I_DONTCACHE;
+ inode_state_clear(VFS_I(ip), I_DONTCACHE);
spin_unlock(&VFS_I(ip)->i_lock);
}
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index e44040206851..f3fc4d21bfe1 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -334,7 +334,7 @@ xfs_reinit_inode(
dev_t dev = inode->i_rdev;
kuid_t uid = inode->i_uid;
kgid_t gid = inode->i_gid;
- unsigned long state = inode->i_state;
+ unsigned long state = inode_state_read_once(inode);
error = inode_init_always(mp->m_super, inode);
@@ -345,7 +345,7 @@ xfs_reinit_inode(
inode->i_rdev = dev;
inode->i_uid = uid;
inode->i_gid = gid;
- inode->i_state = state;
+ inode_state_assign_raw(inode, state);
mapping_set_folio_min_order(inode->i_mapping,
M_IGEO(mp)->min_folio_order);
return error;
@@ -411,7 +411,7 @@ xfs_iget_recycle(
ip->i_flags |= XFS_INEW;
xfs_perag_clear_inode_tag(pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
XFS_ICI_RECLAIM_TAG);
- inode->i_state = I_NEW;
+ inode_state_assign_raw(inode, I_NEW);
spin_unlock(&ip->i_flags_lock);
spin_unlock(&pag->pag_ici_lock);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 36b39539e561..f1f88e48fe22 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1580,7 +1580,7 @@ xfs_iunlink_reload_next(
next_ip->i_prev_unlinked = prev_agino;
trace_xfs_iunlink_reload_next(next_ip);
rele:
- ASSERT(!(VFS_I(next_ip)->i_state & I_DONTCACHE));
+ ASSERT(!(inode_state_read_once(VFS_I(next_ip)) & I_DONTCACHE));
if (xfs_is_quotacheck_running(mp) && next_ip)
xfs_iflags_set(next_ip, XFS_IQUOTAUNCHECKED);
xfs_irele(next_ip);
@@ -2111,7 +2111,7 @@ xfs_rename_alloc_whiteout(
*/
xfs_setup_iops(tmpfile);
xfs_finish_inode_setup(tmpfile);
- VFS_I(tmpfile)->i_state |= I_LINKABLE;
+ inode_state_set_raw(VFS_I(tmpfile), I_LINKABLE);
*wip = tmpfile;
return 0;
@@ -2330,7 +2330,7 @@ xfs_rename(
* flag from the inode so it doesn't accidentally get misused in
* future.
*/
- VFS_I(du_wip.ip)->i_state &= ~I_LINKABLE;
+ inode_state_clear_raw(VFS_I(du_wip.ip), I_LINKABLE);
}
out_commit:
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 1bd411a1114c..2eb0c6011a2e 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -113,9 +113,9 @@ xfs_inode_item_precommit(
* to log the timestamps, or will clear already cleared fields in the
* worst case.
*/
- if (inode->i_state & I_DIRTY_TIME) {
+ if (inode_state_read_once(inode) & I_DIRTY_TIME) {
spin_lock(&inode->i_lock);
- inode->i_state &= ~I_DIRTY_TIME;
+ inode_state_clear(inode, I_DIRTY_TIME);
spin_unlock(&inode->i_lock);
}
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index caff0125faea..ad94fbf55014 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1420,7 +1420,7 @@ xfs_setup_inode(
bool is_meta = xfs_is_internal_inode(ip);
inode->i_ino = ip->i_ino;
- inode->i_state |= I_NEW;
+ inode_state_set_raw(inode, I_NEW);
inode_sb_list_add(inode);
/* make the inode look hashed for the writeback code */
diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h
index 36cda724da89..9d1ed9bb0bee 100644
--- a/fs/xfs/xfs_reflink.h
+++ b/fs/xfs/xfs_reflink.h
@@ -17,7 +17,7 @@ xfs_can_free_cowblocks(struct xfs_inode *ip)
{
struct inode *inode = VFS_I(ip);
- if ((inode->i_state & I_DIRTY_PAGES) ||
+ if ((inode_state_read_once(inode) & I_DIRTY_PAGES) ||
mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY) ||
mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK) ||
atomic_read(&inode->i_dio_count))
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 13/14] xfs: use the new ->i_state accessors
2025-10-09 7:59 ` [PATCH v7 13/14] xfs: " Mateusz Guzik
@ 2025-10-10 14:41 ` Jan Kara
2025-10-10 15:40 ` Mateusz Guzik
0 siblings, 1 reply; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:41 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:27, Mateusz Guzik wrote:
> Change generated with coccinelle and fixed up by hand as appropriate.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
...
> @@ -2111,7 +2111,7 @@ xfs_rename_alloc_whiteout(
> */
> xfs_setup_iops(tmpfile);
> xfs_finish_inode_setup(tmpfile);
> - VFS_I(tmpfile)->i_state |= I_LINKABLE;
> + inode_state_set_raw(VFS_I(tmpfile), I_LINKABLE);
>
> *wip = tmpfile;
> return 0;
> @@ -2330,7 +2330,7 @@ xfs_rename(
> * flag from the inode so it doesn't accidentally get misused in
> * future.
> */
> - VFS_I(du_wip.ip)->i_state &= ~I_LINKABLE;
> + inode_state_clear_raw(VFS_I(du_wip.ip), I_LINKABLE);
> }
>
> out_commit:
These two accesses look fishy (not your fault but when we are doing this
i_state exercise better make sure all the places are correct before
papering over bugs with _raw function variant). How come they cannot race
with other i_state modifications and thus corrupt i_state?
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index caff0125faea..ad94fbf55014 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -1420,7 +1420,7 @@ xfs_setup_inode(
> bool is_meta = xfs_is_internal_inode(ip);
>
> inode->i_ino = ip->i_ino;
> - inode->i_state |= I_NEW;
> + inode_state_set_raw(inode, I_NEW);
>
> inode_sb_list_add(inode);
> /* make the inode look hashed for the writeback code */
Frankly, the XFS i_state handling is kind of messy and I suspect we should
be getting i_state == 0 here. But we need to confirm with XFS guys. I'm
poking into this because this is actually the only case where we need
inode_state_set_raw() or inode_state_clear_raw() outside of core VFS and
I'd like to get rid of these functions because IMHO they are actively
dangerous to use.
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 13/14] xfs: use the new ->i_state accessors
2025-10-10 14:41 ` Jan Kara
@ 2025-10-10 15:40 ` Mateusz Guzik
2025-10-15 0:02 ` Dave Chinner
0 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-10 15:40 UTC (permalink / raw)
To: Jan Kara
Cc: brauner, viro, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs
On Fri, Oct 10, 2025 at 4:41 PM Jan Kara <jack@suse.cz> wrote:
>
> On Thu 09-10-25 09:59:27, Mateusz Guzik wrote:
> > Change generated with coccinelle and fixed up by hand as appropriate.
> >
> > Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
>
> ...
>
> > @@ -2111,7 +2111,7 @@ xfs_rename_alloc_whiteout(
> > */
> > xfs_setup_iops(tmpfile);
> > xfs_finish_inode_setup(tmpfile);
> > - VFS_I(tmpfile)->i_state |= I_LINKABLE;
> > + inode_state_set_raw(VFS_I(tmpfile), I_LINKABLE);
> >
> > *wip = tmpfile;
> > return 0;
> > @@ -2330,7 +2330,7 @@ xfs_rename(
> > * flag from the inode so it doesn't accidentally get misused in
> > * future.
> > */
> > - VFS_I(du_wip.ip)->i_state &= ~I_LINKABLE;
> > + inode_state_clear_raw(VFS_I(du_wip.ip), I_LINKABLE);
> > }
> >
> > out_commit:
>
> These two accesses look fishy (not your fault but when we are doing this
> i_state exercise better make sure all the places are correct before
> papering over bugs with _raw function variant). How come they cannot race
> with other i_state modifications and thus corrupt i_state?
>
I asked about this here:
https://lore.kernel.org/linux-xfs/CAGudoHEi05JGkTQ9PbM20D98S9fv0hTqpWRd5fWjEwkExSiVSw@mail.gmail.com/
> > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > index caff0125faea..ad94fbf55014 100644
> > --- a/fs/xfs/xfs_iops.c
> > +++ b/fs/xfs/xfs_iops.c
> > @@ -1420,7 +1420,7 @@ xfs_setup_inode(
> > bool is_meta = xfs_is_internal_inode(ip);
> >
> > inode->i_ino = ip->i_ino;
> > - inode->i_state |= I_NEW;
> > + inode_state_set_raw(inode, I_NEW);
> >
> > inode_sb_list_add(inode);
> > /* make the inode look hashed for the writeback code */
>
> Frankly, the XFS i_state handling is kind of messy and I suspect we should
> be getting i_state == 0 here. But we need to confirm with XFS guys. I'm
> poking into this because this is actually the only case where we need
> inode_state_set_raw() or inode_state_clear_raw() outside of core VFS and
> I'd like to get rid of these functions because IMHO they are actively
> dangerous to use.
>
I'm going to address this in the other e-mail.
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 13/14] xfs: use the new ->i_state accessors
2025-10-10 15:40 ` Mateusz Guzik
@ 2025-10-15 0:02 ` Dave Chinner
2025-10-15 2:10 ` Mateusz Guzik
0 siblings, 1 reply; 41+ messages in thread
From: Dave Chinner @ 2025-10-15 0:02 UTC (permalink / raw)
To: Mateusz Guzik
Cc: Jan Kara, brauner, viro, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Fri, Oct 10, 2025 at 05:40:49PM +0200, Mateusz Guzik wrote:
> On Fri, Oct 10, 2025 at 4:41 PM Jan Kara <jack@suse.cz> wrote:
> >
> > On Thu 09-10-25 09:59:27, Mateusz Guzik wrote:
> > > Change generated with coccinelle and fixed up by hand as appropriate.
> > >
> > > Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
> >
> > ...
> >
> > > @@ -2111,7 +2111,7 @@ xfs_rename_alloc_whiteout(
> > > */
> > > xfs_setup_iops(tmpfile);
> > > xfs_finish_inode_setup(tmpfile);
> > > - VFS_I(tmpfile)->i_state |= I_LINKABLE;
> > > + inode_state_set_raw(VFS_I(tmpfile), I_LINKABLE);
> > >
> > > *wip = tmpfile;
> > > return 0;
> > > @@ -2330,7 +2330,7 @@ xfs_rename(
> > > * flag from the inode so it doesn't accidentally get misused in
> > > * future.
> > > */
> > > - VFS_I(du_wip.ip)->i_state &= ~I_LINKABLE;
> > > + inode_state_clear_raw(VFS_I(du_wip.ip), I_LINKABLE);
> > > }
> > >
> > > out_commit:
> >
> > These two accesses look fishy (not your fault but when we are doing this
> > i_state exercise better make sure all the places are correct before
> > papering over bugs with _raw function variant). How come they cannot race
> > with other i_state modifications and thus corrupt i_state?
> >
>
> I asked about this here:
> https://lore.kernel.org/linux-xfs/CAGudoHEi05JGkTQ9PbM20D98S9fv0hTqpWRd5fWjEwkExSiVSw@mail.gmail.com/
Yes, as I said, we can add locking here if necessary, but locking
isn't necessary at this point in time because nothing else can
change the state of the newly allocated whiteout inode until we
unlock it.
Keep in mind the reason why we need I_LINKABLE here - it's not
needed for correctness - it's needed to avoid a warning embedded
in inc_nlink() because filesystems aren't trusted to implement
link counts correctly anymore.
Now we're being told that "it is too dangerous to let filesystems
manage inode state themselves" and so we have to add extra overhead
to code that we were forced to add to avoid VFS warnings added
because the VFS doesn't trust filesystems to maintain some other
important inode state....
So, if you want to get rid of XFS using I_LINKABLE here, please fix
the nlink VFS api to allow us to call inc_nlink_<something>() on a
zero link inode without I_LINKABLE needing to be set. We do actually
know what we are doing here, and as such needing I_LINKABLE here is
nothing but a hacky workaround for inflexible, trustless VFS APIs...
> > > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > > index caff0125faea..ad94fbf55014 100644
> > > --- a/fs/xfs/xfs_iops.c
> > > +++ b/fs/xfs/xfs_iops.c
> > > @@ -1420,7 +1420,7 @@ xfs_setup_inode(
> > > bool is_meta = xfs_is_internal_inode(ip);
> > >
> > > inode->i_ino = ip->i_ino;
> > > - inode->i_state |= I_NEW;
> > > + inode_state_set_raw(inode, I_NEW);
"set" is wrong and will introduce a regression. This must be an
"add" operation as inode->i_state may have already been modified
by the time we get here. From 2021:
commit f38a032b165d812b0ba8378a5cd237c0888ff65f
Author: Dave Chinner <dchinner@redhat.com>
Date: Tue Aug 24 19:13:04 2021 -0700
xfs: fix I_DONTCACHE
Yup, the VFS hoist broke it, and nobody noticed. Bulkstat workloads
make it clear that it doesn't work as it should.
Fixes: dae2f8ed7992 ("fs: Lift XFS_IDONTCACHE to the VFS layer")
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index a3fe4c5307d3..f2210d927481 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -84,8 +84,9 @@ xfs_inode_alloc(
return NULL;
}
- /* VFS doesn't initialise i_mode! */
+ /* VFS doesn't initialise i_mode or i_state! */
VFS_I(ip)->i_mode = 0;
+ VFS_I(ip)->i_state = 0;
XFS_STATS_INC(mp, vn_active);
ASSERT(atomic_read(&ip->i_pincount) == 0);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 0ff0cca94092..a607d6aca5c4 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1344,7 +1344,7 @@ xfs_setup_inode(
gfp_t gfp_mask;
inode->i_ino = ip->i_ino;
- inode->i_state = I_NEW;
+ inode->i_state |= I_NEW;
inode_sb_list_add(inode);
/* make the inode look hashed for the writeback code */
-Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 13/14] xfs: use the new ->i_state accessors
2025-10-15 0:02 ` Dave Chinner
@ 2025-10-15 2:10 ` Mateusz Guzik
0 siblings, 0 replies; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-15 2:10 UTC (permalink / raw)
To: Dave Chinner
Cc: Jan Kara, brauner, viro, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Wed, Oct 15, 2025 at 2:02 AM Dave Chinner <david@fromorbit.com> wrote:
>
> On Fri, Oct 10, 2025 at 05:40:49PM +0200, Mateusz Guzik wrote:
> > On Fri, Oct 10, 2025 at 4:41 PM Jan Kara <jack@suse.cz> wrote:
> > >
> > > On Thu 09-10-25 09:59:27, Mateusz Guzik wrote:
> > > > Change generated with coccinelle and fixed up by hand as appropriate.
> > > >
> > > > Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
> > >
> > > ...
> > >
> > > > @@ -2111,7 +2111,7 @@ xfs_rename_alloc_whiteout(
> > > > */
> > > > xfs_setup_iops(tmpfile);
> > > > xfs_finish_inode_setup(tmpfile);
> > > > - VFS_I(tmpfile)->i_state |= I_LINKABLE;
> > > > + inode_state_set_raw(VFS_I(tmpfile), I_LINKABLE);
> > > >
> > > > *wip = tmpfile;
> > > > return 0;
> > > > @@ -2330,7 +2330,7 @@ xfs_rename(
> > > > * flag from the inode so it doesn't accidentally get misused in
> > > > * future.
> > > > */
> > > > - VFS_I(du_wip.ip)->i_state &= ~I_LINKABLE;
> > > > + inode_state_clear_raw(VFS_I(du_wip.ip), I_LINKABLE);
> > > > }
> > > >
> > > > out_commit:
> > >
> > > These two accesses look fishy (not your fault but when we are doing this
> > > i_state exercise better make sure all the places are correct before
> > > papering over bugs with _raw function variant). How come they cannot race
> > > with other i_state modifications and thus corrupt i_state?
> > >
> >
> > I asked about this here:
> > https://lore.kernel.org/linux-xfs/CAGudoHEi05JGkTQ9PbM20D98S9fv0hTqpWRd5fWjEwkExSiVSw@mail.gmail.com/
>
> Yes, as I said, we can add locking here if necessary, but locking
> isn't necessary at this point in time because nothing else can
> change the state of the newly allocated whiteout inode until we
> unlock it.
>
I don't have much of an opinion about this bit. Not as per my response
I added routines to facilitate not taking the lock (for the time being
anyway).
> Keep in mind the reason why we need I_LINKABLE here - it's not
> needed for correctness - it's needed to avoid a warning embedded
> in inc_nlink() because filesystems aren't trusted to implement
> link counts correctly anymore.
Ok, I did not know that. Maybe I'll take a stab at sorting this out.
xfs aside, for unrelated reasons I was looking at the placement of the
indicator to begin with. Seems like for basic correctness this in fact
wants the inode lock (not the spin lock) and the spin lock is only
taken to synchronize against other spots which modify i_state. Perhaps
it should move, which would also obsolete the above woes.
> Now we're being told that "it is too dangerous to let filesystems
> manage inode state themselves" and so we have to add extra overhead
> to code that we were forced to add to avoid VFS warnings added
> because the VFS doesn't trust filesystems to maintain some other
> important inode state....
>
Given that this is how XFS behaved for a long time now and that
perhaps the I_LINKABLE handling can be redone in the first place,
perhaps Jan will be willing to un-NAK this bit.
> So, if you want to get rid of XFS using I_LINKABLE here, please fix
> the nlink VFS api to allow us to call inc_nlink_<something>() on a
> zero link inode without I_LINKABLE needing to be set. We do actually
> know what we are doing here, and as such needing I_LINKABLE here is
> nothing but a hacky workaround for inflexible, trustless VFS APIs...
>
> > > > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > > > index caff0125faea..ad94fbf55014 100644
> > > > --- a/fs/xfs/xfs_iops.c
> > > > +++ b/fs/xfs/xfs_iops.c
> > > > @@ -1420,7 +1420,7 @@ xfs_setup_inode(
> > > > bool is_meta = xfs_is_internal_inode(ip);
> > > >
> > > > inode->i_ino = ip->i_ino;
> > > > - inode->i_state |= I_NEW;
> > > > + inode_state_set_raw(inode, I_NEW);
>
> "set" is wrong and will introduce a regression. This must be an
> "add" operation as inode->i_state may have already been modified
> by the time we get here.
There were complaints about original naming and _add/_del/_set got
whacked. So now this settled on _set/_clear/_assign, per the cheat
sheet in the patch. So this does what it was supposed to.
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v7 14/14] fs: make plain ->i_state access fail to compile
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (12 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 13/14] xfs: " Mateusz Guzik
@ 2025-10-09 7:59 ` Mateusz Guzik
2025-10-10 14:26 ` Jan Kara
2025-10-10 11:24 ` [PATCH v7 00/14] hide ->i_state behind accessors Christian Brauner
2025-10-10 11:29 ` Christian Brauner
15 siblings, 1 reply; 41+ messages in thread
From: Mateusz Guzik @ 2025-10-09 7:59 UTC (permalink / raw)
To: brauner
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs, Mateusz Guzik
... to make sure all accesses are properly validated.
Merely renaming the var to __i_state still lets the compiler make the
following suggestion:
error: 'struct inode' has no member named 'i_state'; did you mean '__i_state'?
Unfortunately some people will add the __'s and call it a day.
In order to make it harder to mess up in this way, hide it behind a
struct. The resulting error message should be convincing in terms of
checking what to do:
error: invalid operands to binary & (have 'struct inode_state_flags' and 'int')
Of course people determined to do a plain access can still do it, but
nothing can be done for that case.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
include/linux/fs.h | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 77b6486dcae7..21c73df3ce75 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -785,6 +785,13 @@ enum inode_state_flags_enum {
#define I_DIRTY (I_DIRTY_INODE | I_DIRTY_PAGES)
#define I_DIRTY_ALL (I_DIRTY | I_DIRTY_TIME)
+/*
+ * Use inode_state_read() & friends to access.
+ */
+struct inode_state_flags {
+ enum inode_state_flags_enum __state;
+};
+
/*
* Keep mostly read-only and often accessed (especially for
* the RCU path lookup and 'stat' data) fields at the beginning
@@ -843,7 +850,7 @@ struct inode {
#endif
/* Misc */
- enum inode_state_flags_enum i_state;
+ struct inode_state_flags i_state;
/* 32-bit hole */
struct rw_semaphore i_rwsem;
@@ -909,19 +916,19 @@ struct inode {
*/
static inline enum inode_state_flags_enum inode_state_read_once(struct inode *inode)
{
- return READ_ONCE(inode->i_state);
+ return READ_ONCE(inode->i_state.__state);
}
static inline enum inode_state_flags_enum inode_state_read(struct inode *inode)
{
lockdep_assert_held(&inode->i_lock);
- return inode->i_state;
+ return inode->i_state.__state;
}
static inline void inode_state_set_raw(struct inode *inode,
enum inode_state_flags_enum flags)
{
- WRITE_ONCE(inode->i_state, inode->i_state | flags);
+ WRITE_ONCE(inode->i_state.__state, inode->i_state.__state | flags);
}
static inline void inode_state_set(struct inode *inode,
@@ -934,7 +941,7 @@ static inline void inode_state_set(struct inode *inode,
static inline void inode_state_clear_raw(struct inode *inode,
enum inode_state_flags_enum flags)
{
- WRITE_ONCE(inode->i_state, inode->i_state & ~flags);
+ WRITE_ONCE(inode->i_state.__state, inode->i_state.__state & ~flags);
}
static inline void inode_state_clear(struct inode *inode,
@@ -947,7 +954,7 @@ static inline void inode_state_clear(struct inode *inode,
static inline void inode_state_assign_raw(struct inode *inode,
enum inode_state_flags_enum flags)
{
- WRITE_ONCE(inode->i_state, flags);
+ WRITE_ONCE(inode->i_state.__state, flags);
}
static inline void inode_state_assign(struct inode *inode,
@@ -962,7 +969,7 @@ static inline void inode_state_replace_raw(struct inode *inode,
enum inode_state_flags_enum setflags)
{
enum inode_state_flags_enum flags;
- flags = inode->i_state;
+ flags = inode->i_state.__state;
flags &= ~clearflags;
flags |= setflags;
inode_state_assign_raw(inode, flags);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PATCH v7 14/14] fs: make plain ->i_state access fail to compile
2025-10-09 7:59 ` [PATCH v7 14/14] fs: make plain ->i_state access fail to compile Mateusz Guzik
@ 2025-10-10 14:26 ` Jan Kara
0 siblings, 0 replies; 41+ messages in thread
From: Jan Kara @ 2025-10-10 14:26 UTC (permalink / raw)
To: Mateusz Guzik
Cc: brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu 09-10-25 09:59:28, Mateusz Guzik wrote:
> ... to make sure all accesses are properly validated.
>
> Merely renaming the var to __i_state still lets the compiler make the
> following suggestion:
> error: 'struct inode' has no member named 'i_state'; did you mean '__i_state'?
>
> Unfortunately some people will add the __'s and call it a day.
>
> In order to make it harder to mess up in this way, hide it behind a
> struct. The resulting error message should be convincing in terms of
> checking what to do:
> error: invalid operands to binary & (have 'struct inode_state_flags' and 'int')
>
> Of course people determined to do a plain access can still do it, but
> nothing can be done for that case.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> include/linux/fs.h | 21 ++++++++++++++-------
> 1 file changed, 14 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 77b6486dcae7..21c73df3ce75 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -785,6 +785,13 @@ enum inode_state_flags_enum {
> #define I_DIRTY (I_DIRTY_INODE | I_DIRTY_PAGES)
> #define I_DIRTY_ALL (I_DIRTY | I_DIRTY_TIME)
>
> +/*
> + * Use inode_state_read() & friends to access.
> + */
> +struct inode_state_flags {
> + enum inode_state_flags_enum __state;
> +};
> +
> /*
> * Keep mostly read-only and often accessed (especially for
> * the RCU path lookup and 'stat' data) fields at the beginning
> @@ -843,7 +850,7 @@ struct inode {
> #endif
>
> /* Misc */
> - enum inode_state_flags_enum i_state;
> + struct inode_state_flags i_state;
> /* 32-bit hole */
> struct rw_semaphore i_rwsem;
>
> @@ -909,19 +916,19 @@ struct inode {
> */
> static inline enum inode_state_flags_enum inode_state_read_once(struct inode *inode)
> {
> - return READ_ONCE(inode->i_state);
> + return READ_ONCE(inode->i_state.__state);
> }
>
> static inline enum inode_state_flags_enum inode_state_read(struct inode *inode)
> {
> lockdep_assert_held(&inode->i_lock);
> - return inode->i_state;
> + return inode->i_state.__state;
> }
>
> static inline void inode_state_set_raw(struct inode *inode,
> enum inode_state_flags_enum flags)
> {
> - WRITE_ONCE(inode->i_state, inode->i_state | flags);
> + WRITE_ONCE(inode->i_state.__state, inode->i_state.__state | flags);
> }
>
> static inline void inode_state_set(struct inode *inode,
> @@ -934,7 +941,7 @@ static inline void inode_state_set(struct inode *inode,
> static inline void inode_state_clear_raw(struct inode *inode,
> enum inode_state_flags_enum flags)
> {
> - WRITE_ONCE(inode->i_state, inode->i_state & ~flags);
> + WRITE_ONCE(inode->i_state.__state, inode->i_state.__state & ~flags);
> }
>
> static inline void inode_state_clear(struct inode *inode,
> @@ -947,7 +954,7 @@ static inline void inode_state_clear(struct inode *inode,
> static inline void inode_state_assign_raw(struct inode *inode,
> enum inode_state_flags_enum flags)
> {
> - WRITE_ONCE(inode->i_state, flags);
> + WRITE_ONCE(inode->i_state.__state, flags);
> }
>
> static inline void inode_state_assign(struct inode *inode,
> @@ -962,7 +969,7 @@ static inline void inode_state_replace_raw(struct inode *inode,
> enum inode_state_flags_enum setflags)
> {
> enum inode_state_flags_enum flags;
> - flags = inode->i_state;
> + flags = inode->i_state.__state;
> flags &= ~clearflags;
> flags |= setflags;
> inode_state_assign_raw(inode, flags);
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v7 00/14] hide ->i_state behind accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (13 preceding siblings ...)
2025-10-09 7:59 ` [PATCH v7 14/14] fs: make plain ->i_state access fail to compile Mateusz Guzik
@ 2025-10-10 11:24 ` Christian Brauner
2025-10-10 11:29 ` Christian Brauner
15 siblings, 0 replies; 41+ messages in thread
From: Christian Brauner @ 2025-10-10 11:24 UTC (permalink / raw)
To: Mateusz Guzik
Cc: viro, jack, linux-kernel, linux-fsdevel, josef, kernel-team,
amir73il, linux-btrfs, linux-ext4, linux-xfs, ceph-devel,
linux-unionfs
> More importantly though, this is generated against:
> https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git/log/?h=vfs-6.19.inode
>
> but that branch happens to be significantly lagging behind master,
> notably it does not include some writeback changes and bcachefs removal.
> Thus before generating the patchset I did a rebase on master.
That's fine I tend to rebase from time-to-time until -rc1 on is out
which is the final rebase.
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PATCH v7 00/14] hide ->i_state behind accessors
2025-10-09 7:59 [PATCH v7 00/14] hide ->i_state behind accessors Mateusz Guzik
` (14 preceding siblings ...)
2025-10-10 11:24 ` [PATCH v7 00/14] hide ->i_state behind accessors Christian Brauner
@ 2025-10-10 11:29 ` Christian Brauner
15 siblings, 0 replies; 41+ messages in thread
From: Christian Brauner @ 2025-10-10 11:29 UTC (permalink / raw)
To: Mateusz Guzik
Cc: Christian Brauner, viro, jack, linux-kernel, linux-fsdevel, josef,
kernel-team, amir73il, linux-btrfs, linux-ext4, linux-xfs,
ceph-devel, linux-unionfs
On Thu, 09 Oct 2025 09:59:14 +0200, Mateusz Guzik wrote:
> Commit message from the patch adding helpers quoted verbatim with rationable + API:
>
> [quote]
> Open-coded accesses prevent asserting they are done correctly. One
> obvious aspect is locking, but significantly more can checked. For
> example it can be detected when the code is clearing flags which are
> already missing, or is setting flags when it is illegal (e.g., I_FREEING
> when ->i_count > 0).
>
> [...]
Applied to the vfs-6.19.inode branch of the vfs/vfs.git tree.
Patches in the vfs-6.19.inode branch should appear in linux-next soon.
Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.
It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.
Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs-6.19.inode
[01/14] fs: move wait_on_inode() from writeback.h to fs.h
https://git.kernel.org/vfs/vfs/c/6605bf7d9536
[02/14] fs: spell out fenced ->i_state accesses with explicit smp_wmb/smp_rmb
https://git.kernel.org/vfs/vfs/c/1fdd36da49d5
[03/14] fs: provide accessors for ->i_state
https://git.kernel.org/vfs/vfs/c/1f4e908f28da
[04/14] Coccinelle-based conversion to use ->i_state accessors
https://git.kernel.org/vfs/vfs/c/91d75e00d68f
[05/14] Manual conversion to use ->i_state accessors of all places not covered by coccinelle
https://git.kernel.org/vfs/vfs/c/5b953be62d20
[06/14] btrfs: use the new ->i_state accessors
https://git.kernel.org/vfs/vfs/c/b77405952757
[07/14] ceph: use the new ->i_state accessors
https://git.kernel.org/vfs/vfs/c/9e121446182b
[08/14] smb: use the new ->i_state accessors
https://git.kernel.org/vfs/vfs/c/6f44aedc8692
[09/14] f2fs: use the new ->i_state accessors
https://git.kernel.org/vfs/vfs/c/60d14a5b26e3
[10/14] gfs2: use the new ->i_state accessors
https://git.kernel.org/vfs/vfs/c/8b5a2dbef579
[11/14] overlayfs: use the new ->i_state accessors
https://git.kernel.org/vfs/vfs/c/46ee05af3842
[12/14] nilfs2: use the new ->i_state accessors
https://git.kernel.org/vfs/vfs/c/ff6d2b3d3473
[13/14] xfs: use the new ->i_state accessors
https://git.kernel.org/vfs/vfs/c/fdbb1cb57675
[14/14] fs: make plain ->i_state access fail to compile
https://git.kernel.org/vfs/vfs/c/708bcf48adda
^ permalink raw reply [flat|nested] 41+ messages in thread