Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9924a92a authored by Theodore Ts'o's avatar Theodore Ts'o
Browse files

ext4: pass context information to jbd2__journal_start()



So we can better understand what bits of ext4 are responsible for
long-running jbd2 handles, use jbd2__journal_start() so we can pass
context information for logging purposes.

The recommended way for finding the longer-running handles is:

   T=/sys/kernel/debug/tracing
   EVENT=$T/events/jbd2/jbd2_handle_stats
   echo "interval > 5" > $EVENT/filter
   echo 1 > $EVENT/enable

   ./run-my-fs-benchmark

   cat $T/trace > /tmp/problem-handles

This will list handles that were active for longer than 20ms.  Having
longer-running handles is bad, because a commit started at the wrong
time could stall for those 20+ milliseconds, which could delay an
fsync() or an O_SYNC operation.  Here is an example line from the
trace file describing a handle which lived on for 311 jiffies, or over
1.2 seconds:

postmark-2917  [000] ....   196.435786: jbd2_handle_stats: dev 254,32 
   tid 570 type 2 line_no 2541 interval 311 sync 0 requested_blocks 1
   dirtied_blocks 0

Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 722887dd
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -324,7 +324,7 @@ ext4_acl_chmod(struct inode *inode)
	if (error)
		return error;
retry:
	handle = ext4_journal_start(inode,
	handle = ext4_journal_start(inode, EXT4_HT_XATTR,
			EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
	if (IS_ERR(handle)) {
		error = PTR_ERR(handle);
@@ -422,7 +422,8 @@ ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
		acl = NULL;

retry:
	handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
	handle = ext4_journal_start(inode, EXT4_HT_XATTR,
				    EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
	if (IS_ERR(handle)) {
		error = PTR_ERR(handle);
		goto release_and_out;
+3 −2
Original line number Diff line number Diff line
@@ -38,7 +38,8 @@ static void ext4_put_nojournal(handle_t *handle)
/*
 * Wrappers for jbd2_journal_start/end.
 */
handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
				  int type, int nblocks)
{
	journal_t *journal;

@@ -59,7 +60,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
		ext4_abort(sb, "Detected aborted journal");
		return ERR_PTR(-EROFS);
	}
	return jbd2_journal_start(journal, nblocks);
	return jbd2__journal_start(journal, nblocks, GFP_NOFS, type, line);
}

int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
+28 −3
Original line number Diff line number Diff line
@@ -110,6 +110,22 @@
#define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb))
#define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb))

/*
 * Ext4 handle operation types -- for logging purposes
 */
#define EXT4_HT_MISC             0
#define EXT4_HT_INODE            1
#define EXT4_HT_WRITE_PAGE       2
#define EXT4_HT_MAP_BLOCKS       3
#define EXT4_HT_DIR              4
#define EXT4_HT_TRUNCATE         5
#define EXT4_HT_QUOTA            6
#define EXT4_HT_RESIZE           7
#define EXT4_HT_MIGRATE          8
#define EXT4_HT_MOVE_EXTENTS     9
#define EXT4_HT_XATTR           10
#define EXT4_HT_MAX             11

/**
 *   struct ext4_journal_cb_entry - Base structure for callback information.
 *
@@ -234,7 +250,8 @@ int __ext4_handle_dirty_super(const char *where, unsigned int line,
#define ext4_handle_dirty_super(handle, sb) \
	__ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb))

handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
				  int type, int nblocks);
int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle);

#define EXT4_NOJOURNAL_MAX_REF_COUNT ((unsigned long) 4096)
@@ -268,9 +285,17 @@ static inline int ext4_handle_has_enough_credits(handle_t *handle, int needed)
	return 1;
}

static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks)
#define ext4_journal_start_sb(sb, type, nblocks)			\
	__ext4_journal_start_sb((sb), __LINE__, (type), (nblocks))

#define ext4_journal_start(inode, type, nblocks)			\
	__ext4_journal_start((inode), __LINE__, (type), (nblocks))

static inline handle_t *__ext4_journal_start(struct inode *inode,
					     unsigned int line, int type,
					     int nblocks)
{
	return ext4_journal_start_sb(inode->i_sb, nblocks);
	return __ext4_journal_start_sb(inode->i_sb, line, type, nblocks);
}

#define ext4_journal_stop(handle) \
+6 −5
Original line number Diff line number Diff line
@@ -2656,7 +2656,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
	ext_debug("truncate since %u to %u\n", start, end);

	/* probably first extent we're gonna free will be last in block */
	handle = ext4_journal_start(inode, depth + 1);
	handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, depth + 1);
	if (IS_ERR(handle))
		return PTR_ERR(handle);

@@ -4287,7 +4287,7 @@ void ext4_ext_truncate(struct inode *inode)
	 * probably first extent we're gonna free will be last in block
	 */
	err = ext4_writepage_trans_blocks(inode);
	handle = ext4_journal_start(inode, err);
	handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, err);
	if (IS_ERR(handle))
		return;

@@ -4454,7 +4454,8 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
	while (ret >= 0 && ret < max_blocks) {
		map.m_lblk = map.m_lblk + ret;
		map.m_len = max_blocks = max_blocks - ret;
		handle = ext4_journal_start(inode, credits);
		handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,
					    credits);
		if (IS_ERR(handle)) {
			ret = PTR_ERR(handle);
			break;
@@ -4532,7 +4533,7 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
	while (ret >= 0 && ret < max_blocks) {
		map.m_lblk += ret;
		map.m_len = (max_blocks -= ret);
		handle = ext4_journal_start(inode, credits);
		handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, credits);
		if (IS_ERR(handle)) {
			ret = PTR_ERR(handle);
			break;
@@ -4710,7 +4711,7 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length)
	inode_dio_wait(inode);

	credits = ext4_writepage_trans_blocks(inode);
	handle = ext4_journal_start(inode, credits);
	handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
	if (IS_ERR(handle)) {
		err = PTR_ERR(handle);
		goto out_dio;
+1 −1
Original line number Diff line number Diff line
@@ -240,7 +240,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
			handle_t *handle;
			int err;

			handle = ext4_journal_start_sb(sb, 1);
			handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1);
			if (IS_ERR(handle))
				return PTR_ERR(handle);
			err = ext4_journal_get_write_access(handle, sbi->s_sbh);
Loading