diff options
Diffstat (limited to 'debian/patches-rt/0007-jbd2-Free-journal-head-outside-of-locked-region.patch')
-rw-r--r-- | debian/patches-rt/0007-jbd2-Free-journal-head-outside-of-locked-region.patch | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/debian/patches-rt/0007-jbd2-Free-journal-head-outside-of-locked-region.patch b/debian/patches-rt/0007-jbd2-Free-journal-head-outside-of-locked-region.patch new file mode 100644 index 000000000..17a2978c9 --- /dev/null +++ b/debian/patches-rt/0007-jbd2-Free-journal-head-outside-of-locked-region.patch @@ -0,0 +1,89 @@ +From: Thomas Gleixner <tglx@linutronix.de> +Date: Fri, 9 Aug 2019 14:42:33 +0200 +Subject: [PATCH 7/7] jbd2: Free journal head outside of locked region +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.4/older/patches-5.4.3-rt1.tar.xz + +On PREEMPT_RT bit-spinlocks have the same semantics as on PREEMPT_RT=n, +i.e. they disable preemption. That means functions which are not safe to be +called in preempt disabled context on RT trigger a might_sleep() assert. + +The journal head bit spinlock is mostly held for short code sequences with +trivial RT safe functionality, except for one place: + +jbd2_journal_put_journal_head() invokes __journal_remove_journal_head() +with the journal head bit spinlock held. __journal_remove_journal_head() +invokes kmem_cache_free() which must not be called with preemption disabled +on RT. + +Jan suggested to rework the removal function so the actual free happens +outside the bit-spinlocked region. + +Split it into two parts: + + - Do the sanity checks and the buffer head detach under the lock + + - Do the actual free after dropping the lock + +There is error case handling in the free part which needs to dereference +the b_size field of the now detached buffer head. Due to paranoia (caused +by ignorance) the size is retrieved in the detach function and handed into +the free function. Might be over-engineered, but better safe than sorry. + +This makes the journal head bit-spinlock usage RT compliant and also avoids +nested locking which is not covered by lockdep. + +Suggested-by: Jan Kara <jack@suse.com> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Cc: linux-ext4@vger.kernel.org +Cc: "Theodore Ts'o" <tytso@mit.edu> +Cc: Jan Kara <jack@suse.com> +Signed-off-by: Jan Kara <jack@suse.cz> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + fs/jbd2/journal.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -2531,17 +2531,23 @@ static void __journal_remove_journal_hea + J_ASSERT_BH(bh, buffer_jbd(bh)); + J_ASSERT_BH(bh, jh2bh(jh) == bh); + BUFFER_TRACE(bh, "remove journal_head"); ++ ++ /* Unlink before dropping the lock */ ++ bh->b_private = NULL; ++ jh->b_bh = NULL; /* debug, really */ ++ clear_buffer_jbd(bh); ++} ++ ++static void journal_release_journal_head(struct journal_head *jh, size_t b_size) ++{ + if (jh->b_frozen_data) { + printk(KERN_WARNING "%s: freeing b_frozen_data\n", __func__); +- jbd2_free(jh->b_frozen_data, bh->b_size); ++ jbd2_free(jh->b_frozen_data, b_size); + } + if (jh->b_committed_data) { + printk(KERN_WARNING "%s: freeing b_committed_data\n", __func__); +- jbd2_free(jh->b_committed_data, bh->b_size); ++ jbd2_free(jh->b_committed_data, b_size); + } +- bh->b_private = NULL; +- jh->b_bh = NULL; /* debug, really */ +- clear_buffer_jbd(bh); + journal_free_journal_head(jh); + } + +@@ -2559,9 +2565,11 @@ void jbd2_journal_put_journal_head(struc + if (!jh->b_jcount) { + __journal_remove_journal_head(bh); + jbd_unlock_bh_journal_head(bh); ++ journal_release_journal_head(jh, bh->b_size); + __brelse(bh); +- } else ++ } else { + jbd_unlock_bh_journal_head(bh); ++ } + } + + /* |