diff --git a/src/box/func.c b/src/box/func.c
index 04b04b6adc88adb0d38d38ba72a395b9a3c13e97..c44da9971af657eb7b66de2ae7711f0d03d27da3 100644
--- a/src/box/func.c
+++ b/src/box/func.c
@@ -40,6 +40,8 @@
 #include "port.h"
 #include "schema.h"
 #include "session.h"
+#include "libeio/eio.h"
+#include <fcntl.h>
 #include <dlfcn.h>
 
 /**
@@ -269,10 +271,45 @@ module_load(const char *package, const char *package_end)
 	char load_name[PATH_MAX + 1];
 	snprintf(load_name, sizeof(load_name), "%s/%.*s." TARANTOOL_LIBEXT,
 		 dir_name, package_len, package);
-	if (symlink(path, load_name) < 0) {
-		diag_set(SystemError, "failed to create dso link");
+
+	struct stat st;
+	if (stat(path, &st) < 0) {
+		diag_set(SystemError, "failed to stat() module %s", path);
+		goto error;
+	}
+
+	int source_fd = open(path, O_RDONLY);
+	if (source_fd < 0) {
+		diag_set(SystemError, "failed to open module %s file for" \
+			 " reading", path);
+		goto error;
+	}
+	int dest_fd = open(load_name, O_WRONLY|O_CREAT|O_TRUNC,
+			   st.st_mode & 0777);
+	if (dest_fd < 0) {
+		diag_set(SystemError, "failed to open file %s for writing ",
+			 load_name);
+		close(source_fd);
 		goto error;
 	}
+
+	off_t pos, left;
+	for (left = st.st_size, pos = 0; left > 0;) {
+		off_t ret = eio_sendfile_sync(dest_fd, source_fd, pos,
+					      st.st_size);
+		if (ret < 0) {
+			diag_set(SystemError, "failed to copy DSO %s to %s",
+				 path, load_name);
+			close(source_fd);
+			close(dest_fd);
+			goto error;
+		}
+		pos += ret;
+		left -= ret;
+	}
+	close(source_fd);
+	close(dest_fd);
+
 	module->handle = dlopen(load_name, RTLD_NOW | RTLD_LOCAL);
 	if (unlink(load_name) != 0)
 		say_warn("failed to unlink dso link %s", load_name);
diff --git a/test/box/func_reload.result b/test/box/func_reload.result
index b024cd143e0e2a57b742ad3294de3c280e48fea2..1313fdf1841310967b313b282943a0a929929884 100644
--- a/test/box/func_reload.result
+++ b/test/box/func_reload.result
@@ -46,7 +46,7 @@ box.schema.user.grant('guest', 'read,write', 'space', 'test')
 _ = fio.unlink(reload_path)
 ---
 ...
-fio.symlink(reload1_path, reload_path)
+fio.copyfile(reload1_path, reload_path)
 ---
 - true
 ...
@@ -68,10 +68,7 @@ box.space.test:delete{0}
 ---
 - [0]
 ...
-_ = fio.unlink(reload_path)
----
-...
-fio.symlink(reload2_path, reload_path)
+fio.copyfile(reload2_path, reload_path)
 ---
 - true
 ...
@@ -92,10 +89,7 @@ box.space.test:truncate()
 ---
 ...
 -- test case with hanging calls
-_ = fio.unlink(reload_path)
----
-...
-fio.symlink(reload1_path, reload_path)
+fio.copyfile(reload1_path, reload_path)
 ---
 - true
 ...
@@ -115,10 +109,7 @@ while box.space.test:count() < fibers do fiber.sleep(0.001) end
 box.schema.func.reload("reload")
 ---
 ...
-_ = fio.unlink(reload_path)
----
-...
-fio.symlink(reload2_path, reload_path)
+fio.copyfile(reload2_path, reload_path)
 ---
 - true
 ...
@@ -162,10 +153,7 @@ box.schema.func.drop("reload.foo")
 box.space.test:drop()
 ---
 ...
-_ = fio.unlink(reload_path)
----
-...
-fio.symlink(reload1_path, reload_path)
+fio.copyfile(reload1_path, reload_path)
 ---
 - true
 ...
@@ -196,10 +184,7 @@ s:delete({1})
 ---
 - [1, 2]
 ...
-_ = fio.unlink(reload_path)
----
-...
-fio.symlink(reload2_path, reload_path)
+fio.copyfile(reload2_path, reload_path)
 ---
 - true
 ...
@@ -236,10 +221,7 @@ c:call("reload.test_reload_fail")
 ---
 - [[2]]
 ...
-_ = fio.unlink(reload_path)
----
-...
-fio.symlink(reload1_path, reload_path)
+fio.copyfile(reload1_path, reload_path)
 ---
 - true
 ...
diff --git a/test/box/func_reload.test.lua b/test/box/func_reload.test.lua
index 8906898ecb304dadbdc54ad2771cb75054af1ffc..4c062fd72a1f332b7d789e0391b3684ddfb1ee11 100644
--- a/test/box/func_reload.test.lua
+++ b/test/box/func_reload.test.lua
@@ -17,7 +17,7 @@ _ = box.schema.space.create('test')
 _ = box.space.test:create_index('primary', {parts = {1, "integer"}})
 box.schema.user.grant('guest', 'read,write', 'space', 'test')
 _ = fio.unlink(reload_path)
-fio.symlink(reload1_path, reload_path)
+fio.copyfile(reload1_path, reload_path)
 
 --check not fail on non-load func
 box.schema.func.reload("reload")
@@ -26,8 +26,7 @@ box.schema.func.reload("reload")
 box.space.test:insert{0}
 c:call("reload.foo", {1})
 box.space.test:delete{0}
-_ = fio.unlink(reload_path)
-fio.symlink(reload2_path, reload_path)
+fio.copyfile(reload2_path, reload_path)
 
 box.schema.func.reload("reload")
 c:call("reload.foo")
@@ -35,8 +34,7 @@ box.space.test:select{}
 box.space.test:truncate()
 
 -- test case with hanging calls
-_ = fio.unlink(reload_path)
-fio.symlink(reload1_path, reload_path)
+fio.copyfile(reload1_path, reload_path)
 box.schema.func.reload("reload")
 
 fibers = 10
@@ -46,8 +44,7 @@ while box.space.test:count() < fibers do fiber.sleep(0.001) end
 -- double reload doesn't fail waiting functions
 box.schema.func.reload("reload")
 
-_ = fio.unlink(reload_path)
-fio.symlink(reload2_path, reload_path)
+fio.copyfile(reload2_path, reload_path)
 box.schema.func.reload("reload")
 c:call("reload.foo")
 
@@ -55,9 +52,8 @@ while box.space.test:count() < 2 * fibers + 1 do fiber.sleep(0.001) end
 box.space.test:select{}
 box.schema.func.drop("reload.foo")
 box.space.test:drop()
-_ = fio.unlink(reload_path)
 
-fio.symlink(reload1_path, reload_path)
+fio.copyfile(reload1_path, reload_path)
 box.schema.func.create('reload.test_reload', {language = "C"})
 box.schema.user.grant('guest', 'execute', 'function', 'reload.test_reload')
 s = box.schema.space.create('test_reload')
@@ -67,8 +63,7 @@ ch = fiber.channel(2)
 -- call first time to load function
 c:call("reload.test_reload")
 s:delete({1})
-_ = fio.unlink(reload_path)
-fio.symlink(reload2_path, reload_path)
+fio.copyfile(reload2_path, reload_path)
 _ = fiber.create(function() ch:put(c:call("reload.test_reload")) end)
 while s:get({1}) == nil do fiber.yield(0.0001) end
 box.schema.func.reload("reload")
@@ -80,8 +75,7 @@ s:drop()
 box.schema.func.create('reload.test_reload_fail', {language = "C"})
 box.schema.user.grant('guest', 'execute', 'function', 'reload.test_reload_fail')
 c:call("reload.test_reload_fail")
-_ = fio.unlink(reload_path)
-fio.symlink(reload1_path, reload_path)
+fio.copyfile(reload1_path, reload_path)
 c:call("reload.test_reload")
 c:call("reload.test_reload_fail")