Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_page.c
Show First 20 Lines • Show All 876 Lines • ▼ Show 20 Lines | vm_page_busy_acquire(vm_page_t m, int allocflags) | ||||
/* | /* | ||||
* The page-specific object must be cached because page | * The page-specific object must be cached because page | ||||
* identity can change during the sleep, causing the | * identity can change during the sleep, causing the | ||||
* re-lock of a different object. | * re-lock of a different object. | ||||
* It is assumed that a reference to the object is already | * It is assumed that a reference to the object is already | ||||
* held by the callers. | * held by the callers. | ||||
*/ | */ | ||||
obj = m->object; | obj = atomic_load_ptr(&m->object); | ||||
for (;;) { | for (;;) { | ||||
if (vm_page_tryacquire(m, allocflags)) | if (vm_page_tryacquire(m, allocflags)) | ||||
return (true); | return (true); | ||||
if ((allocflags & VM_ALLOC_NOWAIT) != 0) | if ((allocflags & VM_ALLOC_NOWAIT) != 0) | ||||
return (false); | return (false); | ||||
if (obj != NULL) | if (obj != NULL) | ||||
locked = VM_OBJECT_WOWNED(obj); | locked = VM_OBJECT_WOWNED(obj); | ||||
else | else | ||||
locked = false; | locked = false; | ||||
MPASS(locked || vm_page_wired(m)); | MPASS(locked || vm_page_wired(m)); | ||||
if (_vm_page_busy_sleep(obj, m, m->pindex, "vmpba", allocflags, | if (_vm_page_busy_sleep(obj, m, m->pindex, "vmpba", allocflags, | ||||
alc: Why isn't the pindex also cached? The page could move to a different offset within the same… | |||||
locked) && locked) | locked) && locked) | ||||
VM_OBJECT_WLOCK(obj); | VM_OBJECT_WLOCK(obj); | ||||
if ((allocflags & VM_ALLOC_WAITFAIL) != 0) | if ((allocflags & VM_ALLOC_WAITFAIL) != 0) | ||||
return (false); | return (false); | ||||
KASSERT(m->object == obj || m->object == NULL, | KASSERT(m->object == obj || m->object == NULL, | ||||
Not Done Inline ActionsI'm puzzled by the "m->object == NULL" case here. We appear to be allowing for the page to be removed from an object but not the possibility that is removed and quickly added to a different object. alc: I'm puzzled by the "m->object == NULL" case here. We appear to be allowing for the page to be… | |||||
Done Inline ActionsResponding to both comments here. I believe that consumers are supposed to guarantee that pages will not be freed or moved to another object if VM_ALLOC_WAITOK is specified. More concretely, VM_ALLOC_WAITOK must not be specified if the object has OBJ_ANON set. Otherwise the page must be wired, so it may be removed from its object but will not be freed, and vm_page_remove() preserves the pindex. I think is would be correct to add the following assertions: if (obj != NULL && (obj->flags & OBJ_ANON) != 0) KASSERT((allocflags & (VM_ALLOC_NOWAIT | VM_ALLOC_WAITFAIL)) != 0); else KASSERT(vm_page_wired(m)); At least, I'm able to boot with this change applied. markj: Responding to both comments here. I believe that consumers are supposed to guarantee that pages… | |||||
("vm_page_busy_acquire: page %p does not belong to %p", | ("vm_page_busy_acquire: page %p does not belong to %p", | ||||
m, obj)); | m, obj)); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* vm_page_busy_downgrade: | * vm_page_busy_downgrade: | ||||
* | * | ||||
▲ Show 20 Lines • Show All 3,471 Lines • ▼ Show 20 Lines | vm_page_grab_sleep(vm_object_t object, vm_page_t m, vm_pindex_t pindex, | ||||
/* | /* | ||||
* Reference the page before unlocking and sleeping so that | * Reference the page before unlocking and sleeping so that | ||||
* the page daemon is less likely to reclaim it. | * the page daemon is less likely to reclaim it. | ||||
*/ | */ | ||||
if (locked && (allocflags & VM_ALLOC_NOCREAT) == 0) | if (locked && (allocflags & VM_ALLOC_NOCREAT) == 0) | ||||
vm_page_reference(m); | vm_page_reference(m); | ||||
if (_vm_page_busy_sleep(object, m, m->pindex, wmesg, allocflags, | if (_vm_page_busy_sleep(object, m, pindex, wmesg, allocflags, locked) && | ||||
locked) && locked) | locked) | ||||
VM_OBJECT_WLOCK(object); | VM_OBJECT_WLOCK(object); | ||||
if ((allocflags & VM_ALLOC_WAITFAIL) != 0) | if ((allocflags & VM_ALLOC_WAITFAIL) != 0) | ||||
return (false); | return (false); | ||||
return (true); | return (true); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 376 Lines • ▼ Show 20 Lines | retrylookup: | ||||
if (m == NULL || m->pindex != pindex + i) { | if (m == NULL || m->pindex != pindex + i) { | ||||
mpred = m; | mpred = m; | ||||
m = NULL; | m = NULL; | ||||
} else | } else | ||||
mpred = TAILQ_PREV(m, pglist, listq); | mpred = TAILQ_PREV(m, pglist, listq); | ||||
for (; i < count; i++) { | for (; i < count; i++) { | ||||
if (m != NULL) { | if (m != NULL) { | ||||
if (!vm_page_tryacquire(m, allocflags)) { | if (!vm_page_tryacquire(m, allocflags)) { | ||||
if (vm_page_grab_sleep(object, m, pindex, | if (vm_page_grab_sleep(object, m, pindex + i, | ||||
"grbmaw", allocflags, true)) | "grbmaw", allocflags, true)) | ||||
goto retrylookup; | goto retrylookup; | ||||
break; | break; | ||||
} | } | ||||
} else { | } else { | ||||
if ((allocflags & VM_ALLOC_NOCREAT) != 0) | if ((allocflags & VM_ALLOC_NOCREAT) != 0) | ||||
break; | break; | ||||
m = vm_page_alloc_after(object, pindex + i, | m = vm_page_alloc_after(object, pindex + i, | ||||
▲ Show 20 Lines • Show All 740 Lines • Show Last 20 Lines |
Why isn't the pindex also cached? The page could move to a different offset within the same object.