|
|
| version 1.10, 2004/03/23 22:54:32 | version 1.11, 2004/05/13 17:40:19 |
|---|---|
| Line 209 static void vm_pageout_page_stats(void); | Line 209 static void vm_pageout_page_stats(void); |
| /* | /* |
| * vm_pageout_clean: | * vm_pageout_clean: |
| * | * |
| * Clean the page and remove it from the laundry. | * Clean the page and remove it from the laundry. The page must not be |
| * busy on-call. | |
| * | * |
| * We set the busy bit to cause potential page faults on this page to | * We set the busy bit to cause potential page faults on this page to |
| * block. Note the careful timing, however, the busy bit isn't set till | * block. Note the careful timing, however, the busy bit isn't set till |
| Line 443 vm_pageout_flush(vm_page_t *mc, int coun | Line 444 vm_pageout_flush(vm_page_t *mc, int coun |
| */ | */ |
| static void | static void |
| vm_pageout_object_deactivate_pages(vm_map_t map, vm_object_t object, | vm_pageout_object_deactivate_pages(vm_map_t map, vm_object_t object, |
| vm_pindex_t desired, int map_remove_only) | vm_pindex_t desired, int map_remove_only) |
| { | { |
| vm_page_t p, next; | vm_page_t p, next; |
| int rcount; | int rcount; |
| Line 462 vm_pageout_object_deactivate_pages(vm_ma | Line 463 vm_pageout_object_deactivate_pages(vm_ma |
| remove_mode = map_remove_only; | remove_mode = map_remove_only; |
| if (object->shadow_count > 1) | if (object->shadow_count > 1) |
| remove_mode = 1; | remove_mode = 1; |
| /* | |
| * scan the objects entire memory queue | /* |
| */ | * scan the objects entire memory queue. spl protection is |
| * required to avoid an interrupt unbusy/free race against | |
| * our busy check. | |
| */ | |
| s = splvm(); | |
| rcount = object->resident_page_count; | rcount = object->resident_page_count; |
| p = TAILQ_FIRST(&object->memq); | p = TAILQ_FIRST(&object->memq); |
| while (p && (rcount-- > 0)) { | while (p && (rcount-- > 0)) { |
| int actcount; | int actcount; |
| if (pmap_resident_count(vm_map_pmap(map)) <= desired) | if (pmap_resident_count(vm_map_pmap(map)) <= desired) { |
| splx(s); | |
| return; | return; |
| } | |
| next = TAILQ_NEXT(p, listq); | next = TAILQ_NEXT(p, listq); |
| mycpu->gd_cnt.v_pdpages++; | mycpu->gd_cnt.v_pdpages++; |
| if (p->wire_count != 0 || | if (p->wire_count != 0 || |
| Line 501 vm_pageout_object_deactivate_pages(vm_ma | Line 509 vm_pageout_object_deactivate_pages(vm_ma |
| vm_page_protect(p, VM_PROT_NONE); | vm_page_protect(p, VM_PROT_NONE); |
| vm_page_deactivate(p); | vm_page_deactivate(p); |
| } else { | } else { |
| s = splvm(); | |
| TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, p, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, p, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, p, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, p, pageq); |
| splx(s); | |
| } | } |
| } else { | } else { |
| vm_page_activate(p); | vm_page_activate(p); |
| vm_page_flag_clear(p, PG_REFERENCED); | vm_page_flag_clear(p, PG_REFERENCED); |
| if (p->act_count < (ACT_MAX - ACT_ADVANCE)) | if (p->act_count < (ACT_MAX - ACT_ADVANCE)) |
| p->act_count += ACT_ADVANCE; | p->act_count += ACT_ADVANCE; |
| s = splvm(); | |
| TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, p, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, p, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, p, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, p, pageq); |
| splx(s); | |
| } | } |
| } else if (p->queue == PQ_INACTIVE) { | } else if (p->queue == PQ_INACTIVE) { |
| vm_page_protect(p, VM_PROT_NONE); | vm_page_protect(p, VM_PROT_NONE); |
| } | } |
| p = next; | p = next; |
| } | } |
| splx(s); | |
| object = object->backing_object; | object = object->backing_object; |
| } | } |
| return; | |
| } | } |
| /* | /* |
| Line 675 vm_pageout_scan(int pass) | Line 679 vm_pageout_scan(int pass) |
| if (pass) | if (pass) |
| maxlaunder = 10000; | maxlaunder = 10000; |
| /* | |
| * We will generally be at splvm() throughout the scan, but we | |
| * can release it temporarily when we are sitting on a non-busy | |
| * page without fear. The spl protection is required because an | |
| * an interrupt can come along and unbusy/free a busy page prior | |
| * to our busy check, leaving us on the wrong queue or checking | |
| * the wrong page. | |
| */ | |
| s = splvm(); | |
| rescan0: | rescan0: |
| addl_page_shortage = addl_page_shortage_init; | addl_page_shortage = addl_page_shortage_init; |
| maxscan = vmstats.v_inactive_count; | maxscan = vmstats.v_inactive_count; |
| for (m = TAILQ_FIRST(&vm_page_queues[PQ_INACTIVE].pl); | for (m = TAILQ_FIRST(&vm_page_queues[PQ_INACTIVE].pl); |
| m != NULL && maxscan-- > 0 && page_shortage > 0; | m != NULL && maxscan-- > 0 && page_shortage > 0; |
| m = next) { | m = next |
| ) { | |
| mycpu->gd_cnt.v_pdpages++; | mycpu->gd_cnt.v_pdpages++; |
| if (m->queue != PQ_INACTIVE) { | /* |
| goto rescan0; | * Give interrupts a chance |
| } | */ |
| splx(s); | |
| s = splvm(); | |
| /* | |
| * It's easier for some of the conditions below to just loop | |
| * and catch queue changes here rather then check everywhere | |
| * else. | |
| */ | |
| if (m->queue != PQ_INACTIVE) | |
| goto rescan0; | |
| next = TAILQ_NEXT(m, pageq); | next = TAILQ_NEXT(m, pageq); |
| /* | /* |
| Line 700 rescan0: | Line 722 rescan0: |
| * A held page may be undergoing I/O, so skip it. | * A held page may be undergoing I/O, so skip it. |
| */ | */ |
| if (m->hold_count) { | if (m->hold_count) { |
| s = splvm(); | |
| TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); |
| splx(s); | |
| addl_page_shortage++; | addl_page_shortage++; |
| continue; | continue; |
| } | } |
| /* | /* |
| * Dont mess with busy pages, keep in the front of the | * Dont mess with busy pages, keep in the front of the |
| * queue, most likely are being paged out. | * queue, most likely are being paged out. |
| Line 716 rescan0: | Line 737 rescan0: |
| continue; | continue; |
| } | } |
| /* | |
| * If the object is not being used, we ignore previous | |
| * references. | |
| */ | |
| if (m->object->ref_count == 0) { | if (m->object->ref_count == 0) { |
| /* | |
| * If the object is not being used, we ignore previous | |
| * references. | |
| */ | |
| vm_page_flag_clear(m, PG_REFERENCED); | vm_page_flag_clear(m, PG_REFERENCED); |
| pmap_clear_reference(m); | pmap_clear_reference(m); |
| /* | |
| * Otherwise, if the page has been referenced while in the | |
| * inactive queue, we bump the "activation count" upwards, | |
| * making it less likely that the page will be added back to | |
| * the inactive queue prematurely again. Here we check the | |
| * page tables (or emulated bits, if any), given the upper | |
| * level VM system not knowing anything about existing | |
| * references. | |
| */ | |
| } else if (((m->flags & PG_REFERENCED) == 0) && | } else if (((m->flags & PG_REFERENCED) == 0) && |
| (actcount = pmap_ts_referenced(m))) { | (actcount = pmap_ts_referenced(m))) { |
| /* | |
| * Otherwise, if the page has been referenced while | |
| * in the inactive queue, we bump the "activation | |
| * count" upwards, making it less likely that the | |
| * page will be added back to the inactive queue | |
| * prematurely again. Here we check the page tables | |
| * (or emulated bits, if any), given the upper level | |
| * VM system not knowing anything about existing | |
| * references. | |
| */ | |
| vm_page_activate(m); | vm_page_activate(m); |
| m->act_count += (actcount + ACT_ADVANCE); | m->act_count += (actcount + ACT_ADVANCE); |
| continue; | continue; |
| Line 806 rescan0: | Line 828 rescan0: |
| * before being freed. This significantly extends | * before being freed. This significantly extends |
| * the thrash point for a heavily loaded machine. | * the thrash point for a heavily loaded machine. |
| */ | */ |
| s = splvm(); | |
| vm_page_flag_set(m, PG_WINATCFLS); | vm_page_flag_set(m, PG_WINATCFLS); |
| TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); |
| splx(s); | |
| } else if (maxlaunder > 0) { | } else if (maxlaunder > 0) { |
| /* | /* |
| * We always want to try to flush some dirty pages if | * We always want to try to flush some dirty pages if |
| Line 838 rescan0: | Line 858 rescan0: |
| * Those objects are in a "rundown" state. | * Those objects are in a "rundown" state. |
| */ | */ |
| if (!swap_pageouts_ok || (object->flags & OBJ_DEAD)) { | if (!swap_pageouts_ok || (object->flags & OBJ_DEAD)) { |
| s = splvm(); | |
| TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); |
| splx(s); | |
| continue; | continue; |
| } | } |
| Line 907 rescan0: | Line 925 rescan0: |
| * be undergoing I/O, so skip it | * be undergoing I/O, so skip it |
| */ | */ |
| if (m->hold_count) { | if (m->hold_count) { |
| s = splvm(); | |
| TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); |
| splx(s); | |
| if (object->flags & OBJ_MIGHTBEDIRTY) | if (object->flags & OBJ_MIGHTBEDIRTY) |
| vnodes_skipped++; | vnodes_skipped++; |
| vput(vp); | vput(vp); |
| Line 932 rescan0: | Line 948 rescan0: |
| * the (future) cleaned page. Otherwise we could wind | * the (future) cleaned page. Otherwise we could wind |
| * up laundering or cleaning too many pages. | * up laundering or cleaning too many pages. |
| */ | */ |
| s = splvm(); | |
| TAILQ_INSERT_AFTER(&vm_page_queues[PQ_INACTIVE].pl, m, &marker, pageq); | TAILQ_INSERT_AFTER(&vm_page_queues[PQ_INACTIVE].pl, m, &marker, pageq); |
| splx(s); | |
| if (vm_pageout_clean(m) != 0) { | if (vm_pageout_clean(m) != 0) { |
| --page_shortage; | --page_shortage; |
| --maxlaunder; | --maxlaunder; |
| } | } |
| s = splvm(); | |
| next = TAILQ_NEXT(&marker, pageq); | next = TAILQ_NEXT(&marker, pageq); |
| TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, &marker, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, &marker, pageq); |
| splx(s); | |
| if (vp != NULL) | if (vp != NULL) |
| vput(vp); | vput(vp); |
| } | } |
| Line 960 rescan0: | Line 972 rescan0: |
| * Scan the active queue for things we can deactivate. We nominally | * Scan the active queue for things we can deactivate. We nominally |
| * track the per-page activity counter and use it to locate | * track the per-page activity counter and use it to locate |
| * deactivation candidates. | * deactivation candidates. |
| * | |
| * NOTE: we are still at splvm(). | |
| */ | */ |
| pcount = vmstats.v_active_count; | pcount = vmstats.v_active_count; |
| m = TAILQ_FIRST(&vm_page_queues[PQ_ACTIVE].pl); | m = TAILQ_FIRST(&vm_page_queues[PQ_ACTIVE].pl); |
| while ((m != NULL) && (pcount-- > 0) && (page_shortage > 0)) { | while ((m != NULL) && (pcount-- > 0) && (page_shortage > 0)) { |
| /* | |
| * Give interrupts a chance. | |
| */ | |
| splx(s); | |
| s = splvm(); | |
| /* | /* |
| * This is a consistency check, and should likely be a panic | * If the page was ripped out from under us, just stop. |
| * or warning. | |
| */ | */ |
| if (m->queue != PQ_ACTIVE) { | if (m->queue != PQ_ACTIVE) |
| break; | break; |
| } | |
| next = TAILQ_NEXT(m, pageq); | next = TAILQ_NEXT(m, pageq); |
| /* | /* |
| * Don't deactivate pages that are busy. | * Don't deactivate pages that are busy. |
| */ | */ |
| if ((m->busy != 0) || | if ((m->busy != 0) || |
| (m->flags & PG_BUSY) || | (m->flags & PG_BUSY) || |
| (m->hold_count != 0)) { | (m->hold_count != 0)) { |
| s = splvm(); | |
| TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); |
| splx(s); | |
| m = next; | m = next; |
| continue; | continue; |
| } | } |
| Line 1022 rescan0: | Line 1036 rescan0: |
| * page activation count stats. | * page activation count stats. |
| */ | */ |
| if (actcount && (m->object->ref_count != 0)) { | if (actcount && (m->object->ref_count != 0)) { |
| s = splvm(); | |
| TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); |
| splx(s); | |
| } else { | } else { |
| m->act_count -= min(m->act_count, ACT_DECLINE); | m->act_count -= min(m->act_count, ACT_DECLINE); |
| if (vm_pageout_algorithm || | if (vm_pageout_algorithm || |
| Line 1042 rescan0: | Line 1054 rescan0: |
| vm_page_deactivate(m); | vm_page_deactivate(m); |
| } | } |
| } else { | } else { |
| s = splvm(); | |
| TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); | TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); |
| TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); | TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); |
| splx(s); | |
| } | } |
| } | } |
| m = next; | m = next; |
| } | } |
| s = splvm(); | |
| /* | /* |
| * We try to maintain some *really* free pages, this allows interrupt | * We try to maintain some *really* free pages, this allows interrupt |
| * code to be guaranteed space. Since both cache and free queues | * code to be guaranteed space. Since both cache and free queues |
| * are considered basically 'free', moving pages from cache to free | * are considered basically 'free', moving pages from cache to free |
| * does not effect other calculations. | * does not effect other calculations. |
| * | |
| * NOTE: we are still at splvm(). | |
| */ | */ |
| while (vmstats.v_free_count < vmstats.v_free_reserved) { | while (vmstats.v_free_count < vmstats.v_free_reserved) { |
| Line 1079 rescan0: | Line 1089 rescan0: |
| vm_pageout_page_free(m); | vm_pageout_page_free(m); |
| mycpu->gd_cnt.v_dfree++; | mycpu->gd_cnt.v_dfree++; |
| } | } |
| splx(s); | splx(s); |
| #if !defined(NO_SWAPPING) | #if !defined(NO_SWAPPING) |