ext4l: Add bh_cache_release_jbd() to clean up journal references
Add bh_cache_release_jbd() to forcibly release any journal_heads still attached to buffer_heads after journal destroy. This must be called after journal destroy but before bh_cache_clear() to ensure all journal_heads are properly released, even if journal destroy did not fully clean up (e.g., on abort). The function clears b_bh in each journal_head to prevent use-after-free when the buffer_head is later freed, and resets transaction pointers. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
@@ -2901,6 +2901,7 @@ void free_buffer_head(struct buffer_head *bh);
|
||||
|
||||
/* ext4l support functions (support.c) */
|
||||
void ext4l_crc32c_init(void);
|
||||
void bh_cache_release_jbd(void);
|
||||
void bh_cache_clear(void);
|
||||
int bh_cache_sync(void);
|
||||
int ext4l_read_block(sector_t block, size_t size, void *buffer);
|
||||
|
||||
@@ -335,6 +335,42 @@ void bh_cache_clear(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bh_cache_release_jbd() - Release all JBD references from buffer cache
|
||||
*
|
||||
* This must be called after journal destroy but before bh_cache_clear().
|
||||
* It ensures all journal_heads are properly released from buffer_heads
|
||||
* even if the journal destroy didn't fully clean up (e.g., on abort).
|
||||
*/
|
||||
void bh_cache_release_jbd(void)
|
||||
{
|
||||
int i;
|
||||
struct bh_cache_entry *entry;
|
||||
|
||||
for (i = 0; i < BH_CACHE_SIZE; i++) {
|
||||
for (entry = bh_cache[i]; entry; entry = entry->next) {
|
||||
if (entry->bh && buffer_jbd(entry->bh)) {
|
||||
struct buffer_head *bh = entry->bh;
|
||||
struct journal_head *jh = bh2jh(bh);
|
||||
|
||||
/*
|
||||
* Forcibly release the journal_head.
|
||||
* Clear b_bh to prevent use-after-free when
|
||||
* the buffer_head is later freed.
|
||||
*/
|
||||
if (jh) {
|
||||
jh->b_bh = NULL;
|
||||
jh->b_transaction = NULL;
|
||||
jh->b_next_transaction = NULL;
|
||||
jh->b_cp_transaction = NULL;
|
||||
}
|
||||
clear_buffer_jbd(bh);
|
||||
bh->b_private = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bh_cache_sync() - Sync all dirty buffers to disk
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user