diff options
Diffstat (limited to 'patches/0002-fs-dcache-Split-__d_lookup_done.patch')
-rw-r--r-- | patches/0002-fs-dcache-Split-__d_lookup_done.patch | 98 |
1 files changed, 0 insertions, 98 deletions
diff --git a/patches/0002-fs-dcache-Split-__d_lookup_done.patch b/patches/0002-fs-dcache-Split-__d_lookup_done.patch deleted file mode 100644 index b9d731468f19..000000000000 --- a/patches/0002-fs-dcache-Split-__d_lookup_done.patch +++ /dev/null @@ -1,98 +0,0 @@ -From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> -Date: Sun, 12 Jun 2022 16:27:29 +0200 -Subject: [PATCH 2/4] fs/dcache: Split __d_lookup_done() - -__d_lookup_done() wakes waiters on dentry::d_wait inside a preemption -disabled region. This violates the PREEMPT_RT constraints as the wake up -acquires wait_queue_head::lock which is a "sleeping" spinlock on RT. - -As a first step to solve this, move the wake up outside of the -hlist_bl_lock() held section. - -This is safe because: - - 1) The whole sequence including the wake up is protected by dentry::lock. - - 2) The waitqueue head is allocated by the caller on stack and can't go - away until the whole callchain completes. - - 3) If a queued waiter is woken by a spurious wake up, then it is blocked - on dentry:lock before it can observe DCACHE_PAR_LOOKUP cleared and - return from d_wait_lookup(). - - As the wake up is inside the dentry:lock held region it's guaranteed - that the waiters waitq is dequeued from the waitqueue head before the - waiter returns. - - Moving the wake up past the unlock of dentry::lock would allow the - waiter to return with the on stack waitq still enqueued due to a - spurious wake up. - - 4) New waiters have to acquire dentry::lock before checking whether the - DCACHE_PAR_LOOKUP flag is set. - -Let __d_lookup_unhash(): - - 1) Lock the lookup hash and clear DCACHE_PAR_LOOKUP - 2) Unhash the dentry - 3) Retrieve and clear dentry::d_wait - 4) Unlock the hash and return the retrieved waitqueue head pointer - 5) Let the caller handle the wake up. - -This does not yet solve the PREEMPT_RT problem completely because -preemption is still disabled due to i_dir_seq being held for write. This -will be addressed in subsequent steps. - -An alternative solution would be to switch the waitqueue to a simple -waitqueue, but aside of Linus not being a fan of them, moving the wake up -closer to the place where dentry::lock is unlocked reduces lock contention -time for the woken up waiter. - -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> -Signed-off-by: Thomas Gleixner <tglx@linutronix.de> -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> -Link: https://lkml.kernel.org/r/20220613140712.77932-3-bigeasy@linutronix.de ---- - fs/dcache.c | 23 +++++++++++++++++++---- - 1 file changed, 19 insertions(+), 4 deletions(-) - ---- a/fs/dcache.c -+++ b/fs/dcache.c -@@ -2711,18 +2711,33 @@ struct dentry *d_alloc_parallel(struct d - } - EXPORT_SYMBOL(d_alloc_parallel); - --void __d_lookup_done(struct dentry *dentry) -+/* -+ * - Unhash the dentry -+ * - Retrieve and clear the waitqueue head in dentry -+ * - Return the waitqueue head -+ */ -+static wait_queue_head_t *__d_lookup_unhash(struct dentry *dentry) - { -- struct hlist_bl_head *b = in_lookup_hash(dentry->d_parent, -- dentry->d_name.hash); -+ wait_queue_head_t *d_wait; -+ struct hlist_bl_head *b; -+ -+ lockdep_assert_held(&dentry->d_lock); -+ -+ b = in_lookup_hash(dentry->d_parent, dentry->d_name.hash); - hlist_bl_lock(b); - dentry->d_flags &= ~DCACHE_PAR_LOOKUP; - __hlist_bl_del(&dentry->d_u.d_in_lookup_hash); -- wake_up_all(dentry->d_wait); -+ d_wait = dentry->d_wait; - dentry->d_wait = NULL; - hlist_bl_unlock(b); - INIT_HLIST_NODE(&dentry->d_u.d_alias); - INIT_LIST_HEAD(&dentry->d_lru); -+ return d_wait; -+} -+ -+void __d_lookup_done(struct dentry *dentry) -+{ -+ wake_up_all(__d_lookup_unhash(dentry)); - } - EXPORT_SYMBOL(__d_lookup_done); - |