Free allocated BOs for read-only user pointer

- when pinning fails with EFAULT due to read-only memory
used for allocation (BO), mark the allocated fragments
to be freed, as cpu copy will be used.
- prevent possible leaks

Change-Id: I200ba276da5e3a8557df28fe2e411ef30d69a86a
This commit is contained in:
Hoppe, Mateusz 2018-03-20 16:06:16 +01:00 committed by sys_ocldev
parent 1e81426599
commit eec43f65a7
2 changed files with 51 additions and 0 deletions

View File

@ -472,6 +472,7 @@ uint64_t DrmMemoryManager::getInternalHeapBaseAddress() {
MemoryManager::AllocationStatus DrmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) {
BufferObject *allocatedBos[max_fragments_count];
size_t numberOfBosAllocated = 0;
uint32_t indexesOfAllocatedBos[max_fragments_count];
for (unsigned int i = 0; i < max_fragments_count; i++) {
// If there is no fragment it means it already exists.
@ -489,6 +490,7 @@ MemoryManager::AllocationStatus DrmMemoryManager::populateOsHandles(OsHandleStor
}
allocatedBos[numberOfBosAllocated] = handleStorage.fragmentStorageData[i].osHandleStorage->bo;
indexesOfAllocatedBos[numberOfBosAllocated] = i;
numberOfBosAllocated++;
hostPtrManager.storeFragment(handleStorage.fragmentStorageData[i]);
@ -499,6 +501,9 @@ MemoryManager::AllocationStatus DrmMemoryManager::populateOsHandles(OsHandleStor
int result = pinBB->pin(allocatedBos, numberOfBosAllocated);
if (result == EFAULT) {
for (uint32_t i = 0; i < numberOfBosAllocated; i++) {
handleStorage.fragmentStorageData[indexesOfAllocatedBos[i]].freeTheFragment = true;
}
return AllocationStatus::InvalidHostPointer;
} else if (result != 0) {
return AllocationStatus::Error;

View File

@ -2571,3 +2571,49 @@ TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenForcePinNotAllowedAndH
::alignedFree(ptr);
}
TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenEnabledValidateHostMemoryWhenReadOnlyPointerCausesPinningFailWithEfaultThenPopulateOsHandlesMarksFragmentsToFree) {
std::unique_ptr<TestedDrmMemoryManager> testedMemoryManager(new TestedDrmMemoryManager(this->mock, false, true));
ASSERT_NE(nullptr, testedMemoryManager.get());
ASSERT_NE(nullptr, testedMemoryManager->getPinBB());
mock->reset();
DrmMockCustom::IoctlResExt ioctlResExt = {2, -1};
mock->ioctl_res_ext = &ioctlResExt;
mock->errnoValue = EFAULT;
mock->ioctl_expected.gemUserptr = 2;
mock->ioctl_expected.execbuffer2 = 1;
OsHandleStorage handleStorage;
OsHandle handle1;
handleStorage.fragmentStorageData[0].osHandleStorage = &handle1;
handleStorage.fragmentStorageData[0].cpuPtr = (void *)0x1000;
handleStorage.fragmentStorageData[0].fragmentSize = 4096;
handleStorage.fragmentStorageData[1].osHandleStorage = nullptr;
handleStorage.fragmentStorageData[1].cpuPtr = (void *)0x2000;
handleStorage.fragmentStorageData[1].fragmentSize = 8192;
handleStorage.fragmentStorageData[2].osHandleStorage = nullptr;
handleStorage.fragmentStorageData[2].cpuPtr = (void *)0x4000;
handleStorage.fragmentStorageData[2].fragmentSize = 4096;
auto result = testedMemoryManager->populateOsHandles(handleStorage);
EXPECT_EQ(MemoryManager::AllocationStatus::InvalidHostPointer, result);
mock->testIoctls();
EXPECT_NE(nullptr, handleStorage.fragmentStorageData[0].osHandleStorage);
EXPECT_NE(nullptr, handleStorage.fragmentStorageData[1].osHandleStorage);
EXPECT_NE(nullptr, handleStorage.fragmentStorageData[2].osHandleStorage);
EXPECT_TRUE(handleStorage.fragmentStorageData[1].freeTheFragment);
EXPECT_TRUE(handleStorage.fragmentStorageData[2].freeTheFragment);
handleStorage.fragmentStorageData[0].freeTheFragment = false;
handleStorage.fragmentStorageData[1].freeTheFragment = true;
handleStorage.fragmentStorageData[2].freeTheFragment = true;
testedMemoryManager->cleanOsHandles(handleStorage);
}