Skip to content

Commit 7855a57

Browse files
KAGA-KOKOtytso
authored andcommitted
jbd2: Free journal head outside of locked region
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 <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: "Theodore Ts'o" <[email protected]> Cc: Jan Kara <[email protected]> Signed-off-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 4641706 commit 7855a57

File tree

1 file changed

+14
-6
lines changed

1 file changed

+14
-6
lines changed

fs/jbd2/journal.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,17 +2531,23 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
25312531
J_ASSERT_BH(bh, buffer_jbd(bh));
25322532
J_ASSERT_BH(bh, jh2bh(jh) == bh);
25332533
BUFFER_TRACE(bh, "remove journal_head");
2534+
2535+
/* Unlink before dropping the lock */
2536+
bh->b_private = NULL;
2537+
jh->b_bh = NULL; /* debug, really */
2538+
clear_buffer_jbd(bh);
2539+
}
2540+
2541+
static void journal_release_journal_head(struct journal_head *jh, size_t b_size)
2542+
{
25342543
if (jh->b_frozen_data) {
25352544
printk(KERN_WARNING "%s: freeing b_frozen_data\n", __func__);
2536-
jbd2_free(jh->b_frozen_data, bh->b_size);
2545+
jbd2_free(jh->b_frozen_data, b_size);
25372546
}
25382547
if (jh->b_committed_data) {
25392548
printk(KERN_WARNING "%s: freeing b_committed_data\n", __func__);
2540-
jbd2_free(jh->b_committed_data, bh->b_size);
2549+
jbd2_free(jh->b_committed_data, b_size);
25412550
}
2542-
bh->b_private = NULL;
2543-
jh->b_bh = NULL; /* debug, really */
2544-
clear_buffer_jbd(bh);
25452551
journal_free_journal_head(jh);
25462552
}
25472553

@@ -2559,9 +2565,11 @@ void jbd2_journal_put_journal_head(struct journal_head *jh)
25592565
if (!jh->b_jcount) {
25602566
__journal_remove_journal_head(bh);
25612567
jbd_unlock_bh_journal_head(bh);
2568+
journal_release_journal_head(jh, bh->b_size);
25622569
__brelse(bh);
2563-
} else
2570+
} else {
25642571
jbd_unlock_bh_journal_head(bh);
2572+
}
25652573
}
25662574

25672575
/*

0 commit comments

Comments
 (0)