Commit 188c299e authored by Jan Kara's avatar Jan Kara Committed by Theodore Ts'o
Browse files

ext4: Support for checksumming from journal triggers



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: default avatarTheodore Ts'o <tytso@mit.edu>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20210816095713.16537-1-jack@suse.cz


Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent a54c4613
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -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
 */
@@ -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;
@@ -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
+31 −12
Original line number Diff line number Diff line
@@ -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();

@@ -229,12 +231,19 @@ 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;
		}
	}
	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;
}

/*
 * The ext4 forget function must perform a revoke if we are freeing data
@@ -301,18 +310,28 @@ 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))
		return 0;

	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 (err) {
		ext4_journal_abort_handle(where, line, __func__, bh, handle,
					  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,
				 handle_t *handle, struct inode *inode,
+12 −6
Original line number Diff line number Diff line
@@ -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))
+8 −4
Original line number Diff line number Diff line
@@ -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 */
@@ -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;

@@ -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;

@@ -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;
+2 −1
Original line number Diff line number Diff line
@@ -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);
Loading