mirror of
https://dev.lirent.ru/Vatrog/vm-vgpu-streamer.git
synced 2026-07-08 22:36:38 +03:00
fix: pin the vgpu region resident (raise working set, then VirtualLock)
The fallback path committed the region but left it demand-zero (not resident). VirtualLock can pin only up to the process minimum working set, and the default quota is far below the 96 MiB region, so a bare lock fails with ERROR_WORKING_SET_QUOTA. Raise the minimum first via SetProcessWorkingSetSize, then VirtualLock; pre-fault every page as a last resort. Neither needs SE_LOCK_MEMORY (that is for large pages / AWE).
This commit is contained in:
@@ -106,14 +106,40 @@ int vgpu_region_create(vgpu_region_t* out) {
|
|||||||
}
|
}
|
||||||
uintptr_t addr = (uintptr_t)p;
|
uintptr_t addr = (uintptr_t)p;
|
||||||
uintptr_t aligned = (addr + VGPU_2MB - 1) & ~(uintptr_t)(VGPU_2MB - 1);
|
uintptr_t aligned = (addr + VGPU_2MB - 1) & ~(uintptr_t)(VGPU_2MB - 1);
|
||||||
if (!VirtualLock((void*)aligned, (SIZE_T)bytes)) {
|
|
||||||
fprintf(stderr, "region: VirtualLock failed (%lu) — pages may not be pinned\n",
|
/* The region must be RESIDENT, not merely committed: the host reads it out
|
||||||
GetLastError());
|
* of guest RAM and only PRESENT pages are visible to it — a committed but
|
||||||
|
* demand-zero page has no PTE, so it is unreadable from the host. VirtualLock
|
||||||
|
* pins the pages into the working set, but it can lock at most the process
|
||||||
|
* MINIMUM working set, and the default quota is far below the region size
|
||||||
|
* (so a bare VirtualLock fails with ERROR_WORKING_SET_QUOTA). Raise the
|
||||||
|
* minimum first. NB: VirtualLock / SetProcessWorkingSetSize do NOT need
|
||||||
|
* SE_LOCK_MEMORY — that privilege is only for large pages / AWE. */
|
||||||
|
SIZE_T ws_min = (SIZE_T)(bytes + 64ull * 1024 * 1024); /* region + headroom */
|
||||||
|
SIZE_T ws_max = ws_min + 128ull * 1024 * 1024;
|
||||||
|
SIZE_T cur_min = 0, cur_max = 0;
|
||||||
|
if (GetProcessWorkingSetSize(GetCurrentProcess(), &cur_min, &cur_max)) {
|
||||||
|
if (cur_min > ws_min) ws_min = cur_min; /* never shrink an existing quota */
|
||||||
|
if (cur_max > ws_max) ws_max = cur_max;
|
||||||
}
|
}
|
||||||
|
if (!SetProcessWorkingSetSize(GetCurrentProcess(), ws_min, ws_max))
|
||||||
|
fprintf(stderr, "region: SetProcessWorkingSetSize(%llu MiB) failed (%lu)\n",
|
||||||
|
(unsigned long long)(ws_min / (1024 * 1024)), GetLastError());
|
||||||
|
|
||||||
|
if (!VirtualLock((void*)aligned, (SIZE_T)bytes)) {
|
||||||
|
fprintf(stderr, "region: VirtualLock failed (%lu) — pre-faulting region\n",
|
||||||
|
GetLastError());
|
||||||
|
/* Last resort: fault every page so it is at least PRESENT now. Without
|
||||||
|
* the lock the trimmer may evict it under pressure, but the raised
|
||||||
|
* minimum working set above makes eviction far less likely. */
|
||||||
|
volatile uint8_t* q = (volatile uint8_t*)aligned;
|
||||||
|
for (uint64_t off = 0; off < bytes; off += 4096u) q[off] = q[off];
|
||||||
|
}
|
||||||
|
|
||||||
os_base = p;
|
os_base = p;
|
||||||
base = (uint8_t*)aligned;
|
base = (uint8_t*)aligned;
|
||||||
os_total = total;
|
os_total = total;
|
||||||
fprintf(stderr, "region: fallback VirtualAlloc+VirtualLock %llu MiB, aligned at %p\n",
|
fprintf(stderr, "region: fallback VirtualAlloc+lock %llu MiB, aligned at %p\n",
|
||||||
(unsigned long long)(bytes / (1024 * 1024)), (void*)aligned);
|
(unsigned long long)(bytes / (1024 * 1024)), (void*)aligned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user