From e5ebe1c840eacd84816a02a2dd3f35ab892ddf58 Mon Sep 17 00:00:00 2001
From: zhangxiaoyu <zhangxiaoyu58@huawei.com>
Date: Thu, 31 Aug 2023 13:10:12 +0000
Subject: [PATCH 131/145] !2164 add bind mount file lock * add bind mount file
 lock

---
 src/cmd/isula/stream/cp.c                     |  66 ++++++-
 src/cmd/isulad/main.c                         |  51 ++++++
 src/common/constants.h                        |   4 +
 .../executor/container_cb/execution_stream.c  |  23 ++-
 src/daemon/modules/image/oci/oci_export.c     |  13 +-
 src/daemon/modules/image/oci/oci_load.c       |  13 +-
 .../graphdriver/devmapper/driver_devmapper.c  |  12 +-
 .../graphdriver/overlay2/driver_overlay2.c    |  12 +-
 src/utils/tar/isulad_tar.c                    |  16 +-
 src/utils/tar/isulad_tar.h                    |   4 +-
 src/utils/tar/util_archive.c                  | 163 +++++++++++++++---
 src/utils/tar/util_archive.h                  |   8 +-
 12 files changed, 333 insertions(+), 52 deletions(-)

diff --git a/src/cmd/isula/stream/cp.c b/src/cmd/isula/stream/cp.c
index f0cd99c9..b1e3bbd6 100644
--- a/src/cmd/isula/stream/cp.c
+++ b/src/cmd/isula/stream/cp.c
@@ -73,6 +73,44 @@ static void print_copy_from_container_error(const char *ops_err, const char *arc
     }
 }
 
+static int client_get_root_dir(const isula_connect_ops *ops, const client_connect_config_t *config, char **root_dir)
+{
+    int ret = 0;
+    struct isula_info_request request = { 0 };
+    struct isula_info_response *response = NULL;
+
+    response = util_common_calloc_s(sizeof(struct isula_info_response));
+    if (response == NULL) {
+        COMMAND_ERROR("Info: Out of memory");
+        return -1;
+    }
+
+    if (!ops->container.info) {
+        COMMAND_ERROR("Unimplemented info op");
+        ret = -1;
+        goto out;
+    }
+
+    ret = ops->container.info(&request, response, (void *)config);
+    if (ret != 0) {
+        client_print_error(response->cc, response->server_errono, response->errmsg);
+        ret = -1;
+        goto out;
+    }
+
+    if (response->isulad_root_dir == NULL) {
+        COMMAND_ERROR("None root dir");
+        ret = -1;
+        goto out;
+    }
+
+    *root_dir = util_strdup_s(response->isulad_root_dir);
+
+out:
+    isula_info_response_free(response);
+    return ret;
+}
+
 static int client_copy_from_container(const struct client_arguments *args, const char *id, const char *srcpath,
                                       const char *destpath)
 {
@@ -84,6 +122,7 @@ static int client_copy_from_container(const struct client_arguments *args, const
     char *archive_err = NULL;
     char *ops_err = NULL;
     char *resolved = NULL;
+    char *root_dir = NULL;
     struct archive_copy_info *srcinfo = NULL;
     client_connect_config_t config;
 
@@ -92,18 +131,24 @@ static int client_copy_from_container(const struct client_arguments *args, const
         COMMAND_ERROR("Unimplemented copy from container operation");
         return -1;
     }
+    config = get_connect_config(args);
+
+    ret = client_get_root_dir(ops, &config, &root_dir);
+    if (ret != 0) {
+        return -1;
+    }
 
     response = util_common_calloc_s(sizeof(struct isula_copy_from_container_response));
     if (response == NULL) {
         ERROR("Event: Out of memory");
-        return -1;
+        ret = -1;
+        goto out;
     }
 
     request.id = (char *)id;
     request.runtime = args->runtime;
     request.srcpath = (char *)srcpath;
 
-    config = get_connect_config(args);
     ret = ops->container.copy_from_container(&request, response, &config);
     if (ret) {
         ops_err = (response->errmsg != NULL) ? util_strdup_s(response->errmsg) : NULL;
@@ -125,7 +170,7 @@ static int client_copy_from_container(const struct client_arguments *args, const
     srcinfo->path = util_strdup_s(srcpath);
     srcinfo->isdir = S_ISDIR(response->stat->mode);
 
-    nret = archive_copy_to(&response->reader, srcinfo, resolved, &archive_err);
+    nret = archive_copy_to(&response->reader, srcinfo, resolved, root_dir, &archive_err);
     if (nret != 0) {
         ret = nret;
     }
@@ -137,6 +182,7 @@ static int client_copy_from_container(const struct client_arguments *args, const
 
 out:
     print_copy_from_container_error(ops_err, archive_err, ret, args);
+    free(root_dir);
     free(resolved);
     free(archive_err);
     free(ops_err);
@@ -167,6 +213,7 @@ static int client_copy_to_container(const struct client_arguments *args, const c
     int nret = 0;
     char *archive_err = NULL;
     char *resolved = NULL;
+    char *root_dir = NULL;
     struct archive_copy_info *srcinfo = NULL;
     struct io_read_wrapper archive_reader = { 0 };
     client_connect_config_t config = { 0 };
@@ -176,11 +223,18 @@ static int client_copy_to_container(const struct client_arguments *args, const c
         COMMAND_ERROR("Unimplemented copy to container operation");
         return -1;
     }
+    config = get_connect_config(args);
+
+    ret = client_get_root_dir(ops, &config, &root_dir);
+    if (ret != 0) {
+        return -1;
+    }
 
     response = util_common_calloc_s(sizeof(struct isula_copy_to_container_response));
     if (response == NULL) {
         ERROR("Event: Out of memory");
-        return -1;
+        ret = -1;
+        goto out;
     }
 
     request.id = (char *)id;
@@ -199,7 +253,7 @@ static int client_copy_to_container(const struct client_arguments *args, const c
         goto out;
     }
 
-    nret = tar_resource(srcinfo, &archive_reader, &archive_err);
+    nret = tar_resource(srcinfo, root_dir, &archive_reader, &archive_err);
     if (nret != 0) {
         ret = -1;
         goto out;
@@ -212,7 +266,6 @@ static int client_copy_to_container(const struct client_arguments *args, const c
     request.reader.read = archive_reader.read;
     request.reader.close = archive_reader.close;
 
-    config = get_connect_config(args);
     ret = ops->container.copy_to_container(&request, response, &config);
 
     // archive reader close if copy to container failed
@@ -223,6 +276,7 @@ static int client_copy_to_container(const struct client_arguments *args, const c
 
 out:
     print_copy_to_container_error(response, archive_err, ret, args);
+    free(root_dir);
     free(resolved);
     free(archive_err);
     free_archive_copy_info(srcinfo);
diff --git a/src/cmd/isulad/main.c b/src/cmd/isulad/main.c
index 7b337358..4c057065 100644
--- a/src/cmd/isulad/main.c
+++ b/src/cmd/isulad/main.c
@@ -72,6 +72,7 @@
 #include "utils_file.h"
 #include "utils_string.h"
 #include "utils_verify.h"
+#include "path.h"
 #include "volume_api.h"
 #ifndef DISABLE_CLEANUP
 #include "leftover_cleanup_api.h"
@@ -1374,6 +1375,50 @@ out:
     return ret;
 }
 
+static int create_mount_flock_file(const struct service_arguments *args)
+{
+    int nret = 0;
+    int fd = -1;
+    char path[PATH_MAX] = { 0 };
+    char cleanpath[PATH_MAX] = { 0 };
+
+    nret = snprintf(path, PATH_MAX, "%s/%s", args->json_confs->graph, MOUNT_FLOCK_FILE_PATH);
+    if (nret < 0 || (size_t)nret >= PATH_MAX) {
+        ERROR("Failed to snprintf");
+        return -1;
+    }
+
+    if (util_clean_path(path, cleanpath, sizeof(cleanpath)) == NULL) {
+        ERROR("clean path for %s failed", path);
+        return -1;
+    }
+
+    if (util_fileself_exists(cleanpath)) {
+        int err = 0;
+        // recreate mount flock file
+        // and make file uid/gid and permission correct
+        if (!util_force_remove_file(cleanpath, &err)) {
+            ERROR("Failed to delete %s, error: %s. Please delete %s manually.", path, strerror(err), path);
+            return -1;
+        }
+    }
+
+    fd = util_open(cleanpath, O_RDWR | O_CREAT, MOUNT_FLOCK_FILE_MODE);
+    if (fd < 0) {
+        ERROR("Failed to create file %s", cleanpath);
+        return -1;
+    }
+    close(fd);
+
+    nret = util_set_file_group(cleanpath, args->json_confs->group);
+    if (nret < 0) {
+        ERROR("set group of the path %s failed", cleanpath);
+        return -1;
+    }
+
+    return 0;
+}
+
 static int isulad_server_init_service()
 {
     int ret = -1;
@@ -1404,6 +1449,12 @@ static int isulad_server_init_service()
         goto unlock_out;
     }
 
+    ret = create_mount_flock_file(args);
+    if (ret != 0) {
+        ERROR("Failed to create mount flock file");
+        goto unlock_out;
+    }
+
 unlock_out:
     if (isulad_server_conf_unlock()) {
         ret = -1;
diff --git a/src/common/constants.h b/src/common/constants.h
index e968d8cd..6988e25b 100644
--- a/src/common/constants.h
+++ b/src/common/constants.h
@@ -68,6 +68,8 @@ extern "C" {
 
 #define DEFAULT_HIGHEST_DIRECTORY_MODE 0755
 
+#define MOUNT_FLOCK_FILE_MODE 0660
+
 #define ISULAD_CONFIG SYSCONFDIR_PREFIX"/etc/isulad"
 
 #define ISULAD_DAEMON_CONTAINER_CONTEXTS ISULAD_CONFIG "/container_contexts"
@@ -119,6 +121,8 @@ extern "C" {
 #define OCI_VERSION "1.0.1"
 #endif
 
+#define MOUNT_FLOCK_FILE_PATH "isulad-chroot-mount.flock"
+
 #define OCI_IMAGE_GRAPH_ROOTPATH_NAME "storage"
 
 #ifdef ENABLE_GRPC_REMOTE_CONNECT
diff --git a/src/daemon/executor/container_cb/execution_stream.c b/src/daemon/executor/container_cb/execution_stream.c
index 32721e68..244ec6a0 100644
--- a/src/daemon/executor/container_cb/execution_stream.c
+++ b/src/daemon/executor/container_cb/execution_stream.c
@@ -62,6 +62,7 @@
 #include "utils.h"
 #include "utils_file.h"
 #include "utils_verify.h"
+#include "isulad_config.h"
 
 #if defined (__ANDROID__) || defined(__MUSL__)
 #define SIG_CANCEL_SIGNAL     SIGUSR1
@@ -442,6 +443,7 @@ static int archive_and_send_copy_data(const stream_func_wrapper *stream,
     char *absbase = NULL;
     char *err = NULL;
     char *buf = NULL;
+    char *root_dir = NULL;
     char cleaned[PATH_MAX + 2] = { 0 };
     struct io_read_wrapper reader = { 0 };
     char *tar_path = NULL;
@@ -474,9 +476,15 @@ static int archive_and_send_copy_data(const stream_func_wrapper *stream,
         goto cleanup;
     }
 
+    root_dir = conf_get_isulad_rootdir();
+    if (root_dir == NULL) {
+        ERROR("Failed to get isulad rootdir");
+        goto cleanup;
+    }
+
     DEBUG("archive chroot tar stream container_fs(%s) srcdir(%s) relative(%s) srcbase(%s) absbase(%s)",
           container_fs, srcdir, tar_path, srcbase, absbase);
-    nret = archive_chroot_tar_stream(container_fs, tar_path, srcbase, absbase, &reader);
+    nret = archive_chroot_tar_stream(container_fs, tar_path, srcbase, absbase, root_dir, &reader);
     if (nret != 0) {
         ERROR("Archive %s failed", resolvedpath);
         goto cleanup;
@@ -504,6 +512,7 @@ cleanup:
     free(srcdir);
     free(srcbase);
     free(absbase);
+    free(root_dir);
     if (reader.close != NULL) {
         int cret = reader.close(reader.context, &err);
         if (err != NULL) {
@@ -776,15 +785,25 @@ static int read_and_extract_archive(stream_func_wrapper *stream, const char *con
 {
     int ret = -1;
     char *err = NULL;
+    char *root_dir = NULL;
     struct io_read_wrapper content = { 0 };
     content.context = stream;
     content.read = extract_stream_to_io_read;
-    ret = archive_chroot_untar_stream(&content, container_fs, dstdir_in_container, src_rebase, dst_rebase, &err);
+
+    root_dir = conf_get_isulad_rootdir();
+    if (root_dir == NULL) {
+        ERROR("Failed to get isulad rootdir");
+        isulad_set_error_message("Failed to get isulad rootdir");
+        return -1;
+    }
+
+    ret = archive_chroot_untar_stream(&content, container_fs, dstdir_in_container, src_rebase, dst_rebase, root_dir, &err);
     if (ret != 0) {
         ERROR("Can not untar to container: %s", (err != NULL) ? err : "unknown");
         isulad_set_error_message("Can not untar to container: %s", (err != NULL) ? err : "unknown");
     }
     free(err);
+    free(root_dir);
     return ret;
 }
 
diff --git a/src/daemon/modules/image/oci/oci_export.c b/src/daemon/modules/image/oci/oci_export.c
index e27ed6d8..6bfcf4d5 100644
--- a/src/daemon/modules/image/oci/oci_export.c
+++ b/src/daemon/modules/image/oci/oci_export.c
@@ -23,6 +23,7 @@
 #include "util_archive.h"
 #include "path.h"
 #include "utils_file.h"
+#include "isulad_config.h"
 
 int oci_do_export(char *id, char *file)
 {
@@ -30,6 +31,7 @@ int oci_do_export(char *id, char *file)
     int ret2 = 0;
     char *mount_point = NULL;
     char *errmsg = NULL;
+    char *root_dir = NULL;
     char cleanpath[PATH_MAX] = { 0 };
 
     if (id == NULL || file == NULL) {
@@ -56,7 +58,15 @@ int oci_do_export(char *id, char *file)
         return -1;
     }
 
-    ret = archive_chroot_tar(mount_point, cleanpath, &errmsg);
+    root_dir = conf_get_isulad_rootdir();
+    if (root_dir == NULL) {
+        ERROR("Failed to get isulad rootdir");
+        isulad_set_error_message("Failed to get isulad rootdir");
+        ret = -1;
+        goto out;
+    }
+
+    ret = archive_chroot_tar(mount_point, cleanpath, root_dir, &errmsg);
     if (ret != 0) {
         ERROR("failed to export container %s to file %s: %s", id, cleanpath, errmsg);
         isulad_set_error_message("Failed to export rootfs with error: %s", errmsg);
@@ -68,6 +78,7 @@ out:
     mount_point = NULL;
     free(errmsg);
     errmsg = NULL;
+    free(root_dir);
 
     ret2 = storage_rootfs_umount(id, false);
     if (ret2 != 0) {
diff --git a/src/daemon/modules/image/oci/oci_load.c b/src/daemon/modules/image/oci/oci_load.c
index a5b669cd..0d450bb6 100644
--- a/src/daemon/modules/image/oci/oci_load.c
+++ b/src/daemon/modules/image/oci/oci_load.c
@@ -42,6 +42,7 @@
 #include "utils_file.h"
 #include "utils_verify.h"
 #include "oci_image.h"
+#include "isulad_config.h"
 
 #define MANIFEST_BIG_DATA_KEY "manifest"
 #define OCI_SCHEMA_VERSION 2
@@ -1051,6 +1052,7 @@ int oci_do_load(const im_load_request *request)
     char *digest = NULL;
     char *dstdir = NULL;
     char *err = NULL;
+    char *root_dir = NULL;
 
     if (request == NULL || request->file == NULL) {
         ERROR("Invalid input arguments, cannot load image");
@@ -1071,8 +1073,16 @@ int oci_do_load(const im_load_request *request)
         goto out;
     }
 
+    root_dir = conf_get_isulad_rootdir();
+    if (root_dir == NULL) {
+        ERROR("Failed to get isulad rootdir");
+        isulad_try_set_error_message("Failed to get isulad rootdir");
+        ret = -1;
+        goto out;
+    }
+
     options.whiteout_format = NONE_WHITEOUT_FORMATE;
-    if (archive_unpack(&reader, dstdir, &options, &err) != 0) {
+    if (archive_unpack(&reader, dstdir, &options, root_dir, &err) != 0) {
         ERROR("Failed to unpack to %s: %s", dstdir, err);
         isulad_try_set_error_message("Failed to unpack to %s: %s", dstdir, err);
         ret = -1;
@@ -1158,5 +1168,6 @@ out:
     }
     free(dstdir);
     free(err);
+    free(root_dir);
     return ret;
 }
diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c
index ca1b49df..0215fa6e 100644
--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c
+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c
@@ -33,6 +33,7 @@
 #include "utils_file.h"
 #include "utils_fs.h"
 #include "utils_string.h"
+#include "isulad_config.h"
 
 struct io_read_wrapper;
 
@@ -347,6 +348,7 @@ int devmapper_apply_diff(const char *id, const struct graphdriver *driver, const
     int ret = 0;
     struct archive_options options = { 0 };
     char *err = NULL;
+    char *root_dir = NULL;
 
     if (!util_valid_str(id) || driver == NULL || content == NULL) {
         ERROR("invalid argument to apply diff with id(%s)", id);
@@ -367,8 +369,15 @@ int devmapper_apply_diff(const char *id, const struct graphdriver *driver, const
         goto out;
     }
 
+    root_dir = conf_get_isulad_rootdir();
+    if (root_dir == NULL) {
+        ERROR("Failed to get isulad rootdir");
+        ret = -1;
+        goto umount_out;
+    }
+
     options.whiteout_format = REMOVE_WHITEOUT_FORMATE;
-    if (archive_unpack(content, layer_fs, &options, &err) != 0) {
+    if (archive_unpack(content, layer_fs, &options, root_dir, &err) != 0) {
         ERROR("devmapper: failed to unpack to %s: %s", layer_fs, err);
         ret = -1;
         goto umount_out;
@@ -385,6 +394,7 @@ out:
     free_driver_mount_opts(mount_opts);
     free(layer_fs);
     free(err);
+    free(root_dir);
     return ret;
 }
 
diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c
index 469a2367..510bd079 100644
--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c
+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c
@@ -45,6 +45,7 @@
 #include "utils_timestamp.h"
 #include "selinux_label.h"
 #include "err_msg.h"
+#include "isulad_config.h"
 #ifdef ENABLE_REMOTE_LAYER_STORE
 #include "ro_symlink_maintain.h"
 #endif
@@ -1883,6 +1884,7 @@ int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const
     char *layer_diff = NULL;
     struct archive_options options = { 0 };
     char *err = NULL;
+    char *root_dir = NULL;
 
     if (id == NULL || driver == NULL || content == NULL) {
         ERROR("invalid argument");
@@ -1916,7 +1918,14 @@ int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const
     }
 #endif
 
-    ret = archive_unpack(content, layer_diff, &options, &err);
+    root_dir = conf_get_isulad_rootdir();
+    if (root_dir == NULL) {
+        ERROR("Failed to get isulad rootdir");
+        ret = -1;
+        goto out;
+    }
+
+    ret = archive_unpack(content, layer_diff, &options, root_dir ,&err);
     if (ret != 0) {
         ERROR("Failed to unpack to %s: %s", layer_diff, err);
         ret = -1;
@@ -1925,6 +1934,7 @@ int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const
 
 out:
     free(err);
+    free(root_dir);
     free(layer_dir);
     free(layer_diff);
 #ifdef ENABLE_USERNS_REMAP
diff --git a/src/utils/tar/isulad_tar.c b/src/utils/tar/isulad_tar.c
index 709dfdd9..751616e7 100644
--- a/src/utils/tar/isulad_tar.c
+++ b/src/utils/tar/isulad_tar.c
@@ -386,7 +386,7 @@ cleanup:
 }
 
 int archive_copy_to(const struct io_read_wrapper *content, const struct archive_copy_info *srcinfo,
-                    const char *dstpath, char **err)
+                    const char *dstpath, const char *root_dir, char **err)
 {
     int ret = -1;
     struct archive_copy_info *dstinfo = NULL;
@@ -394,7 +394,7 @@ int archive_copy_to(const struct io_read_wrapper *content, const struct archive_
     char *src_base = NULL;
     char *dst_base = NULL;
 
-    if (err == NULL || dstpath == NULL || srcinfo == NULL || content == NULL) {
+    if (err == NULL || dstpath == NULL || srcinfo == NULL || content == NULL || root_dir == NULL) {
         return -1;
     }
 
@@ -410,7 +410,7 @@ int archive_copy_to(const struct io_read_wrapper *content, const struct archive_
         goto cleanup;
     }
 
-    ret = archive_chroot_untar_stream(content, dstdir, ".", src_base, dst_base, err);
+    ret = archive_chroot_untar_stream(content, dstdir, ".", src_base, dst_base, root_dir, err);
 
 cleanup:
     free_archive_copy_info(dstinfo);
@@ -420,7 +420,7 @@ cleanup:
     return ret;
 }
 
-static int tar_resource_rebase(const char *path, const char *rebase, struct io_read_wrapper *archive_reader, char **err)
+static int tar_resource_rebase(const char *path, const char *rebase, const char *root_dir, struct io_read_wrapper *archive_reader, char **err)
 {
     int ret = -1;
     int nret;
@@ -439,7 +439,7 @@ static int tar_resource_rebase(const char *path, const char *rebase, struct io_r
     }
 
     DEBUG("chroot tar stream srcdir(%s) srcbase(%s) rebase(%s)", srcdir, srcbase, rebase);
-    nret = archive_chroot_tar_stream(srcdir, srcbase, srcbase, rebase, archive_reader);
+    nret = archive_chroot_tar_stream(srcdir, srcbase, srcbase, rebase, root_dir, archive_reader);
     if (nret < 0) {
         ERROR("Can not archive path: %s", path);
         goto cleanup;
@@ -451,11 +451,11 @@ cleanup:
     return ret;
 }
 
-int tar_resource(const struct archive_copy_info *info, struct io_read_wrapper *archive_reader, char **err)
+int tar_resource(const struct archive_copy_info *info, const char *root_dir, struct io_read_wrapper *archive_reader, char **err)
 {
-    if (info == NULL || archive_reader == NULL || err == NULL) {
+    if (info == NULL || root_dir == NULL || archive_reader == NULL || err == NULL) {
         return -1;
     }
 
-    return tar_resource_rebase(info->path, info->rebase_name, archive_reader, err);
+    return tar_resource_rebase(info->path, info->rebase_name, root_dir, archive_reader, err);
 }
diff --git a/src/utils/tar/isulad_tar.h b/src/utils/tar/isulad_tar.h
index b620fd02..61edeaae 100644
--- a/src/utils/tar/isulad_tar.h
+++ b/src/utils/tar/isulad_tar.h
@@ -48,10 +48,10 @@ struct archive_copy_info *copy_info_source_path(const char *path, bool follow_li
 char *prepare_archive_copy(const struct archive_copy_info *srcinfo, const struct archive_copy_info *dstinfo,
                            char **src_base, char **dst_base, char **err);
 
-int tar_resource(const struct archive_copy_info *info, struct io_read_wrapper *archive_reader, char **err);
+int tar_resource(const struct archive_copy_info *info, const char *root_dir, struct io_read_wrapper *archive_reader, char **err);
 
 int archive_copy_to(const struct io_read_wrapper *content, const struct archive_copy_info *srcinfo,
-                    const char *dstpath, char **err);
+                    const char *dstpath, const char *root_dir, char **err);
 
 #ifdef __cplusplus
 }
diff --git a/src/utils/tar/util_archive.c b/src/utils/tar/util_archive.c
index a9d0025b..d5dabda9 100644
--- a/src/utils/tar/util_archive.c
+++ b/src/utils/tar/util_archive.c
@@ -23,6 +23,7 @@
 #include <sys/stat.h>
 #include <sys/mount.h>
 #include <sys/capability.h>
+#include <sys/file.h>
 #include <archive.h>
 #include <archive_entry.h>
 #include <errno.h>
@@ -78,6 +79,31 @@ static ssize_t read_content(struct archive *a, void *client_data, const void **b
     return mydata->content->read(mydata->content->context, mydata->buff, sizeof(mydata->buff));
 }
 
+static char *generate_flock_path(const char *root_dir)
+{
+    int nret = 0;
+    char path[PATH_MAX] = { 0 };
+    char cleanpath[PATH_MAX] = { 0 };
+
+    nret = snprintf(path, PATH_MAX, "%s/%s", root_dir, MOUNT_FLOCK_FILE_PATH);
+    if (nret < 0 || (size_t)nret >= PATH_MAX) {
+        ERROR("Failed to snprintf");
+        return NULL;
+    }
+
+    if (util_clean_path(path, cleanpath, sizeof(cleanpath)) == NULL) {
+        ERROR("clean path for %s failed", path);
+        return NULL;
+    }
+
+    if (!util_file_exists(cleanpath)) {
+        ERROR("flock file %s doesn't exist", cleanpath);
+        return NULL;
+    }
+
+    return util_strdup_s(cleanpath);
+}
+
 static void do_disable_unneccessary_caps()
 {
     cap_t caps;
@@ -99,7 +125,61 @@ static void do_disable_unneccessary_caps()
     cap_free(caps);
 }
 
-static int make_safedir_is_noexec(const char *dstdir, char **safe_dir)
+// Add flock when bind mount and make it private.
+// Because bind mount usually makes safedir shared mount point,
+// and sometimes it will cause "mount point explosion".
+// E.g. concurrently execute isula cp /tmp/<XXX-File> <CONTAINER-ID>:<CONTAINER-PAT>
+static int bind_mount_with_flock(const char *flock_path, const char *dstdir, const char *tmp_dir)
+{
+    int fd = -1;
+    int ret = -1;
+
+    fd = open(flock_path, O_RDWR | O_CLOEXEC);
+    if (fd < 0) {
+        SYSERROR("Failed to open file %s", flock_path);
+        return -1;
+    }
+
+    if (flock(fd, LOCK_EX) != 0) {
+        SYSERROR("Failed to lock file %s", flock_path);
+        goto out;
+    }
+
+    if (mount(dstdir, tmp_dir, "none", MS_BIND, NULL) != 0) {
+        SYSERROR("Mount safe dir failed");
+        goto unlock_out;
+    }
+
+    if (mount(tmp_dir, tmp_dir, "none", MS_BIND | MS_REMOUNT | MS_NOEXEC, NULL) != 0) {
+        SYSERROR("Mount safe dir failed");
+        if (umount(tmp_dir) != 0) {
+            SYSERROR("Failed to umount target %s", tmp_dir);
+        }
+        goto unlock_out;
+    }
+
+    // Change the propagation type.
+    if (mount("", tmp_dir, "", MS_PRIVATE, "") != 0) {
+        SYSERROR("Failed to change the propagation type");
+        if (umount(tmp_dir) != 0) {
+            SYSERROR("Failed to umount target %s", tmp_dir);
+        }
+        goto unlock_out;
+    }
+
+    ret = 0;
+
+unlock_out:
+    if (flock(fd, LOCK_UN) != 0) {
+        SYSERROR("Failed to unlock file %s", flock_path);
+    }
+
+out:
+    close(fd);
+    return ret;
+}
+
+static int make_safedir_is_noexec(const char *flock_path, const char *dstdir, char **safe_dir)
 {
     struct stat buf;
     char *isulad_tmpdir_env = NULL;
@@ -151,19 +231,8 @@ static int make_safedir_is_noexec(const char *dstdir, char **safe_dir)
         return -1;
     }
 
-    if (mount(dstdir, tmp_dir, "none", MS_BIND, NULL) != 0) {
-        SYSERROR("Mount safe dir failed");
-        if (util_path_remove(tmp_dir) != 0) {
-            ERROR("Failed to remove path %s", tmp_dir);
-        }
-        return -1;
-    }
-
-    if (mount(tmp_dir, tmp_dir, "none", MS_BIND | MS_REMOUNT | MS_NOEXEC, NULL) != 0) {
-        SYSERROR("Mount safe dir failed");
-        if (umount(tmp_dir) != 0) {
-            ERROR("Failed to umount target %s", tmp_dir);
-        }
+    if (bind_mount_with_flock(flock_path, dstdir, tmp_dir) != 0) {
+        ERROR("Failed to bind mount from %s to %s with flock", dstdir, tmp_dir);
         if (util_path_remove(tmp_dir) != 0) {
             ERROR("Failed to remove path %s", tmp_dir);
         }
@@ -718,7 +787,7 @@ static void set_child_process_pdeathsig(void)
 }
 
 int archive_unpack(const struct io_read_wrapper *content, const char *dstdir, const struct archive_options *options,
-                   char **errmsg)
+                   const char *root_dir, char **errmsg)
 {
     int ret = 0;
     pid_t pid = -1;
@@ -726,12 +795,24 @@ int archive_unpack(const struct io_read_wrapper *content, const char *dstdir, co
     int pipe_stderr[2] = { -1, -1 };
     char errbuf[BUFSIZ + 1] = { 0 };
     char *safe_dir = NULL;
+    char *flock_path = NULL;
 
-    if (make_safedir_is_noexec(dstdir, &safe_dir) != 0) {
-        ERROR("Prepare safe dir failed");
+    if (content == NULL || dstdir == NULL || options == NULL || root_dir == NULL) {
         return -1;
     }
 
+    flock_path = generate_flock_path(root_dir);
+    if (flock_path == NULL) {
+        ERROR("Failed to generate flock path");
+        return -1;
+    }
+
+    if (make_safedir_is_noexec(flock_path, dstdir, &safe_dir) != 0) {
+        ERROR("Prepare safe dir failed");
+        ret = -1;
+        goto cleanup;
+    }
+
     if (pipe2(pipe_stderr, O_CLOEXEC) != 0) {
         ERROR("Failed to create pipe");
         ret = -1;
@@ -811,6 +892,7 @@ cleanup:
         ERROR("Failed to remove path %s", safe_dir);
     }
     free(safe_dir);
+    free(flock_path);
     return ret;
 }
 
@@ -1121,7 +1203,7 @@ static ssize_t fd_write(void *context, const void *data, size_t len)
     return util_write_nointr(*(int *)context, data, len);
 }
 
-int archive_chroot_tar(char *path, char *file, char **errmsg)
+int archive_chroot_tar(const char *path, const char *file, const char *root_dir, char **errmsg)
 {
     struct io_write_wrapper pipe_context = { 0 };
     int ret = 0;
@@ -1131,12 +1213,24 @@ int archive_chroot_tar(char *path, char *file, char **errmsg)
     char errbuf[BUFSIZ + 1] = { 0 };
     int fd = 0;
     char *safe_dir = NULL;
+    char *flock_path = NULL;
 
-    if (make_safedir_is_noexec(path, &safe_dir) != 0) {
-        ERROR("Prepare safe dir failed");
+    if (path == NULL || file == NULL || root_dir == NULL) {
         return -1;
     }
 
+    flock_path = generate_flock_path(root_dir);
+    if (flock_path == NULL) {
+        ERROR("Failed to generate flock path");
+        return -1;
+    }
+
+    if (make_safedir_is_noexec(flock_path, path, &safe_dir) != 0) {
+        ERROR("Prepare safe dir failed");
+        ret = -1;
+        goto cleanup;
+    }
+
     if (pipe2(pipe_for_read, O_CLOEXEC) != 0) {
         ERROR("Failed to create pipe");
         ret = -1;
@@ -1227,6 +1321,7 @@ cleanup:
         ERROR("Failed to remove path %s", safe_dir);
     }
     free(safe_dir);
+    free(flock_path);
     return ret;
 }
 
@@ -1347,7 +1442,7 @@ static int archive_context_close(void *context, char **err)
 }
 
 int archive_chroot_untar_stream(const struct io_read_wrapper *context, const char *chroot_dir, const char *untar_dir,
-                                const char *src_base, const char *dst_base, char **errmsg)
+                                const char *src_base, const char *dst_base, const char *root_dir, char **errmsg)
 {
     struct io_read_wrapper pipe_context = { 0 };
     int pipe_stream[2] = { -1, -1 };
@@ -1365,12 +1460,19 @@ int archive_chroot_untar_stream(const struct io_read_wrapper *context, const cha
                .dst_base = dst_base
     };
     char *safe_dir = NULL;
+    char *flock_path = NULL;
 
-    if (make_safedir_is_noexec(chroot_dir, &safe_dir) != 0) {
-        ERROR("Prepare safe dir failed");
+    flock_path = generate_flock_path(root_dir);
+    if (flock_path == NULL) {
+        ERROR("Failed to generate flock path");
         return -1;
     }
 
+    if (make_safedir_is_noexec(flock_path, chroot_dir, &safe_dir) != 0) {
+        ERROR("Prepare safe dir failed");
+        goto cleanup;
+    }
+
     if (pipe(pipe_stderr) != 0) {
         ERROR("Failed to create pipe: %s", strerror(errno));
         goto cleanup;
@@ -1478,12 +1580,13 @@ cleanup:
         ERROR("Failed to remove path %s", safe_dir);
     }
     free(safe_dir);
+    free(flock_path);
 
     return ret;
 }
 
 int archive_chroot_tar_stream(const char *chroot_dir, const char *tar_path, const char *src_base, const char *dst_base,
-                              struct io_read_wrapper *reader)
+                              const char *root_dir, struct io_read_wrapper *reader)
 {
     struct io_write_wrapper pipe_context = { 0 };
     int keepfds[] = { -1, -1, -1 };
@@ -1493,12 +1596,19 @@ int archive_chroot_tar_stream(const char *chroot_dir, const char *tar_path, cons
     pid_t pid;
     struct archive_context *ctx = NULL;
     char *safe_dir = NULL;
+    char *flock_path = NULL;
 
-    if (make_safedir_is_noexec(chroot_dir, &safe_dir) != 0) {
-        ERROR("Prepare safe dir failed");
+    flock_path = generate_flock_path(root_dir);
+    if (flock_path == NULL) {
+        ERROR("Failed to generate flock path");
         return -1;
     }
 
+    if (make_safedir_is_noexec(flock_path, chroot_dir, &safe_dir) != 0) {
+        ERROR("Prepare safe dir failed");
+        goto free_out;
+    }
+
     if (pipe(pipe_stderr) != 0) {
         ERROR("Failed to create pipe: %s", strerror(errno));
         goto free_out;
@@ -1602,6 +1712,7 @@ free_out:
     close_archive_pipes_fd(pipe_stderr, 2);
     close_archive_pipes_fd(pipe_stream, 2);
     free(ctx);
+    free(flock_path);
     if (safe_dir != NULL) {
         if (umount(safe_dir) != 0) {
             ERROR("Failed to umount target %s", safe_dir);
diff --git a/src/utils/tar/util_archive.h b/src/utils/tar/util_archive.h
index 9312235d..be1f2cc7 100644
--- a/src/utils/tar/util_archive.h
+++ b/src/utils/tar/util_archive.h
@@ -49,17 +49,17 @@ struct archive_options {
 };
 
 int archive_unpack(const struct io_read_wrapper *content, const char *dstdir, const struct archive_options *options,
-                   char **errmsg);
+                   const char *root_dir, char **errmsg);
 
 bool valid_archive_format(const char *file);
 
-int archive_chroot_tar(char *path, char *file, char **errmsg);
+int archive_chroot_tar(const char *path, const char *file, const char *root_dir, char **errmsg);
 
 int archive_chroot_tar_stream(const char *chroot_dir, const char *tar_path, const char *src_base,
-                              const char *dst_base, struct io_read_wrapper *content);
+                              const char *dst_base, const char *root_dir, struct io_read_wrapper *content);
 int archive_chroot_untar_stream(const struct io_read_wrapper *content, const char *chroot_dir,
                                 const char *untar_dir, const char *src_base, const char *dst_base,
-                                char **errmsg);
+                                const char *root_dir, char **errmsg);
 
 #ifdef __cplusplus
 }
-- 
2.40.1

