On 3/3/21 10:16 PM, Alistair Popple wrote:
Some devices require exclusive write access to shared virtual memory (SVM) ranges to perform atomic operations on that memory. This requires CPU page tables to be updated to deny access whilst atomic operations are occurring. In order to do this introduce a new swap entry type (SWP_DEVICE_EXCLUSIVE). When a SVM range needs to be marked for exclusive access by a device all page table mappings for the particular range are replaced with device exclusive swap entries. This causes any CPU access to the page to result in a fault. Faults are resovled by replacing the faulting entry with the original mapping. This results in MMU notifiers being called which a driver uses to update access permissions such as revoking atomic access. After notifiers have been called the device will no longer have exclusive access to the region. Signed-off-by: Alistair Popple <apopple@xxxxxxxxxx>
I see in the next two patches how make_device_exclusive_entry() and check_device_exclusive_range() are used. This points out a similar problem that migrate_vma_setup() had before I added the mmu_notifier_range_init_migrate() helper to pass a cookie from migrate_vma_setup() to the invalidation callback so the device driver could ignore an invalidation callback triggered by the caller and thus resulting in a deadlock or having to invalidate device PTEs that wouldn't be migrating. I think you can eliminate the need for check_device_exclusive_range() in the same way by adding a "void *" pointer to make_device_exclusive_entry() and passing that through to try_to_protect(), setting rmap_walk_control rwc.arg and then passing arg to mmu_notifier_range_init_migrate(). Although, maybe it would be better to define a new mmu_notifier_range_init_exclusive() and event type MMU_NOTIFY_EXCLUSIVE so that a device driver can revoke atomic/exclusive access but keep read/write access to other parts of the page. I thought about how make_device_exclusive_entry() is similar to hmm_range_fault() and whether it would be possible to add a new HMM_PFN_REQ_EXCLUSIVE flag but I see that make_device_exclusive_entry() returns the pages locked and with an additional get_page() reference. This doesn't fit well with the other hmm_range_fault() entries being returned as a "snapshot" so having a different API makes sense. I think it would be useful to add a HMM_PFN_EXCLUSIVE flag so that snapshots of the page tables can at least report that a page is exclusively being accessed by *some* device. Unfortunately, there is no pgmap pointer to be able to tell which device has exclusive access (since any struct page could be exclusively accessed, not just device private ones).