📄 vm_pageo.c
字号:
if ((pager = object->pager) == NULL) { pager = vm_pager_allocate(PG_DFLT, (caddr_t)0, object->size, VM_PROT_ALL, (vm_offset_t)0); if (pager != NULL) vm_object_setpager(object, pager, 0, FALSE); } pageout_status = pager ? vm_pager_put(pager, m, FALSE) : VM_PAGER_FAIL; vm_object_lock(object); vm_page_lock_queues(); switch (pageout_status) { case VM_PAGER_OK: case VM_PAGER_PEND: cnt.v_pgpgout++; m->flags &= ~PG_LAUNDRY; break; case VM_PAGER_BAD: /* * Page outside of range of object. Right now we * essentially lose the changes by pretending it * worked. * * XXX dubious, what should we do? */ m->flags &= ~PG_LAUNDRY; m->flags |= PG_CLEAN; pmap_clear_modify(VM_PAGE_TO_PHYS(m)); break; case VM_PAGER_AGAIN: { extern int lbolt; /* * FAIL on a write is interpreted to mean a resource * shortage, so we put pause for awhile and try again. * XXX could get stuck here. */ vm_page_unlock_queues(); vm_object_unlock(object); (void) tsleep((caddr_t)&lbolt, PZERO|PCATCH, "pageout", 0); vm_object_lock(object); vm_page_lock_queues(); break; } case VM_PAGER_FAIL: case VM_PAGER_ERROR: /* * If page couldn't be paged out, then reactivate * the page so it doesn't clog the inactive list. * (We will try paging out it again later). */ vm_page_activate(m); cnt.v_reactivated++; break; } pmap_clear_reference(VM_PAGE_TO_PHYS(m)); /* * If the operation is still going, leave the page busy * to block all other accesses. Also, leave the paging * in progress indicator set so that we don't attempt an * object collapse. */ if (pageout_status != VM_PAGER_PEND) { m->flags &= ~PG_BUSY; PAGE_WAKEUP(m); object->paging_in_progress--; }}#ifdef CLUSTERED_PAGEOUT#define PAGEOUTABLE(p) \ ((((p)->flags & (PG_INACTIVE|PG_CLEAN|PG_LAUNDRY)) == \ (PG_INACTIVE|PG_LAUNDRY)) && !pmap_is_referenced(VM_PAGE_TO_PHYS(p)))/* * Attempt to pageout as many contiguous (to ``m'') dirty pages as possible * from ``object''. Using information returned from the pager, we assemble * a sorted list of contiguous dirty pages and feed them to the pager in one * chunk. Called with paging queues and object locked. Also, object must * already have a pager. */voidvm_pageout_cluster(m, object) vm_page_t m; vm_object_t object;{ vm_offset_t offset, loff, hoff; vm_page_t plist[MAXPOCLUSTER], *plistp, p; int postatus, ix, count; /* * Determine the range of pages that can be part of a cluster * for this object/offset. If it is only our single page, just * do it normally. */ vm_pager_cluster(object->pager, m->offset, &loff, &hoff); if (hoff - loff == PAGE_SIZE) { vm_pageout_page(m, object); return; } plistp = plist; /* * Target page is always part of the cluster. */ pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE); m->flags |= PG_BUSY; plistp[atop(m->offset - loff)] = m; count = 1; /* * Backup from the given page til we find one not fulfilling * the pageout criteria or we hit the lower bound for the * cluster. For each page determined to be part of the * cluster, unmap it and busy it out so it won't change. */ ix = atop(m->offset - loff); offset = m->offset; while (offset > loff && count < MAXPOCLUSTER-1) { p = vm_page_lookup(object, offset - PAGE_SIZE); if (p == NULL || !PAGEOUTABLE(p)) break; pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); p->flags |= PG_BUSY; plistp[--ix] = p; offset -= PAGE_SIZE; count++; } plistp += atop(offset - loff); loff = offset; /* * Now do the same moving forward from the target. */ ix = atop(m->offset - loff) + 1; offset = m->offset + PAGE_SIZE; while (offset < hoff && count < MAXPOCLUSTER) { p = vm_page_lookup(object, offset); if (p == NULL || !PAGEOUTABLE(p)) break; pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); p->flags |= PG_BUSY; plistp[ix++] = p; offset += PAGE_SIZE; count++; } hoff = offset; /* * Pageout the page. * Unlock everything and do a wakeup prior to the pager call * in case it blocks. */ vm_page_unlock_queues(); object->paging_in_progress++; vm_object_unlock(object);again: thread_wakeup(&cnt.v_free_count); postatus = vm_pager_put_pages(object->pager, plistp, count, FALSE); /* * XXX rethink this */ if (postatus == VM_PAGER_AGAIN) { extern int lbolt; (void) tsleep((caddr_t)&lbolt, PZERO|PCATCH, "pageout", 0); goto again; } else if (postatus == VM_PAGER_BAD) panic("vm_pageout_cluster: VM_PAGER_BAD"); vm_object_lock(object); vm_page_lock_queues(); /* * Loop through the affected pages, reflecting the outcome of * the operation. */ for (ix = 0; ix < count; ix++) { p = *plistp++; switch (postatus) { case VM_PAGER_OK: case VM_PAGER_PEND: cnt.v_pgpgout++; p->flags &= ~PG_LAUNDRY; break; case VM_PAGER_FAIL: case VM_PAGER_ERROR: /* * Pageout failed, reactivate the target page so it * doesn't clog the inactive list. Other pages are * left as they are. */ if (p == m) { vm_page_activate(p); cnt.v_reactivated++; } break; } pmap_clear_reference(VM_PAGE_TO_PHYS(p)); /* * If the operation is still going, leave the page busy * to block all other accesses. */ if (postatus != VM_PAGER_PEND) { p->flags &= ~PG_BUSY; PAGE_WAKEUP(p); } } /* * If the operation is still going, leave the paging in progress * indicator set so that we don't attempt an object collapse. */ if (postatus != VM_PAGER_PEND) object->paging_in_progress--;}#endif/* * vm_pageout is the high level pageout daemon. */voidvm_pageout(){ (void) spl0(); /* * Initialize some paging parameters. */ if (cnt.v_free_min == 0) { cnt.v_free_min = VM_PAGE_FREE_MIN; vm_page_free_min_min /= cnt.v_page_size; vm_page_free_min_max /= cnt.v_page_size; if (cnt.v_free_min < vm_page_free_min_min) cnt.v_free_min = vm_page_free_min_min; if (cnt.v_free_min > vm_page_free_min_max) cnt.v_free_min = vm_page_free_min_max; } if (cnt.v_free_target == 0) cnt.v_free_target = VM_PAGE_FREE_TARGET; if (cnt.v_free_target <= cnt.v_free_min) cnt.v_free_target = cnt.v_free_min + 1; /* XXX does not really belong here */ if (vm_page_max_wired == 0) vm_page_max_wired = cnt.v_free_count / 3; /* * The pageout daemon is never done, so loop * forever. */ simple_lock(&vm_pages_needed_lock); while (TRUE) { thread_sleep(&vm_pages_needed, &vm_pages_needed_lock, FALSE); /* * Compute the inactive target for this scan. * We need to keep a reasonable amount of memory in the * inactive list to better simulate LRU behavior. */ cnt.v_inactive_target = (cnt.v_active_count + cnt.v_inactive_count) / 3; if (cnt.v_inactive_target <= cnt.v_free_target) cnt.v_inactive_target = cnt.v_free_target + 1; /* * Only make a scan if we are likely to do something. * Otherwise we might have been awakened by a pager * to clean up async pageouts. */ if (cnt.v_free_count < cnt.v_free_target || cnt.v_inactive_count < cnt.v_inactive_target) vm_pageout_scan(); vm_pager_sync(); simple_lock(&vm_pages_needed_lock); thread_wakeup(&cnt.v_free_count); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -