diff --git a/convert/source-ext2.c b/convert/source-ext2.c
index 477c39d9d658..9de591e34c18 100644
--- a/convert/source-ext2.c
+++ b/convert/source-ext2.c
@@ -208,6 +208,54 @@ static u8 ext2_filetype_conversion_table[EXT2_FT_MAX] = {
 	[EXT2_FT_SYMLINK]	= BTRFS_FT_SYMLINK,
 };
 
+int ext2_find_unwritten(struct blk_iterate_data *data, int index,
+			bool *has_unwritten)
+{
+	ext2_extent_handle_t handle;
+	struct ext2fs_extent extent;
+	struct ext2_source_fs  *src = (struct ext2_source_fs *) data->source_fs;
+
+	if (ext2fs_extent_open2(src->ext2_fs, src->ext2_ino,
+				src->ext2_inode, &handle)) {
+		error("ext2fs_extent_open2 failed, inode %d", src->ext2_ino);
+		return -EINVAL;
+	}
+
+	if (ext2fs_extent_goto2(handle, 0, index)) {
+		error("ext2fs_extent_goto2 failed, inode %d num_blocks %llu",
+		       src->ext2_ino, data->num_blocks);
+		ext2fs_extent_free(handle);
+		return -EINVAL;
+	}
+
+	memset(&extent, 0, sizeof(struct ext2fs_extent));
+	if (ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent)) {
+		error("ext2fs_extent_get EXT2_EXTENT_CURRENT failed inode %d",
+		       src->ext2_ino);
+		ext2fs_extent_free(handle);
+		return -EINVAL;
+	}
+
+	if (extent.e_pblk != data->disk_block) {
+	error("inode %d index %d found wrong extent e_pblk %llu wanted disk_block %llu",
+		       src->ext2_ino, index, extent.e_pblk, data->disk_block);
+		ext2fs_extent_free(handle);
+		return -EINVAL;
+	}
+
+	if (extent.e_len != data->num_blocks) {
+	error("inode %d index %d: identified unsupported merged block length %u wanted %llu",
+			src->ext2_ino, index, extent.e_len, data->num_blocks);
+		ext2fs_extent_free(handle);
+		return -EINVAL;
+	}
+
+	if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
+		*has_unwritten = true;
+
+	return 0;
+}
+
 static int ext2_dir_iterate_proc(ext2_ino_t dir, int entry,
 			    struct ext2_dir_entry *dirent,
 			    int offset, int blocksize,
diff --git a/convert/source-ext2.h b/convert/source-ext2.h
index 026a7cad8ac8..19014d3c25e6 100644
--- a/convert/source-ext2.h
+++ b/convert/source-ext2.h
@@ -82,6 +82,9 @@ struct ext2_source_fs {
 	ext2_ino_t ext2_ino;
 };
 
+int ext2_find_unwritten(struct blk_iterate_data *data, int index,
+			bool *has_unwritten);
+
 #define EXT2_ACL_VERSION	0x0001
 
 #endif	/* BTRFSCONVERT_EXT2 */
diff --git a/convert/source-fs.c b/convert/source-fs.c
index df5ce66caf7f..88a6ceaf41f6 100644
--- a/convert/source-fs.c
+++ b/convert/source-fs.c
@@ -31,6 +31,7 @@
 #include "common/extent-tree-utils.h"
 #include "convert/common.h"
 #include "convert/source-fs.h"
+#include "convert/source-ext2.h"
 
 const struct simple_range btrfs_reserved_ranges[3] = {
 	{ 0,			     SZ_1M },
@@ -239,6 +240,15 @@ fail:
 	return ret;
 }
 
+int find_prealloc(struct blk_iterate_data *data, int index,
+		  bool *has_prealloc)
+{
+	if (data->source_fs)
+		return ext2_find_unwritten(data, index, has_prealloc);
+
+	return -EINVAL;
+}
+
 /*
  * Record a file extent in original filesystem into btrfs one.
  * The special point is, old disk_block can point to a reserved range.
@@ -257,6 +267,7 @@ int record_file_blocks(struct blk_iterate_data *data,
 	u64 old_disk_bytenr = disk_block * sectorsize;
 	u64 num_bytes = num_blocks * sectorsize;
 	u64 cur_off = old_disk_bytenr;
+	int index = data->first_block;
 
 	/* Hole, pass it to record_file_extent directly */
 	if (old_disk_bytenr == 0)
@@ -276,6 +287,16 @@ int record_file_blocks(struct blk_iterate_data *data,
 		u64 extent_num_bytes;
 		u64 real_disk_bytenr;
 		u64 cur_len;
+		u64 flags = BTRFS_FILE_EXTENT_REG;
+		bool has_prealloc = false;
+
+		if (find_prealloc(data, index, &has_prealloc)) {
+			data->errcode = -1;
+			return -EINVAL;
+		}
+
+		if (has_prealloc)
+			flags = BTRFS_FILE_EXTENT_PREALLOC;
 
 		key.objectid = data->convert_ino;
 		key.type = BTRFS_EXTENT_DATA_KEY;
@@ -316,12 +337,12 @@ int record_file_blocks(struct blk_iterate_data *data,
 			      old_disk_bytenr + num_bytes) - cur_off;
 		ret = btrfs_record_file_extent(data->trans, data->root,
 					data->objectid, data->inode, file_pos,
-					real_disk_bytenr, cur_len,
-					BTRFS_FILE_EXTENT_REG);
+					real_disk_bytenr, cur_len, flags);
 		if (ret < 0)
 			break;
 		cur_off += cur_len;
 		file_pos += cur_len;
+		index++;
 
 		/*
 		 * No need to care about csum
diff --git a/convert/source-fs.h b/convert/source-fs.h
index 25916c65681b..db7ead422585 100644
--- a/convert/source-fs.h
+++ b/convert/source-fs.h
@@ -153,5 +153,6 @@ int read_disk_extent(struct btrfs_root *root, u64 bytenr,
 		            u32 num_bytes, char *buffer);
 int record_file_blocks(struct blk_iterate_data *data,
 			      u64 file_block, u64 disk_block, u64 num_blocks);
+int find_prealloc(struct blk_iterate_data *data, int index, bool *has_prealloc);
 
 #endif
