ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
			struct ext4_map_blocks *map,
			struct ext4_ext_path **ppath, int flags,
			unsigned int allocated, ext4_fsblk_t newblock)
{
	struct ext4_ext_path __maybe_unused *path = *ppath;
	int ret = 0;
	int err = 0;

	ext_debug(inode, "logical block %llu, max_blocks %u, flags 0x%x, allocated %u\n",
		  (unsigned long long)map->m_lblk, map->m_len, flags,
		  allocated);
	ext4_ext_show_leaf(inode, path);

	/*
	 * When writing into unwritten space, we should not fail to
	 * allocate metadata blocks for the new extent block if needed.
	 */
	flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL;

	trace_ext4_ext_handle_unwritten_extents(inode, map, flags,
						    allocated, newblock);

	/* get_block() before submitting IO, split the extent */
	if (flags & EXT4_GET_BLOCKS_PRE_IO) {
		ret = ext4_split_convert_extents(handle, inode, map, ppath,
					 flags | EXT4_GET_BLOCKS_CONVERT);
		if (ret < 0) {
			err = ret;
			goto out2;
		}
		/*
		 * shouldn't get a 0 return when splitting an extent unless
		 * m_len is 0 (bug) or extent has been corrupted
		 */
		if (unlikely(ret == 0)) {
			EXT4_ERROR_INODE(inode,
					 "unexpected ret == 0, m_len = %u",
					 map->m_len);
			err = -EFSCORRUPTED;
			goto out2;
		}
		map->m_flags |= EXT4_MAP_UNWRITTEN;
		goto out;
	}
	/* IO end_io complete, convert the filled extent to written */
	if (flags & EXT4_GET_BLOCKS_CONVERT) {
		err = ext4_convert_unwritten_extents_endio(handle, inode, map,
							   ppath);
		if (err < 0)
			goto out2;
		ext4_update_inode_fsync_trans(handle, inode, 1);
		goto map_out;
	}
	/* buffered IO cases */
	/*
	 * repeat fallocate creation request
	 * we already have an unwritten extent
	 */
	if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT) {
		map->m_flags |= EXT4_MAP_UNWRITTEN;
		goto map_out;
	}

	/* buffered READ or buffered write_begin() lookup */
	if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
		/*
		 * We have blocks reserved already.  We
		 * return allocated blocks so that delalloc
		 * won't do block reservation for us.  But
		 * the buffer head will be unmapped so that
		 * a read from the block returns 0s.
		 */
		map->m_flags |= EXT4_MAP_UNWRITTEN;
		goto out1;
	}

	/*
	 * Default case when (flags & EXT4_GET_BLOCKS_CREATE) == 1.
	 * For buffered writes, at writepage time, etc.  Convert a
	 * discovered unwritten extent to written.
	 */
	ret = ext4_ext_convert_to_initialized(handle, inode, map, ppath, flags);
	if (ret < 0) {
		err = ret;
		goto out2;
	}
	ext4_update_inode_fsync_trans(handle, inode, 1);
	/*
	 * shouldn't get a 0 return when converting an unwritten extent
	 * unless m_len is 0 (bug) or extent has been corrupted
	 */
	if (unlikely(ret == 0)) {
		EXT4_ERROR_INODE(inode, "unexpected ret == 0, m_len = %u",
				 map->m_len);
		err = -EFSCORRUPTED;
		goto out2;
	}

out:
	allocated = ret;
	map->m_flags |= EXT4_MAP_NEW;
map_out:
	map->m_flags |= EXT4_MAP_MAPPED;
out1:
	map->m_pblk = newblock;
	if (allocated > map->m_len)
		allocated = map->m_len;
	map->m_len = allocated;
	ext4_ext_show_leaf(inode, path);
out2:
	return err ? err : allocated;
}
ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
			struct ext4_map_blocks *map,
			struct ext4_ext_path **ppath, int flags,
			unsigned int allocated, ext4_fsblk_t newblock)
{
	struct ext4_ext_path __maybe_unused *path = *ppath;
	int ret = 0;
	int err = 0;

	ext_debug(inode, "logical block %llu, max_blocks %u, flags 0x%x, allocated %u\n",
		  (unsigned long long)map->m_lblk, map->m_len, flags,
		  allocated);
	ext4_ext_show_leaf(inode, path);

	 
	flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL;

	trace_ext4_ext_handle_unwritten_extents(inode, map, flags,
						    allocated, newblock);

	 
	if (flags & EXT4_GET_BLOCKS_PRE_IO) {
		ret = ext4_split_convert_extents(handle, inode, map, ppath,
					 flags | EXT4_GET_BLOCKS_CONVERT);
		if (ret < 0) {
			err = ret;
			goto out2;
		}
		 
		if (unlikely(ret == 0)) {
			EXT4_ERROR_INODE(inode,
					 "unexpected ret == 0, m_len = %u",
					 map->m_len);
			err = -EFSCORRUPTED;
			goto out2;
		}
		map->m_flags |= EXT4_MAP_UNWRITTEN;
		goto out;
	}
	 
	if (flags & EXT4_GET_BLOCKS_CONVERT) {
		err = ext4_convert_unwritten_extents_endio(handle, inode, map,
							   ppath);
		if (err < 0)
			goto out2;
		ext4_update_inode_fsync_trans(handle, inode, 1);
		goto map_out;
	}
	 
	 
	if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT) {
		map->m_flags |= EXT4_MAP_UNWRITTEN;
		goto map_out;
	}

	 
	if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
		 
		map->m_flags |= EXT4_MAP_UNWRITTEN;
		goto out1;
	}

	 
	ret = ext4_ext_convert_to_initialized(handle, inode, map, ppath, flags);
	if (ret < 0) {
		err = ret;
		goto out2;
	}
	ext4_update_inode_fsync_trans(handle, inode, 1);
	 
	if (unlikely(ret == 0)) {
		EXT4_ERROR_INODE(inode, "unexpected ret == 0, m_len = %u",
				 map->m_len);
		err = -EFSCORRUPTED;
		goto out2;
	}

out:
	allocated = ret;
	map->m_flags |= EXT4_MAP_NEW;
map_out:
	map->m_flags |= EXT4_MAP_MAPPED;
out1:
	map->m_pblk = newblock;
	if (allocated > map->m_len)
		allocated = map->m_len;
	map->m_len = allocated;
	ext4_ext_show_leaf(inode, path);
out2:
	return err ? err : allocated;
}