diff --git a/level_zero/tools/source/sysman/global_operations/linux/os_global_operations_imp.cpp b/level_zero/tools/source/sysman/global_operations/linux/os_global_operations_imp.cpp index e3a3eded24..c83cff6692 100644 --- a/level_zero/tools/source/sysman/global_operations/linux/os_global_operations_imp.cpp +++ b/level_zero/tools/source/sysman/global_operations/linux/os_global_operations_imp.cpp @@ -147,30 +147,32 @@ ze_result_t LinuxGlobalOperationsImp::reset(ze_bool_t force) { std::vector myPidFds; std::vector<::pid_t> processes; - // For all processes in the system, see if the process - // has this device open. - result = pProcfsAccess->listProcesses(processes); - if (ZE_RESULT_SUCCESS != result) { - return result; - } - for (auto &&pid : processes) { - std::vector fds; - getPidFdsForOpenDevice(pProcfsAccess, pSysfsAccess, pid, fds); - if (pid == myPid) { - // L0 is expected to have this file open. - // Keep list of fds. Close before unbind. - myPidFds = fds; - } else if (!fds.empty()) { - // Device is in use by another process. - // Don't reset while in use. - return ZE_RESULT_ERROR_HANDLE_OBJECT_IN_USE; + if (!force) { + // If not force, don't reset if any process + // has this device open. + result = pProcfsAccess->listProcesses(processes); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + for (auto &&pid : processes) { + std::vector fds; + getPidFdsForOpenDevice(pProcfsAccess, pSysfsAccess, pid, fds); + if (pid == myPid) { + // L0 is expected to have this file open. + // Keep list of fds. Close before unbind. + myPidFds = fds; + } else if (!fds.empty()) { + // Device is in use by another process. + // Don't reset while in use. + return ZE_RESULT_ERROR_HANDLE_OBJECT_IN_USE; + } } } for (auto &&fd : myPidFds) { // Close open filedescriptors to the device // before unbinding device. - // From this point forward, there is + // From this point forward, there is no // graceful way to fail the reset call. // All future ze calls by this process for this // device will fail. @@ -183,9 +185,9 @@ ze_result_t LinuxGlobalOperationsImp::reset(ze_bool_t force) { return result; } - // Verify no other process has the device open. - // This addresses the window between checking - // file handles above, and unbinding the device. + // If force is set (or someone opened the device + // after we checkd) there could be processes + // that have the device open. Kill them here. result = pProcfsAccess->listProcesses(processes); if (ZE_RESULT_SUCCESS != result) { return result; @@ -194,9 +196,7 @@ ze_result_t LinuxGlobalOperationsImp::reset(ze_bool_t force) { std::vector fds; getPidFdsForOpenDevice(pProcfsAccess, pSysfsAccess, pid, fds); if (!fds.empty()) { - // Process is using this device after we unbound it. - // Send a sigkill to the process to force it to close - // the device. Otherwise, the device cannot be rebound. + // Kill all processes that have the device open. ::kill(pid, SIGKILL); } } diff --git a/level_zero/tools/test/unit_tests/sources/sysman/global_operations/linux/mock_global_operations.h b/level_zero/tools/test/unit_tests/sources/sysman/global_operations/linux/mock_global_operations.h index 4482ffee1a..ed0b9ef93f 100644 --- a/level_zero/tools/test/unit_tests/sources/sysman/global_operations/linux/mock_global_operations.h +++ b/level_zero/tools/test/unit_tests/sources/sysman/global_operations/linux/mock_global_operations.h @@ -39,11 +39,21 @@ const std::string engine2("2"); const std::string engine3("3"); std::string driverVersion("5.0.0-37-generic SMP mod_unload"); std::string srcVersion("5.0.0-37"); +const std::string fullFunctionResetPath("/reset"); class GlobalOperationsSysfsAccess : public SysfsAccess {}; template <> struct Mock : public GlobalOperationsSysfsAccess { + ze_result_t getRealPathVal(const std::string file, std::string &val) { + if (file.compare(functionLevelReset) == 0) { + val = fullFunctionResetPath; + } else { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + ze_result_t getValString(const std::string file, std::string &val) { if (file.compare(subsystemVendorFile) == 0) { val = "0x8086"; @@ -131,6 +141,7 @@ struct Mock : public GlobalOperationsSysfsAccess { MOCK_METHOD(ze_result_t, read, (const std::string file, std::string &val), (override)); MOCK_METHOD(ze_result_t, read, (const std::string file, uint64_t &val), (override)); MOCK_METHOD(ze_result_t, scanDirEntries, (const std::string path, std::vector &list), (override)); + MOCK_METHOD(ze_result_t, getRealPath, (const std::string path, std::string &val), (override)); }; class GlobalOperationsFsAccess : public FsAccess {}; @@ -168,9 +179,14 @@ struct Mock : public GlobalOperationsFsAccess { return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS; } + ze_result_t getPermissionDenied(const std::string file) { + return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS; + } + Mock() = default; MOCK_METHOD(ze_result_t, read, (const std::string file, std::string &val), (override)); + MOCK_METHOD(ze_result_t, canWrite, (const std::string file), (override)); }; class PublicLinuxGlobalOperationsImp : public L0::LinuxGlobalOperationsImp { diff --git a/level_zero/tools/test/unit_tests/sources/sysman/global_operations/linux/test_zes_global_operations.cpp b/level_zero/tools/test/unit_tests/sources/sysman/global_operations/linux/test_zes_global_operations.cpp index 68db1e46e5..89767c53cc 100644 --- a/level_zero/tools/test/unit_tests/sources/sysman/global_operations/linux/test_zes_global_operations.cpp +++ b/level_zero/tools/test/unit_tests/sources/sysman/global_operations/linux/test_zes_global_operations.cpp @@ -178,5 +178,15 @@ TEST_F(SysmanGlobalOperationsFixture, GivenValidDeviceHandleWhileReadingNonExist EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, pSysfsAccess->scanDirEntries("clients/7/busy", engineEntries)); } +TEST_F(SysmanGlobalOperationsFixture, GivenValidDeviceHandleWhenCallingResetVerifyPermissionDenied) { + ON_CALL(*pSysfsAccess.get(), getRealPath(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getRealPathVal)); + ON_CALL(*pFsAccess.get(), canWrite(Matcher(fullFunctionResetPath))) + .WillByDefault(::testing::Invoke(pFsAccess.get(), &Mock::getPermissionDenied)); + pGlobalOperationsImp->init(); + ze_result_t result = zesDeviceReset(device, true); + EXPECT_EQ(ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS, result); +} + } // namespace ult } // namespace L0