Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_mmap.c
Show First 20 Lines • Show All 773 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
return (kern_mincore(td, (uintptr_t)uap->addr, uap->len, uap->vec)); | return (kern_mincore(td, (uintptr_t)uap->addr, uap->len, uap->vec)); | ||||
} | } | ||||
int | int | ||||
kern_mincore(struct thread *td, uintptr_t addr0, size_t len, char *vec) | kern_mincore(struct thread *td, uintptr_t addr0, size_t len, char *vec) | ||||
{ | { | ||||
vm_offset_t addr, first_addr; | |||||
vm_offset_t end, cend; | |||||
pmap_t pmap; | pmap_t pmap; | ||||
vm_map_t map; | vm_map_t map; | ||||
int error = 0; | vm_map_entry_t current, entry; | ||||
int vecindex, lastvecindex; | |||||
vm_map_entry_t current; | |||||
vm_map_entry_t entry; | |||||
vm_object_t object; | vm_object_t object; | ||||
vm_paddr_t locked_pa; | vm_offset_t addr, cend, end, first_addr; | ||||
vm_paddr_t pa; | |||||
vm_page_t m; | vm_page_t m; | ||||
vm_pindex_t pindex; | vm_pindex_t pindex; | ||||
int mincoreinfo; | int error, lastvecindex, mincoreinfo, vecindex; | ||||
unsigned int timestamp; | unsigned int timestamp; | ||||
boolean_t locked; | |||||
/* | /* | ||||
* Make sure that the addresses presented are valid for user | * Make sure that the addresses presented are valid for user | ||||
* mode. | * mode. | ||||
*/ | */ | ||||
first_addr = addr = trunc_page(addr0); | first_addr = addr = trunc_page(addr0); | ||||
end = addr + (vm_size_t)round_page(len); | end = round_page(addr0 + len); | ||||
alc: Shouldn't this be:
```
end = round_page(addr0 + len);
``` | |||||
Done Inline ActionsI think so. markj: I think so. | |||||
map = &td->td_proc->p_vmspace->vm_map; | map = &td->td_proc->p_vmspace->vm_map; | ||||
if (end > vm_map_max(map) || end < addr) | if (end > vm_map_max(map) || end < addr) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
pmap = vmspace_pmap(td->td_proc->p_vmspace); | pmap = vmspace_pmap(td->td_proc->p_vmspace); | ||||
vm_map_lock_read(map); | vm_map_lock_read(map); | ||||
RestartScan: | RestartScan: | ||||
Show All 19 Lines | if (current->end < end && current->next->start > current->end) { | ||||
vm_map_unlock_read(map); | vm_map_unlock_read(map); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
/* | /* | ||||
* ignore submaps (for now) or null objects | * ignore submaps (for now) or null objects | ||||
*/ | */ | ||||
if ((current->eflags & MAP_ENTRY_IS_SUB_MAP) || | if ((current->eflags & MAP_ENTRY_IS_SUB_MAP) || | ||||
current->object.vm_object == NULL) | current->object.vm_object == NULL) | ||||
continue; | continue; | ||||
/* | /* | ||||
* limit this scan to the current map entry and the | * limit this scan to the current map entry and the | ||||
* limits for the mincore call | * limits for the mincore call | ||||
*/ | */ | ||||
if (addr < current->start) | if (addr < current->start) | ||||
addr = current->start; | addr = current->start; | ||||
cend = current->end; | cend = current->end; | ||||
if (cend > end) | if (cend > end) | ||||
cend = end; | cend = end; | ||||
for (; addr < cend; addr += PAGE_SIZE) { | |||||
/* | /* | ||||
* scan this entry one page at a time | |||||
*/ | |||||
while (addr < cend) { | |||||
/* | |||||
* Check pmap first, it is likely faster, also | * Check pmap first, it is likely faster, also | ||||
* it can provide info as to whether we are the | * it can provide info as to whether we are the | ||||
* one referencing or modifying the page. | * one referencing or modifying the page. | ||||
*/ | */ | ||||
m = NULL; | |||||
object = NULL; | object = NULL; | ||||
locked_pa = 0; | |||||
retry: | retry: | ||||
m = NULL; | pa = 0; | ||||
mincoreinfo = pmap_mincore(pmap, addr, &locked_pa); | mincoreinfo = pmap_mincore(pmap, addr, &pa); | ||||
if (mincore_mapped) { | if (mincore_mapped) { | ||||
/* | /* | ||||
* We only care about this pmap's | * We only care about this pmap's | ||||
* mapping of the page, if any. | * mapping of the page, if any. | ||||
*/ | */ | ||||
if (locked_pa != 0) { | ; | ||||
vm_page_unlock(PHYS_TO_VM_PAGE( | } else if (pa != 0) { | ||||
locked_pa)); | |||||
} | |||||
} else if (locked_pa != 0) { | |||||
/* | /* | ||||
* The page is mapped by this process but not | * The page is mapped by this process but not | ||||
* both accessed and modified. It is also | * both accessed and modified. It is also | ||||
* managed. Acquire the object lock so that | * managed. Acquire the object lock so that | ||||
* other mappings might be examined. | * other mappings might be examined. The page's | ||||
* identity may change at any point before its | |||||
* object lock is acquired, so re-validate if | |||||
* necessary. | |||||
*/ | */ | ||||
m = PHYS_TO_VM_PAGE(locked_pa); | m = PHYS_TO_VM_PAGE(pa); | ||||
if (m->object != object) { | while (object == NULL || m->object != object) { | ||||
if (object != NULL) | if (object != NULL) | ||||
VM_OBJECT_WUNLOCK(object); | VM_OBJECT_WUNLOCK(object); | ||||
object = m->object; | object = (vm_object_t)atomic_load_ptr( | ||||
locked = VM_OBJECT_TRYWLOCK(object); | &m->object); | ||||
vm_page_unlock(m); | if (object == NULL) | ||||
if (!locked) { | |||||
VM_OBJECT_WLOCK(object); | |||||
vm_page_lock(m); | |||||
goto retry; | goto retry; | ||||
VM_OBJECT_WLOCK(object); | |||||
} | } | ||||
Not Done Inline ActionsWhere does this loop terminate if m->object == object and not NULL ? kib: Where does this loop terminate if m->object == object and not NULL ? | |||||
Done Inline ActionsI forgot to submit this comment apparently: Sorry, I probably don't understand the question. The loop condition is m->object != object. object != NULL implies that object is write-locked, so if m->object == object the page identity cannot change. markj: I forgot to submit this comment apparently:
Sorry, I probably don't understand the question. | |||||
} else | if (pa != pmap_extract(pmap, addr)) | ||||
vm_page_unlock(m); | goto retry; | ||||
KASSERT(m->valid == VM_PAGE_BITS_ALL, | KASSERT(m->valid == VM_PAGE_BITS_ALL, | ||||
("mincore: page %p is mapped but invalid", | ("mincore: page %p is mapped but invalid", | ||||
m)); | m)); | ||||
} else if (mincoreinfo == 0) { | } else if (mincoreinfo == 0) { | ||||
/* | /* | ||||
* The page is not mapped by this process. If | * The page is not mapped by this process. If | ||||
* the object implements managed pages, then | * the object implements managed pages, then | ||||
* determine if the page is resident so that | * determine if the page is resident so that | ||||
Show All 13 Lines | retry: | ||||
m = vm_page_lookup(object, pindex); | m = vm_page_lookup(object, pindex); | ||||
if (m != NULL && m->valid == 0) | if (m != NULL && m->valid == 0) | ||||
m = NULL; | m = NULL; | ||||
if (m != NULL) | if (m != NULL) | ||||
mincoreinfo = MINCORE_INCORE; | mincoreinfo = MINCORE_INCORE; | ||||
} | } | ||||
} | } | ||||
if (m != NULL) { | if (m != NULL) { | ||||
/* Examine other mappings to the page. */ | VM_OBJECT_ASSERT_WLOCKED(m->object); | ||||
/* Examine other mappings of the page. */ | |||||
if (m->dirty == 0 && pmap_is_modified(m)) | if (m->dirty == 0 && pmap_is_modified(m)) | ||||
vm_page_dirty(m); | vm_page_dirty(m); | ||||
if (m->dirty != 0) | if (m->dirty != 0) | ||||
mincoreinfo |= MINCORE_MODIFIED_OTHER; | mincoreinfo |= MINCORE_MODIFIED_OTHER; | ||||
/* | /* | ||||
* The first test for PGA_REFERENCED is an | * The first test for PGA_REFERENCED is an | ||||
* optimization. The second test is | * optimization. The second test is | ||||
* required because a concurrent pmap | * required because a concurrent pmap | ||||
* operation could clear the last reference | * operation could clear the last reference | ||||
* and set PGA_REFERENCED before the call to | * and set PGA_REFERENCED before the call to | ||||
* pmap_is_referenced(). | * pmap_is_referenced(). | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | retry: | ||||
* If the map has changed, due to the subyte, the previous | * If the map has changed, due to the subyte, the previous | ||||
* output may be invalid. | * output may be invalid. | ||||
*/ | */ | ||||
vm_map_lock_read(map); | vm_map_lock_read(map); | ||||
if (timestamp != map->timestamp) | if (timestamp != map->timestamp) | ||||
goto RestartScan; | goto RestartScan; | ||||
lastvecindex = vecindex; | lastvecindex = vecindex; | ||||
addr += PAGE_SIZE; | |||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* subyte may page fault. In case it needs to modify | * subyte may page fault. In case it needs to modify | ||||
* the map, we release the lock. | * the map, we release the lock. | ||||
*/ | */ | ||||
vm_map_unlock_read(map); | vm_map_unlock_read(map); | ||||
▲ Show 20 Lines • Show All 651 Lines • Show Last 20 Lines |
Shouldn't this be: