ext4 journal commit callbacks access jbd2_inode fields such as
i_transaction and i_dirty_start/end without holding journal->j_list_lock.
Use READ_ONCE() for these reads to correct the concurrency assumptions.
Suggested-by: Jan Kara <jack@suse.com>
Signed-off-by: Li Chen <me@linux.beauty>
---
fs/ext4/inode.c | 6 ++++--
fs/ext4/super.c | 13 ++++++++-----
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index d99296d7315f..2d451388e080 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3033,11 +3033,13 @@ static int ext4_writepages(struct address_space *mapping,
int ext4_normal_submit_inode_data_buffers(struct jbd2_inode *jinode)
{
+ loff_t dirty_start = READ_ONCE(jinode->i_dirty_start);
+ loff_t dirty_end = READ_ONCE(jinode->i_dirty_end);
struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL,
.nr_to_write = LONG_MAX,
- .range_start = jinode->i_dirty_start,
- .range_end = jinode->i_dirty_end,
+ .range_start = dirty_start,
+ .range_end = dirty_end,
};
struct mpage_da_data mpd = {
.inode = jinode->i_vfs_inode,
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 5cf6c2b54bbb..acb2bc016fd4 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -521,6 +521,7 @@ static bool ext4_journalled_writepage_needs_redirty(struct jbd2_inode *jinode,
{
struct buffer_head *bh, *head;
struct journal_head *jh;
+ transaction_t *trans = READ_ONCE(jinode->i_transaction);
bh = head = folio_buffers(folio);
do {
@@ -539,7 +540,7 @@ static bool ext4_journalled_writepage_needs_redirty(struct jbd2_inode *jinode,
*/
jh = bh2jh(bh);
if (buffer_dirty(bh) ||
- (jh && (jh->b_transaction != jinode->i_transaction ||
+ (jh && (jh->b_transaction != trans ||
jh->b_next_transaction)))
return true;
} while ((bh = bh->b_this_page) != head);
@@ -550,12 +551,14 @@ static bool ext4_journalled_writepage_needs_redirty(struct jbd2_inode *jinode,
static int ext4_journalled_submit_inode_data_buffers(struct jbd2_inode *jinode)
{
struct address_space *mapping = jinode->i_vfs_inode->i_mapping;
+ loff_t dirty_start = READ_ONCE(jinode->i_dirty_start);
+ loff_t dirty_end = READ_ONCE(jinode->i_dirty_end);
struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
+ .sync_mode = WB_SYNC_ALL,
.nr_to_write = LONG_MAX,
- .range_start = jinode->i_dirty_start,
- .range_end = jinode->i_dirty_end,
- };
+ .range_start = dirty_start,
+ .range_end = dirty_end,
+ };
struct folio *folio = NULL;
int error;
--
2.52.0
On Fri 30-01-26 11:12:31, Li Chen wrote:
> ext4 journal commit callbacks access jbd2_inode fields such as
> i_transaction and i_dirty_start/end without holding journal->j_list_lock.
>
> Use READ_ONCE() for these reads to correct the concurrency assumptions.
>
> Suggested-by: Jan Kara <jack@suse.com>
> Signed-off-by: Li Chen <me@linux.beauty>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> fs/ext4/inode.c | 6 ++++--
> fs/ext4/super.c | 13 ++++++++-----
> 2 files changed, 12 insertions(+), 7 deletions(-)
>
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index d99296d7315f..2d451388e080 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -3033,11 +3033,13 @@ static int ext4_writepages(struct address_space *mapping,
>
> int ext4_normal_submit_inode_data_buffers(struct jbd2_inode *jinode)
> {
> + loff_t dirty_start = READ_ONCE(jinode->i_dirty_start);
> + loff_t dirty_end = READ_ONCE(jinode->i_dirty_end);
> struct writeback_control wbc = {
> .sync_mode = WB_SYNC_ALL,
> .nr_to_write = LONG_MAX,
> - .range_start = jinode->i_dirty_start,
> - .range_end = jinode->i_dirty_end,
> + .range_start = dirty_start,
> + .range_end = dirty_end,
> };
> struct mpage_da_data mpd = {
> .inode = jinode->i_vfs_inode,
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 5cf6c2b54bbb..acb2bc016fd4 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -521,6 +521,7 @@ static bool ext4_journalled_writepage_needs_redirty(struct jbd2_inode *jinode,
> {
> struct buffer_head *bh, *head;
> struct journal_head *jh;
> + transaction_t *trans = READ_ONCE(jinode->i_transaction);
>
> bh = head = folio_buffers(folio);
> do {
> @@ -539,7 +540,7 @@ static bool ext4_journalled_writepage_needs_redirty(struct jbd2_inode *jinode,
> */
> jh = bh2jh(bh);
> if (buffer_dirty(bh) ||
> - (jh && (jh->b_transaction != jinode->i_transaction ||
> + (jh && (jh->b_transaction != trans ||
> jh->b_next_transaction)))
> return true;
> } while ((bh = bh->b_this_page) != head);
> @@ -550,12 +551,14 @@ static bool ext4_journalled_writepage_needs_redirty(struct jbd2_inode *jinode,
> static int ext4_journalled_submit_inode_data_buffers(struct jbd2_inode *jinode)
> {
> struct address_space *mapping = jinode->i_vfs_inode->i_mapping;
> + loff_t dirty_start = READ_ONCE(jinode->i_dirty_start);
> + loff_t dirty_end = READ_ONCE(jinode->i_dirty_end);
> struct writeback_control wbc = {
> - .sync_mode = WB_SYNC_ALL,
> + .sync_mode = WB_SYNC_ALL,
> .nr_to_write = LONG_MAX,
> - .range_start = jinode->i_dirty_start,
> - .range_end = jinode->i_dirty_end,
> - };
> + .range_start = dirty_start,
> + .range_end = dirty_end,
> + };
> struct folio *folio = NULL;
> int error;
>
> --
> 2.52.0
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
© 2016 - 2026 Red Hat, Inc.