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

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

ext4: move trans handling and completion deferal out of _ext4_get_block



There is no need to handle starting of a transaction and deferal of DIO
completion in _ext4_get_block() function. We can move this out to get
block functions for direct IO that need it. That way we can add stricter
checks verifying things work as we expect.

Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 705965bd
Loading
Loading
Loading
Loading
+59 −32
Original line number Diff line number Diff line
@@ -714,16 +714,11 @@ static void ext4_update_bh_state(struct buffer_head *bh, unsigned long flags)
		 cmpxchg(&bh->b_state, old_state, new_state) != old_state));
}

/* Maximum number of blocks we map for direct IO at once. */
#define DIO_MAX_BLOCKS 4096

static int _ext4_get_block(struct inode *inode, sector_t iblock,
			   struct buffer_head *bh, int flags)
{
	handle_t *handle = ext4_journal_current_handle();
	struct ext4_map_blocks map;
	int ret = 0, started = 0;
	int dio_credits;
	int ret = 0;

	if (ext4_has_inline_data(inode))
		return -ERANGE;
@@ -731,33 +726,14 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock,
	map.m_lblk = iblock;
	map.m_len = bh->b_size >> inode->i_blkbits;

	if (flags && !handle) {
		/* Direct IO write... */
		if (map.m_len > DIO_MAX_BLOCKS)
			map.m_len = DIO_MAX_BLOCKS;
		dio_credits = ext4_chunk_trans_blocks(inode, map.m_len);
		handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,
					    dio_credits);
		if (IS_ERR(handle)) {
			ret = PTR_ERR(handle);
			return ret;
		}
		started = 1;
	}

	ret = ext4_map_blocks(handle, inode, &map, flags);
	ret = ext4_map_blocks(ext4_journal_current_handle(), inode, &map,
			      flags);
	if (ret > 0) {
		ext4_io_end_t *io_end = ext4_inode_aio(inode);

		map_bh(bh, inode->i_sb, map.m_pblk);
		ext4_update_bh_state(bh, map.m_flags);
		if (io_end && io_end->flag & EXT4_IO_END_UNWRITTEN)
			set_buffer_defer_completion(bh);
		bh->b_size = inode->i_sb->s_blocksize * map.m_len;
		ret = 0;
	}
	if (started)
		ext4_journal_stop(handle);
	return ret;
}

@@ -782,12 +758,42 @@ int ext4_get_block_unwritten(struct inode *inode, sector_t iblock,
			       EXT4_GET_BLOCKS_IO_CREATE_EXT);
}

/* Maximum number of blocks we map for direct IO at once. */
#define DIO_MAX_BLOCKS 4096

static handle_t *start_dio_trans(struct inode *inode,
				 struct buffer_head *bh_result)
{
	int dio_credits;

	/* Trim mapping request to maximum we can map at once for DIO */
	if (bh_result->b_size >> inode->i_blkbits > DIO_MAX_BLOCKS)
		bh_result->b_size = DIO_MAX_BLOCKS << inode->i_blkbits;
	dio_credits = ext4_chunk_trans_blocks(inode,
				      bh_result->b_size >> inode->i_blkbits);
	return ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, dio_credits);
}

/* Get block function for DIO reads and writes to inodes without extents */
int ext4_dio_get_block(struct inode *inode, sector_t iblock,
		       struct buffer_head *bh, int create)
{
	return _ext4_get_block(inode, iblock, bh,
	handle_t *handle;
	int ret;

	/* We don't expect handle for direct IO */
	WARN_ON_ONCE(ext4_journal_current_handle());

	if (create) {
		handle = start_dio_trans(inode, bh);
		if (IS_ERR(handle))
			return PTR_ERR(handle);
	}
	ret = _ext4_get_block(inode, iblock, bh,
			      create ? EXT4_GET_BLOCKS_CREATE : 0);
	if (create)
		ext4_journal_stop(handle);
	return ret;
}

/*
@@ -798,10 +804,28 @@ int ext4_dio_get_block(struct inode *inode, sector_t iblock,
static int ext4_dio_get_block_unwritten(struct inode *inode, sector_t iblock,
			struct buffer_head *bh_result, int create)
{
	handle_t *handle;
	int ret;

	ext4_debug("ext4_dio_get_block_unwritten: inode %lu, create flag %d\n",
		   inode->i_ino, create);
	return _ext4_get_block(inode, iblock, bh_result,
	/* We don't expect handle for direct IO */
	WARN_ON_ONCE(ext4_journal_current_handle());

	handle = start_dio_trans(inode, bh_result);
	if (IS_ERR(handle))
		return PTR_ERR(handle);
	ret = _ext4_get_block(inode, iblock, bh_result,
			      EXT4_GET_BLOCKS_IO_CREATE_EXT);
	ext4_journal_stop(handle);
	if (!ret && buffer_unwritten(bh_result)) {
		ext4_io_end_t *io_end = ext4_inode_aio(inode);

		set_buffer_defer_completion(bh_result);
		WARN_ON_ONCE(io_end && !(io_end->flag & EXT4_IO_END_UNWRITTEN));
	}

	return ret;
}

static int ext4_dio_get_block_overwrite(struct inode *inode, sector_t iblock,
@@ -811,12 +835,15 @@ static int ext4_dio_get_block_overwrite(struct inode *inode, sector_t iblock,

	ext4_debug("ext4_dio_get_block_overwrite: inode %lu, create flag %d\n",
		   inode->i_ino, create);
	/* We don't expect handle for direct IO */
	WARN_ON_ONCE(ext4_journal_current_handle());

	ret = _ext4_get_block(inode, iblock, bh_result, 0);
	/*
	 * Blocks should have been preallocated! ext4_file_write_iter() checks
	 * that.
	 */
	WARN_ON_ONCE(!buffer_mapped(bh_result));
	WARN_ON_ONCE(!buffer_mapped(bh_result) || buffer_unwritten(bh_result));

	return ret;
}