diff --git a/convert/source-ext2.c b/convert/source-ext2.c
index acba5db7ee81..d06f90a98e9b 100644
--- a/convert/source-ext2.c
+++ b/convert/source-ext2.c
@@ -390,6 +390,7 @@ static int ext2_create_file_extents(struct btrfs_trans_handle *trans,
 			       ext2_filsys ext2_fs, ext2_ino_t ext2_ino,
 			       u32 convert_flags)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	int ret;
 	char *buffer = NULL;
 	errcode_t err;
@@ -397,8 +398,20 @@ static int ext2_create_file_extents(struct btrfs_trans_handle *trans,
 	u32 last_block;
 	u32 sectorsize = root->fs_info->sectorsize;
 	u64 inode_size = btrfs_stack_inode_size(btrfs_inode);
+	bool meet_inline_size_limit;
 	struct blk_iterate_data data;
 
+	if (S_ISLNK(btrfs_stack_inode_mode(btrfs_inode))) {
+		meet_inline_size_limit = inode_size <= btrfs_symlink_max_size(fs_info);
+		if (!meet_inline_size_limit) {
+			error("symlink too large for ext2 inode %u, has %llu max %u",
+			     ext2_ino, inode_size, btrfs_symlink_max_size(fs_info));
+			return -ENAMETOOLONG;
+		}
+	} else {
+		meet_inline_size_limit = inode_size <= btrfs_data_inline_max_size(fs_info);
+	}
+
 	init_blk_iterate_data(&data, trans, root, btrfs_inode, objectid,
 			convert_flags & CONVERT_FLAG_DATACSUM);
 
@@ -430,8 +443,7 @@ static int ext2_create_file_extents(struct btrfs_trans_handle *trans,
 	if (ret)
 		goto fail;
 	if ((convert_flags & CONVERT_FLAG_INLINE_DATA) && data.first_block == 0
-	    && data.num_blocks > 0 && inode_size < sectorsize
-	    && inode_size <= BTRFS_MAX_INLINE_DATA_SIZE(root->fs_info)) {
+	    && data.num_blocks > 0 && meet_inline_size_limit) {
 		u64 num_bytes = data.num_blocks * sectorsize;
 		u64 disk_bytenr = data.disk_block * sectorsize;
 		u64 nbytes;
@@ -476,21 +488,26 @@ static int ext2_create_symlink(struct btrfs_trans_handle *trans,
 	int ret;
 	char *pathname;
 	u64 inode_size = btrfs_stack_inode_size(btrfs_inode);
+
 	if (ext2fs_inode_data_blocks2(ext2_fs, ext2_inode)) {
-		btrfs_set_stack_inode_size(btrfs_inode, inode_size + 1);
+		if (inode_size > btrfs_symlink_max_size(trans->fs_info)) {
+			error("symlink too large for ext2 inode %u, has %llu max %u",
+				ext2_ino, inode_size,
+				btrfs_symlink_max_size(trans->fs_info));
+			return -ENAMETOOLONG;
+		}
 		ret = ext2_create_file_extents(trans, root, objectid,
 				btrfs_inode, ext2_fs, ext2_ino,
 				CONVERT_FLAG_DATACSUM |
 				CONVERT_FLAG_INLINE_DATA);
-		btrfs_set_stack_inode_size(btrfs_inode, inode_size);
 		return ret;
 	}
 
 	pathname = (char *)&(ext2_inode->i_block[0]);
 	BUG_ON(pathname[inode_size] != 0);
 	ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
-					 pathname, inode_size + 1);
-	btrfs_set_stack_inode_nbytes(btrfs_inode, inode_size + 1);
+					 pathname, inode_size);
+	btrfs_set_stack_inode_nbytes(btrfs_inode, inode_size);
 	return ret;
 }
 
diff --git a/convert/source-reiserfs.c b/convert/source-reiserfs.c
index 3edc72ed08a5..3475b15277dc 100644
--- a/convert/source-reiserfs.c
+++ b/convert/source-reiserfs.c
@@ -537,9 +537,15 @@ static int reiserfs_copy_symlink(struct btrfs_trans_handle *trans,
 	symlink = tp_item_body(&path);
 	len = get_ih_item_len(tp_item_head(&path));
 
+	if (len > btrfs_symlink_max_size(trans->fs_info)) {
+		error("symlink too large, has %u max %u",
+		      len, btrfs_symlink_max_size(trans->fs_info));
+		ret = -ENAMETOOLONG;
+		goto fail;
+	}
 	ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
-					 symlink, len + 1);
-	btrfs_set_stack_inode_nbytes(btrfs_inode, len + 1);
+					 symlink, len);
+	btrfs_set_stack_inode_nbytes(btrfs_inode, len);
 fail:
 	pathrelse(&path);
 	return ret;
diff --git a/kernel-shared/file-item.c b/kernel-shared/file-item.c
index d2da56e1f523..eb9024022d9f 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -26,6 +26,7 @@
 #include "kernel-shared/extent_io.h"
 #include "kernel-shared/uapi/btrfs.h"
 #include "common/internal.h"
+#include "common/messages.h"
 
 #define MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r->fs_info) - \
 			       sizeof(struct btrfs_item) * 2) / \
@@ -88,6 +89,7 @@ int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
 			       struct btrfs_root *root, u64 objectid,
 			       u64 offset, const char *buffer, size_t size)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_key key;
 	struct btrfs_path *path;
 	struct extent_buffer *leaf;
@@ -97,6 +99,10 @@ int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
 	int err = 0;
 	int ret;
 
+	if (size > max(btrfs_symlink_max_size(fs_info),
+		       btrfs_data_inline_max_size(fs_info)))
+		return -EUCLEAN;
+
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
diff --git a/kernel-shared/file-item.h b/kernel-shared/file-item.h
index 0df8f4dfea72..2c1e17c990dc 100644
--- a/kernel-shared/file-item.h
+++ b/kernel-shared/file-item.h
@@ -92,5 +92,23 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 logical,
 int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
 			       struct btrfs_root *root, u64 objectid,
 			       u64 offset, const char *buffer, size_t size);
+/*
+ * For symlink we allow up to PATH_MAX - 1 (PATH_MAX includes the terminating NUL,
+ * but fs doesn't store that terminating NUL).
+ *
+ * But for inlined data extents, the up limit is sectorsize - 1 (inclusive), or a
+ * regular extent should be created instead.
+ */
+static inline u32 btrfs_symlink_max_size(struct btrfs_fs_info *fs_info)
+{
+	return min_t(u32, BTRFS_MAX_INLINE_DATA_SIZE(fs_info),
+		     PATH_MAX - 1);
+}
+
+static inline u32 btrfs_data_inline_max_size(struct btrfs_fs_info *fs_info)
+{
+	return min_t(u32, BTRFS_MAX_INLINE_DATA_SIZE(fs_info),
+		     fs_info->sectorsize - 1);
+}
 
 #endif
