From 9b41a8d28d3ffbe33eb84d8e254b603012b22b34 Mon Sep 17 00:00:00 2001
From: DriedYellowPeach <wangrunze13@huawei.com>
Date: Sun, 11 Dec 2022 11:12:55 +0000
Subject: [PATCH 60/65] !1761 fix leftover devicemapper mnt dir * fix leftover
 devicemapper mnt dir

---
 .../graphdriver/devmapper/deviceset.c         | 37 +++++++++++++
 .../graphdriver/devmapper/deviceset.h         |  2 +
 .../graphdriver/devmapper/driver_devmapper.c  | 55 ++++++++++++-------
 .../oci/storage/layer_store/layer_store.c     | 11 +++-
 4 files changed, 84 insertions(+), 21 deletions(-)

diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c
index 4dadc336..b157510a 100644
--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c
+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c
@@ -486,6 +486,43 @@ out:
     return exist;
 }
 
+// return true if find the metadata
+// or the argument is wrong
+// or can't decide
+bool has_metadata(const char *hash, struct device_set *devset)
+{
+    char metadata_file[PATH_MAX] = { 0 };
+    char *metadata_path = NULL;
+    bool ret = true;
+    int nret = 0;
+
+    if (hash == NULL) {
+        return true;
+    }
+
+    metadata_path = metadata_dir(devset);
+    if (metadata_path == NULL) {
+        ERROR("Failed to get meta data directory");
+        goto out;
+    }
+
+    nret = snprintf(metadata_file, sizeof(metadata_file), "%s/%s", metadata_path, util_valid_str(hash) ? hash : "base");
+    if (nret < 0 || (size_t)nret >= sizeof(metadata_file)) {
+        ERROR("Failed to snprintf metadata file path with hash:%s, path is too long", hash);
+        goto out;
+    }
+
+    if (!util_file_exists(metadata_file)) {
+        WARN("No such file:%s, need not to load", metadata_file);
+        ret = false;
+        goto out;
+    }
+
+out:
+    free(metadata_path);
+    return ret;
+}
+
 static image_devmapper_device_info *load_metadata(const struct device_set *devset, const char *hash)
 {
     image_devmapper_device_info *info = NULL;
diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.h
index c11eece6..ec985e40 100644
--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.h
+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.h
@@ -83,6 +83,8 @@ int delete_device(const char *hash, bool sync_delete, struct device_set *devset)
 
 int export_device_metadata(struct device_metadata *dev_metadata, const char *hash, struct device_set *devset);
 
+bool has_metadata(const char *hash, struct device_set *devset);
+
 struct status *device_set_status(struct device_set *devset);
 
 void free_devmapper_status(struct status *st);
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 dd231bd6..c83d3e54 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
@@ -144,28 +144,11 @@ int devmapper_create_ro(const char *id, const char *parent, const struct graphdr
     return do_create(id, parent, driver, create_opts);
 }
 
-// Remove removes a device with a given id, unmounts the filesystem.
-int devmapper_rm_layer(const char *id, const struct graphdriver *driver)
+static int devmapper_try_rm_layer_mnt(const char *id, const struct graphdriver *driver)
 {
+    int ret = 0;
     char *mnt_parent_dir = NULL;
     char *mnt_point_dir = NULL;
-    int ret = 0;
-
-    if (!util_valid_str(id) || driver == NULL) {
-        ERROR("invalid argument");
-        return -1;
-    }
-
-    if (!has_device(id, driver->devset)) {
-        DEBUG("Device with id:%s is not exist", id);
-        goto out;
-    }
-
-    if (delete_device(id, false, driver->devset) != 0) {
-        ERROR("failed to remove device %s", id);
-        ret = -1;
-        goto out;
-    }
 
     mnt_parent_dir = util_path_join(driver->home, "mnt");
     if (mnt_parent_dir == NULL) {
@@ -193,6 +176,40 @@ out:
     return ret;
 }
 
+// Remove removes a device with a given id, unmounts the filesystem.
+int devmapper_rm_layer(const char *id, const struct graphdriver *driver)
+{
+    if (!util_valid_str(id) || driver == NULL) {
+        ERROR("invalid argument");
+        return -1;
+    }
+
+    if (!has_device(id, driver->devset)) {
+        DEBUG("Device with id:%s is not exist", id);
+        if (!has_metadata(id, driver->devset)) {
+            // this means metadata is lost
+            // if we can rm mnt, then the layer is removed
+            EVENT("try clean lost metadata and its mnt: %s", id);
+            return devmapper_try_rm_layer_mnt(id, driver);
+        }
+        // if has_metadata and not rm successfully, return -1
+        // so next start up of isulad will retry delete the layer.
+        return -1;
+    }
+
+    if (delete_device(id, false, driver->devset) != 0) {
+        ERROR("failed to remove device %s", id);
+        return -1;
+    }
+
+    if (devmapper_try_rm_layer_mnt(id, driver) != 0) {
+        ERROR("failed to remove mnt dir of Device: %s", id);
+        return -1;
+    }
+
+    return 0;
+}
+
 // devmapper_mount_layer mounts a device with given id into the root filesystem
 char *devmapper_mount_layer(const char *id, const struct graphdriver *driver,
                             const struct driver_mount_opts *mount_opts)
diff --git a/src/daemon/modules/image/oci/storage/layer_store/layer_store.c b/src/daemon/modules/image/oci/storage/layer_store/layer_store.c
index b9ab0d65..60aaff22 100644
--- a/src/daemon/modules/image/oci/storage/layer_store/layer_store.c
+++ b/src/daemon/modules/image/oci/storage/layer_store/layer_store.c
@@ -1813,8 +1813,15 @@ static bool load_layer_json_cb(const char *path_name, const struct dirent *sub_d
 
 remove_invalid_dir:
     (void)graphdriver_umount_layer(sub_dir->d_name);
-    (void)graphdriver_rm_layer(sub_dir->d_name);
-    (void)util_recursive_rmdir(tmpdir, 0);
+    // layer not removed successfully, we can't remove layer.json
+    if (graphdriver_rm_layer(sub_dir->d_name) != 0) {
+        ERROR("failed to rm layer: %s when handing invalid rootfs", sub_dir->d_name);
+        goto free_out;
+    }
+    ERROR("tmpdir is %s", tmpdir);
+    if (util_recursive_rmdir(tmpdir, 0) != 0) {
+        ERROR("failed to rm rootfs dir: %s when handing invalid rootfs", tmpdir);
+    }
 
 free_out:
     free(rpath);
-- 
2.25.1

