Update zesDeviceReset to 1.0 Spec.

Change-Id: Idc55e9c06c4cd7cd366c4a1dd9af77e518c0bec3
Signed-off-by: Bill Jordan <bill.jordan@intel.com>
This commit is contained in:
Bill Jordan
2020-08-07 11:40:19 -04:00
committed by sys_ocldev
parent 1f6fc04e91
commit 4b0aad316f
3 changed files with 50 additions and 24 deletions

View File

@@ -147,30 +147,32 @@ ze_result_t LinuxGlobalOperationsImp::reset(ze_bool_t force) {
std::vector<int> 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<int> 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<int> 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<int> 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);
}
}

View File

@@ -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<GlobalOperationsSysfsAccess> : 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<GlobalOperationsSysfsAccess> : 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<std::string> &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<GlobalOperationsFsAccess> : public GlobalOperationsFsAccess {
return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS;
}
ze_result_t getPermissionDenied(const std::string file) {
return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS;
}
Mock<GlobalOperationsFsAccess>() = 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 {

View File

@@ -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<std::string &>(_)))
.WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock<GlobalOperationsSysfsAccess>::getRealPathVal));
ON_CALL(*pFsAccess.get(), canWrite(Matcher<std::string>(fullFunctionResetPath)))
.WillByDefault(::testing::Invoke(pFsAccess.get(), &Mock<GlobalOperationsFsAccess>::getPermissionDenied));
pGlobalOperationsImp->init();
ze_result_t result = zesDeviceReset(device, true);
EXPECT_EQ(ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS, result);
}
} // namespace ult
} // namespace L0