Message ID | 20240820-work-i_state-v1-1-794360714829@kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | inode: turn i_state into u32 | expand |
On Tue, 20 Aug 2024 at 09:07, Christian Brauner <brauner@kernel.org> wrote: > > > +struct wait_queue_head *inode_bit_waitqueue(struct wait_bit_queue_entry *wqe, > + struct inode *inode, int bit); > +{ > + struct wait_queue_head *wq_head; > + void *bit_address; > + > + bit_address = inode_state_wait_address(inode, __I_SYNC); Shouldn't that '__I_SYNC' be 'bit' instead? Now it always uses the __I_SYNC wait address, but: > +static inline void inode_wake_up_bit(struct inode *inode, unsigned int bit) > +{ > + /* Ensure @bit will be seen cleared/set when caller is woken up. */ > + smp_mb(); > + wake_up_var(inode_state_wait_address(inode, bit)); > +} This uses the 'bit' wait address as expected. Linus
.. and one more comment on that patch: it would probably be a good idea to make sure that the __I_xyz constants that are used for this are in the range 0-3. It doesn't really *matter*, in the sense that it will all just be a cookie with a random address, but if anybody else ever uses the same trick (or just uses bit_waitqueue) for another field in the inode, the two cookies might end up being the same if you are very unlucky. So from a future-proofing standpoint it would be good if the cookies that are used are always "within" the address range of i_state. I don't think any of the bits in i_state have any actual meaning, so moving the bits around shouldn't be a problem. Linus
On Tue, Aug 20, 2024 at 10:10:51AM GMT, Linus Torvalds wrote: > On Tue, 20 Aug 2024 at 09:07, Christian Brauner <brauner@kernel.org> wrote: > > > > > > +struct wait_queue_head *inode_bit_waitqueue(struct wait_bit_queue_entry *wqe, > > + struct inode *inode, int bit); Bah, I sent from the wrong branch. This is the branch where I even forgot to remove that godforsaken ; at the end here... > > +{ > > + struct wait_queue_head *wq_head; > > + void *bit_address; > > + > > + bit_address = inode_state_wait_address(inode, __I_SYNC); > > Shouldn't that '__I_SYNC' be 'bit' instead? Yeah, that's also fixed on the work.i_state branch. I sent from work.i_state.wip... :/
On Tue, Aug 20, 2024 at 10:19:11AM GMT, Linus Torvalds wrote: > .. and one more comment on that patch: it would probably be a good > idea to make sure that the __I_xyz constants that are used for this > are in the range 0-3. > > It doesn't really *matter*, in the sense that it will all just be a > cookie with a random address, but if anybody else ever uses the same > trick (or just uses bit_waitqueue) for another field in the inode, the > two cookies might end up being the same if you are very unlucky. > > So from a future-proofing standpoint it would be good if the cookies > that are used are always "within" the address range of i_state. > > I don't think any of the bits in i_state have any actual meaning, so > moving the bits around shouldn't be a problem. Yeah, I reordered. I did not think this too big of an issue but you're right.
diff --git a/fs/inode.c b/fs/inode.c index 154f8689457f..d0f614677798 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -472,6 +472,17 @@ static void __inode_add_lru(struct inode *inode, bool rotate) inode->i_state |= I_REFERENCED; } +struct wait_queue_head *inode_bit_waitqueue(struct wait_bit_queue_entry *wqe, + struct inode *inode, int bit); +{ + struct wait_queue_head *wq_head; + void *bit_address; + + bit_address = inode_state_wait_address(inode, __I_SYNC); + init_wait_var_entry(wqe, bit_address, 0); + return __var_waitqueue(bit_address); +} + /* * Add inode to LRU if needed (inode is unused and clean). * diff --git a/include/linux/fs.h b/include/linux/fs.h index 23e7d46b818a..f854f83e91af 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -744,6 +744,22 @@ struct inode { void *i_private; /* fs or device private pointer */ } __randomize_layout; +/* + * Get bit address from inode->i_state to use with wait_var_event() + * infrastructre. + */ +#define inode_state_wait_address(inode, bit) ((char *)&(inode)->i_state + (bit)) + +struct wait_queue_head *inode_bit_waitqueue(struct wait_bit_queue_entry *wqe, + struct inode *inode, int bit); + +static inline void inode_wake_up_bit(struct inode *inode, unsigned int bit) +{ + /* Ensure @bit will be seen cleared/set when caller is woken up. */ + smp_mb(); + wake_up_var(inode_state_wait_address(inode, bit)); +} + struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode); static inline unsigned int i_blocksize(const struct inode *node)
The i_state member is an unsigned long so that it can be used with the wait bit infrastructure which expects unsigned long. This wastes 4 bytes which we're unlikely to ever use. Switch to using the var event wait mechanism using the address of the bit. Thanks to Linus for the address idea. Signed-off-by: Christian Brauner <brauner@kernel.org> --- fs/inode.c | 11 +++++++++++ include/linux/fs.h | 16 ++++++++++++++++ 2 files changed, 27 insertions(+)