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

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

ext4: handle transient ENOSPC properly for DAX



ext4_dax_get_blocks() was accidentally omitted fixing get blocks
handlers to properly handle transient ENOSPC errors. Fix it now to use
ext4_get_blocks_trans() helper which takes care of these errors.

Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent aef39ab1
Loading
Loading
Loading
Loading
+20 −55
Original line number Diff line number Diff line
@@ -3232,72 +3232,37 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock,
			    struct buffer_head *bh_result, int create)
{
	int ret, err;
	int credits;
	struct ext4_map_blocks map;
	handle_t *handle = NULL;
	int flags = 0;
	int ret;

	ext4_debug("ext4_dax_mmap_get_block: inode %lu, create flag %d\n",
		   inode->i_ino, create);
	map.m_lblk = iblock;
	map.m_len = bh_result->b_size >> inode->i_blkbits;
	credits = ext4_chunk_trans_blocks(inode, map.m_len);
	if (create) {
		flags |= EXT4_GET_BLOCKS_PRE_IO | EXT4_GET_BLOCKS_CREATE_ZERO;
		handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, credits);
		if (IS_ERR(handle)) {
			ret = PTR_ERR(handle);
			return ret;
		}
	}
	if (!create)
		return _ext4_get_block(inode, iblock, bh_result, 0);

	ret = ext4_map_blocks(handle, inode, &map, flags);
	if (create) {
		err = ext4_journal_stop(handle);
		if (ret >= 0 && err < 0)
			ret = err;
	}
	if (ret <= 0)
		goto out;
	if (map.m_flags & EXT4_MAP_UNWRITTEN) {
		int err2;
	ret = ext4_get_block_trans(inode, iblock, bh_result,
				   EXT4_GET_BLOCKS_PRE_IO |
				   EXT4_GET_BLOCKS_CREATE_ZERO);
	if (ret < 0)
		return ret;

	if (buffer_unwritten(bh_result)) {
		/*
		 * We are protected by i_mmap_sem so we know block cannot go
		 * away from under us even though we dropped i_data_sem.
		 * Convert extent to written and write zeros there.
		 *
		 * Note: We may get here even when create == 0.
		 */
		handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, credits);
		if (IS_ERR(handle)) {
			ret = PTR_ERR(handle);
			goto out;
		}

		err = ext4_map_blocks(handle, inode, &map,
		      EXT4_GET_BLOCKS_CONVERT | EXT4_GET_BLOCKS_CREATE_ZERO);
		if (err < 0)
			ret = err;
		err2 = ext4_journal_stop(handle);
		if (err2 < 0 && ret > 0)
			ret = err2;
		ret = ext4_get_block_trans(inode, iblock, bh_result,
					   EXT4_GET_BLOCKS_CONVERT |
					   EXT4_GET_BLOCKS_CREATE_ZERO);
		if (ret < 0)
			return ret;
	}
out:
	WARN_ON_ONCE(ret == 0 && create);
	if (ret > 0) {
		map_bh(bh_result, inode->i_sb, map.m_pblk);
	/*
	 * At least for now we have to clear BH_New so that DAX code
	 * doesn't attempt to zero blocks again in a racy way.
	 */
		map.m_flags &= ~EXT4_MAP_NEW;
		ext4_update_bh_state(bh_result, map.m_flags);
		bh_result->b_size = map.m_len << inode->i_blkbits;
		ret = 0;
	}
	return ret;
	clear_buffer_new(bh_result);
	return 0;
}
#endif