Skip to content

Commit

Permalink
ext4: Support for checksumming from journal triggers
Browse files Browse the repository at this point in the history
JBD2 layer support triggers which are called when journaling layer moves
buffer to a certain state. We can use the frozen trigger, which gets
called when buffer data is frozen and about to be written out to the
journal, to compute block checksums for some buffer types (similarly as
does ocfs2). This avoids unnecessary repeated recomputation of the
checksum (at the cost of larger window where memory corruption won't be
caught by checksumming) and is even necessary when there are
unsynchronized updaters of the checksummed data.

So add superblock and journal trigger type arguments to
ext4_journal_get_write_access() and ext4_journal_get_create_access() so
that frozen triggers can be set accordingly. Also add inode argument to
ext4_walk_page_buffers() and all the callbacks used with that function
for the same purpose. This patch is mostly only a change of prototype of
the above mentioned functions and a few small helpers. Real checksumming
will come later.

Reviewed-by: Theodore Ts'o <[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]>
  • Loading branch information
jankara authored and tytso committed Aug 31, 2021
1 parent a54c461 commit 188c299
Show file tree
Hide file tree
Showing 16 changed files with 259 additions and 128 deletions.
26 changes: 24 additions & 2 deletions fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,24 @@ struct ext4_super_block {

#define EXT4_ENC_UTF8_12_1 1

/* Types of ext4 journal triggers */
enum ext4_journal_trigger_type {
EXT4_JTR_NONE /* This must be the last entry for indexing to work! */
};

#define EXT4_JOURNAL_TRIGGER_COUNT EXT4_JTR_NONE

struct ext4_journal_trigger {
struct jbd2_buffer_trigger_type tr_triggers;
struct super_block *sb;
};

static inline struct ext4_journal_trigger *EXT4_TRIGGER(
struct jbd2_buffer_trigger_type *trigger)
{
return container_of(trigger, struct ext4_journal_trigger, tr_triggers);
}

/*
* fourth extended-fs super-block data in memory
*/
Expand Down Expand Up @@ -1628,6 +1646,9 @@ struct ext4_sb_info {
struct mb_cache *s_ea_inode_cache;
spinlock_t s_es_lock ____cacheline_aligned_in_smp;

/* Journal triggers for checksum computation */
struct ext4_journal_trigger s_journal_triggers[EXT4_JOURNAL_TRIGGER_COUNT];

/* Ratelimit ext4 messages. */
struct ratelimit_state s_err_ratelimit_state;
struct ratelimit_state s_warning_ratelimit_state;
Expand Down Expand Up @@ -2923,13 +2944,14 @@ int ext4_get_block(struct inode *inode, sector_t iblock,
int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
struct buffer_head *bh, int create);
int ext4_walk_page_buffers(handle_t *handle,
struct inode *inode,
struct buffer_head *head,
unsigned from,
unsigned to,
int *partial,
int (*fn)(handle_t *handle,
int (*fn)(handle_t *handle, struct inode *inode,
struct buffer_head *bh));
int do_journal_get_write_access(handle_t *handle,
int do_journal_get_write_access(handle_t *handle, struct inode *inode,
struct buffer_head *bh);
#define FALL_BACK_TO_NONDELALLOC 1
#define CONVERT_INLINE_DATA 2
Expand Down
43 changes: 31 additions & 12 deletions fs/ext4/ext4_jbd2.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,11 @@ static void ext4_check_bdev_write_error(struct super_block *sb)
}

int __ext4_journal_get_write_access(const char *where, unsigned int line,
handle_t *handle, struct buffer_head *bh)
handle_t *handle, struct super_block *sb,
struct buffer_head *bh,
enum ext4_journal_trigger_type trigger_type)
{
int err = 0;
int err;

might_sleep();

Expand All @@ -229,11 +231,18 @@ int __ext4_journal_get_write_access(const char *where, unsigned int line,

if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_write_access(handle, bh);
if (err)
if (err) {
ext4_journal_abort_handle(where, line, __func__, bh,
handle, err);
return err;
}
}
return err;
if (trigger_type == EXT4_JTR_NONE || !ext4_has_metadata_csum(sb))
return 0;
BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT);
jbd2_journal_set_triggers(bh,
&EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers);
return 0;
}

/*
Expand Down Expand Up @@ -301,17 +310,27 @@ int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
}

int __ext4_journal_get_create_access(const char *where, unsigned int line,
handle_t *handle, struct buffer_head *bh)
handle_t *handle, struct super_block *sb,
struct buffer_head *bh,
enum ext4_journal_trigger_type trigger_type)
{
int err = 0;
int err;

if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_create_access(handle, bh);
if (err)
ext4_journal_abort_handle(where, line, __func__,
bh, handle, err);
if (!ext4_handle_valid(handle))
return 0;

err = jbd2_journal_get_create_access(handle, bh);
if (err) {
ext4_journal_abort_handle(where, line, __func__, bh, handle,
err);
return err;
}
return err;
if (trigger_type == EXT4_JTR_NONE || !ext4_has_metadata_csum(sb))
return 0;
BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT);
jbd2_journal_set_triggers(bh,
&EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers);
return 0;
}

int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
Expand Down
18 changes: 12 additions & 6 deletions fs/ext4/ext4_jbd2.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,26 +231,32 @@ int ext4_expand_extra_isize(struct inode *inode,
* Wrapper functions with which ext4 calls into JBD.
*/
int __ext4_journal_get_write_access(const char *where, unsigned int line,
handle_t *handle, struct buffer_head *bh);
handle_t *handle, struct super_block *sb,
struct buffer_head *bh,
enum ext4_journal_trigger_type trigger_type);

int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
int is_metadata, struct inode *inode,
struct buffer_head *bh, ext4_fsblk_t blocknr);

int __ext4_journal_get_create_access(const char *where, unsigned int line,
handle_t *handle, struct buffer_head *bh);
handle_t *handle, struct super_block *sb,
struct buffer_head *bh,
enum ext4_journal_trigger_type trigger_type);

int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
handle_t *handle, struct inode *inode,
struct buffer_head *bh);

#define ext4_journal_get_write_access(handle, bh) \
__ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh))
#define ext4_journal_get_write_access(handle, sb, bh, trigger_type) \
__ext4_journal_get_write_access(__func__, __LINE__, (handle), (sb), \
(bh), (trigger_type))
#define ext4_forget(handle, is_metadata, inode, bh, block_nr) \
__ext4_forget(__func__, __LINE__, (handle), (is_metadata), (inode), \
(bh), (block_nr))
#define ext4_journal_get_create_access(handle, bh) \
__ext4_journal_get_create_access(__func__, __LINE__, (handle), (bh))
#define ext4_journal_get_create_access(handle, sb, bh, trigger_type) \
__ext4_journal_get_create_access(__func__, __LINE__, (handle), (sb), \
(bh), (trigger_type))
#define ext4_handle_dirty_metadata(handle, inode, bh) \
__ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \
(bh))
Expand Down
12 changes: 8 additions & 4 deletions fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
if (path->p_bh) {
/* path points to block */
BUFFER_TRACE(path->p_bh, "get_write_access");
return ext4_journal_get_write_access(handle, path->p_bh);
return ext4_journal_get_write_access(handle, inode->i_sb,
path->p_bh, EXT4_JTR_NONE);
}
/* path points to leaf/index in inode body */
/* we use in-core data, no need to protect them */
Expand Down Expand Up @@ -1082,7 +1083,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
}
lock_buffer(bh);

err = ext4_journal_get_create_access(handle, bh);
err = ext4_journal_get_create_access(handle, inode->i_sb, bh,
EXT4_JTR_NONE);
if (err)
goto cleanup;

Expand Down Expand Up @@ -1160,7 +1162,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
}
lock_buffer(bh);

err = ext4_journal_get_create_access(handle, bh);
err = ext4_journal_get_create_access(handle, inode->i_sb, bh,
EXT4_JTR_NONE);
if (err)
goto cleanup;

Expand Down Expand Up @@ -1286,7 +1289,8 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
return -ENOMEM;
lock_buffer(bh);

err = ext4_journal_get_create_access(handle, bh);
err = ext4_journal_get_create_access(handle, inode->i_sb, bh,
EXT4_JTR_NONE);
if (err) {
unlock_buffer(bh);
goto out;
Expand Down
3 changes: 2 additions & 1 deletion fs/ext4/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,8 @@ static int ext4_sample_last_mounted(struct super_block *sb,
if (IS_ERR(handle))
goto out;
BUFFER_TRACE(sbi->s_sbh, "get_write_access");
err = ext4_journal_get_write_access(handle, sbi->s_sbh);
err = ext4_journal_get_write_access(handle, sb, sbi->s_sbh,
EXT4_JTR_NONE);
if (err)
goto out_journal;
lock_buffer(sbi->s_sbh);
Expand Down
19 changes: 12 additions & 7 deletions fs/ext4/ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,15 +300,17 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
}

BUFFER_TRACE(bitmap_bh, "get_write_access");
fatal = ext4_journal_get_write_access(handle, bitmap_bh);
fatal = ext4_journal_get_write_access(handle, sb, bitmap_bh,
EXT4_JTR_NONE);
if (fatal)
goto error_return;

fatal = -ESRCH;
gdp = ext4_get_group_desc(sb, block_group, &bh2);
if (gdp) {
BUFFER_TRACE(bh2, "get_write_access");
fatal = ext4_journal_get_write_access(handle, bh2);
fatal = ext4_journal_get_write_access(handle, sb, bh2,
EXT4_JTR_NONE);
}
ext4_lock_group(sb, block_group);
cleared = ext4_test_and_clear_bit(bit, bitmap_bh->b_data);
Expand Down Expand Up @@ -1085,7 +1087,8 @@ struct inode *__ext4_new_inode(struct user_namespace *mnt_userns,
}
}
BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, inode_bitmap_bh);
err = ext4_journal_get_write_access(handle, sb, inode_bitmap_bh,
EXT4_JTR_NONE);
if (err) {
ext4_std_error(sb, err);
goto out;
Expand Down Expand Up @@ -1127,7 +1130,8 @@ struct inode *__ext4_new_inode(struct user_namespace *mnt_userns,
}

BUFFER_TRACE(group_desc_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, group_desc_bh);
err = ext4_journal_get_write_access(handle, sb, group_desc_bh,
EXT4_JTR_NONE);
if (err) {
ext4_std_error(sb, err);
goto out;
Expand All @@ -1144,7 +1148,8 @@ struct inode *__ext4_new_inode(struct user_namespace *mnt_userns,
goto out;
}
BUFFER_TRACE(block_bitmap_bh, "get block bitmap access");
err = ext4_journal_get_write_access(handle, block_bitmap_bh);
err = ext4_journal_get_write_access(handle, sb, block_bitmap_bh,
EXT4_JTR_NONE);
if (err) {
brelse(block_bitmap_bh);
ext4_std_error(sb, err);
Expand Down Expand Up @@ -1583,8 +1588,8 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
num = sbi->s_itb_per_group - used_blks;

BUFFER_TRACE(group_desc_bh, "get_write_access");
ret = ext4_journal_get_write_access(handle,
group_desc_bh);
ret = ext4_journal_get_write_access(handle, sb, group_desc_bh,
EXT4_JTR_NONE);
if (ret)
goto err_out;

Expand Down
15 changes: 10 additions & 5 deletions fs/ext4/indirect.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ static int ext4_alloc_branch(handle_t *handle,
}
lock_buffer(bh);
BUFFER_TRACE(bh, "call get_create_access");
err = ext4_journal_get_create_access(handle, bh);
err = ext4_journal_get_create_access(handle, ar->inode->i_sb,
bh, EXT4_JTR_NONE);
if (err) {
unlock_buffer(bh);
goto failed;
Expand Down Expand Up @@ -429,7 +430,8 @@ static int ext4_splice_branch(handle_t *handle,
*/
if (where->bh) {
BUFFER_TRACE(where->bh, "get_write_access");
err = ext4_journal_get_write_access(handle, where->bh);
err = ext4_journal_get_write_access(handle, ar->inode->i_sb,
where->bh, EXT4_JTR_NONE);
if (err)
goto err_out;
}
Expand Down Expand Up @@ -728,7 +730,8 @@ static int ext4_ind_truncate_ensure_credits(handle_t *handle,
return ret;
if (bh) {
BUFFER_TRACE(bh, "retaking write access");
ret = ext4_journal_get_write_access(handle, bh);
ret = ext4_journal_get_write_access(handle, inode->i_sb, bh,
EXT4_JTR_NONE);
if (unlikely(ret))
return ret;
}
Expand Down Expand Up @@ -916,7 +919,8 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,

if (this_bh) { /* For indirect block */
BUFFER_TRACE(this_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, this_bh);
err = ext4_journal_get_write_access(handle, inode->i_sb,
this_bh, EXT4_JTR_NONE);
/* Important: if we can't update the indirect pointers
* to the blocks, we can't free them. */
if (err)
Expand Down Expand Up @@ -1079,7 +1083,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
*/
BUFFER_TRACE(parent_bh, "get_write_access");
if (!ext4_journal_get_write_access(handle,
parent_bh)){
inode->i_sb, parent_bh,
EXT4_JTR_NONE)) {
*p = 0;
BUFFER_TRACE(parent_bh,
"call ext4_handle_dirty_metadata");
Expand Down
Loading

0 comments on commit 188c299

Please sign in to comment.