mirror of https://github.com/torvalds/linux.git
fs: move mntput_no_expire() slowpath into a dedicated routine
In the stock variant the compiler spills several registers on the stack and employs stack smashing protection, adding even more code + a branch on exit.. The actual fast path is small enough that the compiler inlines it for all callers -- the symbol is no longer emitted. Forcing noinline on it just for code-measurement purposes shows the fast path dropping from 111 to 39 bytes. Signed-off-by: Mateusz Guzik <mjguzik@gmail.com> Link: https://patch.msgid.link/20251114201803.2183505-1-mjguzik@gmail.com Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
6d228c181e
commit
bfef6e1f34
|
|
@ -1345,26 +1345,12 @@ static void delayed_mntput(struct work_struct *unused)
|
||||||
}
|
}
|
||||||
static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput);
|
static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput);
|
||||||
|
|
||||||
static void mntput_no_expire(struct mount *mnt)
|
static void noinline mntput_no_expire_slowpath(struct mount *mnt)
|
||||||
{
|
{
|
||||||
LIST_HEAD(list);
|
LIST_HEAD(list);
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
rcu_read_lock();
|
VFS_BUG_ON(mnt->mnt_ns);
|
||||||
if (likely(READ_ONCE(mnt->mnt_ns))) {
|
|
||||||
/*
|
|
||||||
* Since we don't do lock_mount_hash() here,
|
|
||||||
* ->mnt_ns can change under us. However, if it's
|
|
||||||
* non-NULL, then there's a reference that won't
|
|
||||||
* be dropped until after an RCU delay done after
|
|
||||||
* turning ->mnt_ns NULL. So if we observe it
|
|
||||||
* non-NULL under rcu_read_lock(), the reference
|
|
||||||
* we are dropping is not the final one.
|
|
||||||
*/
|
|
||||||
mnt_add_count(mnt, -1);
|
|
||||||
rcu_read_unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lock_mount_hash();
|
lock_mount_hash();
|
||||||
/*
|
/*
|
||||||
* make sure that if __legitimize_mnt() has not seen us grab
|
* make sure that if __legitimize_mnt() has not seen us grab
|
||||||
|
|
@ -1415,6 +1401,26 @@ static void mntput_no_expire(struct mount *mnt)
|
||||||
cleanup_mnt(mnt);
|
cleanup_mnt(mnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mntput_no_expire(struct mount *mnt)
|
||||||
|
{
|
||||||
|
rcu_read_lock();
|
||||||
|
if (likely(READ_ONCE(mnt->mnt_ns))) {
|
||||||
|
/*
|
||||||
|
* Since we don't do lock_mount_hash() here,
|
||||||
|
* ->mnt_ns can change under us. However, if it's
|
||||||
|
* non-NULL, then there's a reference that won't
|
||||||
|
* be dropped until after an RCU delay done after
|
||||||
|
* turning ->mnt_ns NULL. So if we observe it
|
||||||
|
* non-NULL under rcu_read_lock(), the reference
|
||||||
|
* we are dropping is not the final one.
|
||||||
|
*/
|
||||||
|
mnt_add_count(mnt, -1);
|
||||||
|
rcu_read_unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mntput_no_expire_slowpath(mnt);
|
||||||
|
}
|
||||||
|
|
||||||
void mntput(struct vfsmount *mnt)
|
void mntput(struct vfsmount *mnt)
|
||||||
{
|
{
|
||||||
if (mnt) {
|
if (mnt) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue