Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_pageout.c
Show First 20 Lines • Show All 707 Lines • ▼ Show 20 Lines | if (mp != NULL) { | ||||||||
vm_object_deallocate(object); | vm_object_deallocate(object); | ||||||||
vn_finished_write(mp); | vn_finished_write(mp); | ||||||||
} | } | ||||||||
return (error); | return (error); | ||||||||
} | } | ||||||||
/* | /* | ||||||||
* Check if the object is active. Non-anonymous swap objects are | |||||||||
* always referenced by owner, for them require ref_count > 1 to | |||||||||
alcUnsubmitted Done Inline Actions
alc: | |||||||||
* ignore the ownership ref. | |||||||||
* | |||||||||
* Perform an unsynchronized object ref count check. While | |||||||||
* the page lock ensures that the page is not reallocated to | |||||||||
* another object, in particular, one with unmanaged mappings | |||||||||
* that cannot support pmap_ts_referenced(), two races are, | |||||||||
* nonetheless, possible: | |||||||||
* 1) The count was transitioning to zero, but we saw a non- | |||||||||
* zero value. pmap_ts_referenced() will return zero | |||||||||
* because the page is not mapped. | |||||||||
* 2) The count was transitioning to one, but we saw zero. | |||||||||
* This race delays the detection of a new reference. At | |||||||||
* worst, we will deactivate and reactivate the page. | |||||||||
Not Done Inline ActionsThis comment is out of date, the page lock is no longer used. If the page is deallocated, the references are generally lost. I can fix this in a follow-up. markj: This comment is out of date, the page lock is no longer used. If the page is deallocated, the… | |||||||||
Done Inline ActionsI do not think that references of the page being deallocated serve any use. kib: I do not think that references of the page being deallocated serve any use. | |||||||||
*/ | |||||||||
static bool | |||||||||
vm_pageout_object_act(vm_object_t object) | |||||||||
{ | |||||||||
return (object->ref_count > | |||||||||
((object->flags & (OBJ_SWAP | OBJ_ANON)) == OBJ_SWAP ? 1 : 0)); | |||||||||
} | |||||||||
static int | |||||||||
vm_pageout_page_ts_referenced(vm_object_t object, vm_page_t m) | |||||||||
{ | |||||||||
if (!vm_pageout_object_act(object)) | |||||||||
return (0); | |||||||||
return (pmap_ts_referenced(m)); | |||||||||
} | |||||||||
Done Inline ActionsExtra newline. markj: Extra newline. | |||||||||
/* | |||||||||
* Attempt to launder the specified number of pages. | * Attempt to launder the specified number of pages. | ||||||||
* | * | ||||||||
* Returns the number of pages successfully laundered. | * Returns the number of pages successfully laundered. | ||||||||
*/ | */ | ||||||||
static int | static int | ||||||||
vm_pageout_launder(struct vm_domain *vmd, int launder, bool in_shortfall) | vm_pageout_launder(struct vm_domain *vmd, int launder, bool in_shortfall) | ||||||||
{ | { | ||||||||
struct scan_state ss; | struct scan_state ss; | ||||||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | while (launder > 0 && (m = vm_pageout_next(&ss, false)) != NULL) { | ||||||||
/* | /* | ||||||||
* Invalid pages can be easily freed. They cannot be | * Invalid pages can be easily freed. They cannot be | ||||||||
* mapped; vm_page_free() asserts this. | * mapped; vm_page_free() asserts this. | ||||||||
*/ | */ | ||||||||
if (vm_page_none_valid(m)) | if (vm_page_none_valid(m)) | ||||||||
goto free_page; | goto free_page; | ||||||||
refs = object->ref_count != 0 ? pmap_ts_referenced(m) : 0; | refs = vm_pageout_page_ts_referenced(object, m); | ||||||||
for (old = vm_page_astate_load(m);;) { | for (old = vm_page_astate_load(m);;) { | ||||||||
/* | /* | ||||||||
* Check to see if the page has been removed from the | * Check to see if the page has been removed from the | ||||||||
* queue since the first such check. Leave it alone if | * queue since the first such check. Leave it alone if | ||||||||
* so, discarding any references collected by | * so, discarding any references collected by | ||||||||
* pmap_ts_referenced(). | * pmap_ts_referenced(). | ||||||||
*/ | */ | ||||||||
if (__predict_false(_vm_page_queue(old) == PQ_NONE)) | if (__predict_false(_vm_page_queue(old) == PQ_NONE)) | ||||||||
goto skip_page; | goto skip_page; | ||||||||
new = old; | new = old; | ||||||||
act_delta = refs; | act_delta = refs; | ||||||||
if ((old.flags & PGA_REFERENCED) != 0) { | if ((old.flags & PGA_REFERENCED) != 0) { | ||||||||
new.flags &= ~PGA_REFERENCED; | new.flags &= ~PGA_REFERENCED; | ||||||||
act_delta++; | act_delta++; | ||||||||
} | } | ||||||||
if (act_delta == 0) { | if (act_delta == 0) { | ||||||||
; | ; | ||||||||
} else if (object->ref_count != 0) { | } else if (vm_pageout_object_act(object)) { | ||||||||
Done Inline ActionsThis should presumably check whether ref_count > 1 for non-anonymous object. markj: This should presumably check whether ref_count > 1 for non-anonymous object. | |||||||||
/* | /* | ||||||||
* Increase the activation count if the page was | * Increase the activation count if the page was | ||||||||
* referenced while in the laundry queue. This | * referenced while in the laundry queue. This | ||||||||
* makes it less likely that the page will be | * makes it less likely that the page will be | ||||||||
* returned prematurely to the laundry queue. | * returned prematurely to the laundry queue. | ||||||||
*/ | */ | ||||||||
new.act_count += ACT_ADVANCE + | new.act_count += ACT_ADVANCE + | ||||||||
act_delta; | act_delta; | ||||||||
▲ Show 20 Lines • Show All 420 Lines • ▼ Show 20 Lines | while ((m = vm_pageout_next(&ss, false)) != NULL) { | ||||||||
} | } | ||||||||
/* | /* | ||||||||
* Check to see "how much" the page has been used. | * Check to see "how much" the page has been used. | ||||||||
* | * | ||||||||
* Test PGA_REFERENCED after calling pmap_ts_referenced() so | * Test PGA_REFERENCED after calling pmap_ts_referenced() so | ||||||||
* that a reference from a concurrently destroyed mapping is | * that a reference from a concurrently destroyed mapping is | ||||||||
* observed here and now. | * observed here and now. | ||||||||
* | |||||||||
* Perform an unsynchronized object ref count check. While | |||||||||
* the page lock ensures that the page is not reallocated to | |||||||||
* another object, in particular, one with unmanaged mappings | |||||||||
* that cannot support pmap_ts_referenced(), two races are, | |||||||||
* nonetheless, possible: | |||||||||
* 1) The count was transitioning to zero, but we saw a non- | |||||||||
* zero value. pmap_ts_referenced() will return zero | |||||||||
* because the page is not mapped. | |||||||||
* 2) The count was transitioning to one, but we saw zero. | |||||||||
* This race delays the detection of a new reference. At | |||||||||
* worst, we will deactivate and reactivate the page. | |||||||||
*/ | */ | ||||||||
refs = object->ref_count != 0 ? pmap_ts_referenced(m) : 0; | refs = vm_pageout_page_ts_referenced(object, m); | ||||||||
old = vm_page_astate_load(m); | old = vm_page_astate_load(m); | ||||||||
do { | do { | ||||||||
/* | /* | ||||||||
* Check to see if the page has been removed from the | * Check to see if the page has been removed from the | ||||||||
* queue since the first such check. Leave it alone if | * queue since the first such check. Leave it alone if | ||||||||
* so, discarding any references collected by | * so, discarding any references collected by | ||||||||
* pmap_ts_referenced(). | * pmap_ts_referenced(). | ||||||||
▲ Show 20 Lines • Show All 233 Lines • ▼ Show 20 Lines | while (page_shortage > 0 && (m = vm_pageout_next(&ss, true)) != NULL) { | ||||||||
/* | /* | ||||||||
* Invalid pages can be easily freed. They cannot be | * Invalid pages can be easily freed. They cannot be | ||||||||
* mapped, vm_page_free() asserts this. | * mapped, vm_page_free() asserts this. | ||||||||
*/ | */ | ||||||||
if (vm_page_none_valid(m)) | if (vm_page_none_valid(m)) | ||||||||
goto free_page; | goto free_page; | ||||||||
refs = object->ref_count != 0 ? pmap_ts_referenced(m) : 0; | refs = vm_pageout_page_ts_referenced(object, m); | ||||||||
for (old = vm_page_astate_load(m);;) { | for (old = vm_page_astate_load(m);;) { | ||||||||
/* | /* | ||||||||
* Check to see if the page has been removed from the | * Check to see if the page has been removed from the | ||||||||
* queue since the first such check. Leave it alone if | * queue since the first such check. Leave it alone if | ||||||||
* so, discarding any references collected by | * so, discarding any references collected by | ||||||||
* pmap_ts_referenced(). | * pmap_ts_referenced(). | ||||||||
*/ | */ | ||||||||
if (__predict_false(_vm_page_queue(old) == PQ_NONE)) | if (__predict_false(_vm_page_queue(old) == PQ_NONE)) | ||||||||
goto skip_page; | goto skip_page; | ||||||||
new = old; | new = old; | ||||||||
act_delta = refs; | act_delta = refs; | ||||||||
if ((old.flags & PGA_REFERENCED) != 0) { | if ((old.flags & PGA_REFERENCED) != 0) { | ||||||||
new.flags &= ~PGA_REFERENCED; | new.flags &= ~PGA_REFERENCED; | ||||||||
act_delta++; | act_delta++; | ||||||||
} | } | ||||||||
if (act_delta == 0) { | if (act_delta == 0) { | ||||||||
; | ; | ||||||||
} else if (object->ref_count != 0) { | } else if (vm_pageout_object_act(object)) { | ||||||||
Done Inline ActionsPresumably this check should be updated too. markj: Presumably this check should be updated too. | |||||||||
/* | /* | ||||||||
Done Inline ActionsI think the code would be more clear if we instead had bool vm_pageout_object_mapped(vm_object) which returned true if there is a mapping reference, and false otherwise. markj: I think the code would be more clear if we instead had `bool vm_pageout_object_mapped… | |||||||||
* Increase the activation count if the | * Increase the activation count if the | ||||||||
* page was referenced while in the | * page was referenced while in the | ||||||||
* inactive queue. This makes it less | * inactive queue. This makes it less | ||||||||
* likely that the page will be returned | * likely that the page will be returned | ||||||||
* prematurely to the inactive queue. | * prematurely to the inactive queue. | ||||||||
*/ | */ | ||||||||
new.act_count += ACT_ADVANCE + | new.act_count += ACT_ADVANCE + | ||||||||
act_delta; | act_delta; | ||||||||
Show All 20 Lines | while (page_shortage > 0 && (m = vm_pageout_next(&ss, true)) != NULL) { | ||||||||
/* | /* | ||||||||
* If the page appears to be clean at the machine-independent | * If the page appears to be clean at the machine-independent | ||||||||
* layer, then remove all of its mappings from the pmap in | * layer, then remove all of its mappings from the pmap in | ||||||||
* anticipation of freeing it. If, however, any of the page's | * anticipation of freeing it. If, however, any of the page's | ||||||||
* mappings allow write access, then the page may still be | * mappings allow write access, then the page may still be | ||||||||
* modified until the last of those mappings are removed. | * modified until the last of those mappings are removed. | ||||||||
*/ | */ | ||||||||
if (object->ref_count != 0) { | if (vm_pageout_object_act(object)) { | ||||||||
Done Inline ActionsThis should be updated as well. markj: This should be updated as well. | |||||||||
vm_page_test_dirty(m); | vm_page_test_dirty(m); | ||||||||
if (m->dirty == 0 && !vm_page_try_remove_all(m)) | if (m->dirty == 0 && !vm_page_try_remove_all(m)) | ||||||||
goto skip_page; | goto skip_page; | ||||||||
} | } | ||||||||
/* | /* | ||||||||
* Clean pages can be freed, but dirty pages must be sent back | * Clean pages can be freed, but dirty pages must be sent back | ||||||||
* to the laundry, unless they belong to a dead object. | * to the laundry, unless they belong to a dead object. | ||||||||
▲ Show 20 Lines • Show All 827 Lines • Show Last 20 Lines |