Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb58b015 authored by Steve Muckle's avatar Steve Muckle
Browse files

libmodprobe: add support to remove modules

Add a remove method which will unload a given module from the kernel,
along with any modules it depended on, assuming those modules are now
unused.

Change-Id: Ie66dc153ef1771f50e26421d38d3656e95954780
parent 73b2928b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -26,11 +26,13 @@ class Modprobe {

    bool LoadListedModules();
    bool LoadWithAliases(const std::string& module_name, bool strict);
    bool Remove(const std::string& module_name);

  private:
    std::string MakeCanonical(const std::string& module_path);
    bool InsmodWithDeps(const std::string& module_name);
    bool Insmod(const std::string& path_name);
    bool Rmmod(const std::string& module_name);
    std::vector<std::string> GetDependencies(const std::string& module);
    bool ModuleExists(const std::string& module_name);

+15 −0
Original line number Diff line number Diff line
@@ -315,3 +315,18 @@ bool Modprobe::LoadListedModules() {
    }
    return true;
}

bool Modprobe::Remove(const std::string& module_name) {
    auto dependencies = GetDependencies(MakeCanonical(module_name));
    if (dependencies.empty()) {
        LOG(ERROR) << "Empty dependencies for module " << module_name;
        return false;
    }
    if (!Rmmod(dependencies[0])) {
        return false;
    }
    for (auto dep = dependencies.begin() + 1; dep != dependencies.end(); ++dep) {
        Rmmod(*dep);
    }
    return true;
}
+9 −0
Original line number Diff line number Diff line
@@ -51,6 +51,15 @@ bool Modprobe::Insmod(const std::string& path_name) {
    return true;
}

bool Modprobe::Rmmod(const std::string& module_name) {
    int ret = syscall(__NR_delete_module, MakeCanonical(module_name).c_str(), O_NONBLOCK);
    if (ret != 0) {
        PLOG(ERROR) << "Failed to remove module '" << module_name << "'";
        return false;
    }
    return true;
}

bool Modprobe::ModuleExists(const std::string& module_name) {
    struct stat fileStat;
    auto deps = GetDependencies(module_name);
+10 −0
Original line number Diff line number Diff line
@@ -51,6 +51,16 @@ bool Modprobe::Insmod(const std::string& path_name) {
    return true;
}

bool Modprobe::Rmmod(const std::string& module_name) {
    for (auto it = modules_loaded.begin(); it != modules_loaded.end(); it++) {
        if (*it == module_name) {
            modules_loaded.erase(it);
            return true;
        }
    }
    return false;
}

bool Modprobe::ModuleExists(const std::string& module_name) {
    auto deps = GetDependencies(module_name);
    if (deps.empty()) {
+22 −0
Original line number Diff line number Diff line
@@ -56,6 +56,14 @@ TEST(libmodprobe, Test) {
            "/test13.ko",
    };

    std::vector<std::string> expected_after_remove = {
            "/test14.ko", "/test15.ko",         "/test1.ko",
            "/test6.ko",  "/test2.ko",          "/test5.ko",
            "/test8.ko",  "/test7.ko param1=4", "/test9.ko param_x=1 param_y=2 param_z=3",
            "/test10.ko", "/test12.ko",         "/test11.ko",
            "/test13.ko",
    };

    const std::string modules_dep =
            "test1.ko:\n"
            "test2.ko:\n"
@@ -131,4 +139,18 @@ TEST(libmodprobe, Test) {
    }

    EXPECT_TRUE(modules_loaded == expected_modules_loaded);

    EXPECT_TRUE(m.Remove("test4"));

    GTEST_LOG_(INFO) << "Expected modules loaded after removing test4 (in order):";
    for (auto i = expected_after_remove.begin(); i != expected_after_remove.end(); ++i) {
        *i = dir.path + *i;
        GTEST_LOG_(INFO) << "\"" << *i << "\"";
    }
    GTEST_LOG_(INFO) << "Actual modules loaded after removing test4 (in order):";
    for (auto i = modules_loaded.begin(); i != modules_loaded.end(); ++i) {
        GTEST_LOG_(INFO) << "\"" << *i << "\"";
    }

    EXPECT_TRUE(modules_loaded == expected_after_remove);
}