This is an automated email from the git hooks/post-receive script. sthibault pushed a commit to branch master in repository gnumach.
commit edd25941056a7cf231cca23020f7342085bfaf30 Author: Samuel Thibault <[email protected]> Date: Fri Dec 2 10:58:26 2016 +0000 New upstream version 1.7+git20161202 --- ChangeLog | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ configure | 20 +++++++------- doc/mach.info | 2 +- doc/mach.info-1 | 4 +-- doc/mach.info-2 | 2 +- doc/stamp-vti | 4 +-- doc/version.texi | 4 +-- ipc/ipc_kmsg.c | 2 ++ version.m4 | 2 +- vm/vm_map.c | 2 +- vm/vm_page.c | 65 ++++++++++++++-------------------------------- vm/vm_page.h | 3 ++- vm/vm_pageout.c | 30 +++++++++++++++++---- vm/vm_resident.c | 23 +++++++++-------- 14 files changed, 159 insertions(+), 83 deletions(-) diff --git a/ChangeLog b/ChangeLog index f8f10ff..f8397b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,82 @@ +2032-05-12 Richard Braun <[email protected]> + + VM: fix pageout throttling to external pagers + Since the VM system has been tracking whether pages belong to internal + or external objects, pageout throttling to external pagers has simply + not been working. The reason is that, on pageout, requests for external + pages are correctly tracked, but on page release (which is used to + acknowledge the request), external pages are not marked external + any more. This is because the external bit tracks whether a page + belongs to an external object, and all pages, including external + ones, are moved to an internal object during pageout. + + To solve this issue, a new "external_laundry" bit is added. It has + the same purpose as the laundry bit, but for external pagers. + + * vm/vm_page.c (vm_page_seg_min_page_available): Function unused, remove. + (vm_page_seg_evict): Use vm_page_external_laundry_count instead of + vm_page_external_pagedout. Add an assertion about double paging. + (vm_page_check_usable): Use vm_page_external_laundry_count instead of + vm_page_external_pagedout. + (vm_page_evict): Likewise. + * vm/vm_page.h (struct vm_page): New `external_laundry' member. + (vm_page_external_pagedout): Rename to ... + (vm_page_external_laundry_count): ... this. + * vm/vm_pageout.c: Include kern/printf.h. + (DEBUG): New macro. + (VM_PAGEOUT_TIMEOUT): Likewise. + (vm_pageout_setup): Use vm_page_external_laundry_count instead of + vm_page_external_pagedout. Set `external_laundry' where appropriate. + (vm_pageout): Use VM_PAGEOUT_TIMEOUT with thread_set_timeout. + Add debugging code, commented out by default. + * vm/vm_resident.c (vm_page_external_pagedout): Rename to ... + (vm_page_external_laundry_count): ... this. + (vm_page_init_template): Set `external_laundry' member to FALSE. + (vm_page_release): Rename external parameter to external_laundry. + Slightly change pageout resuming. + (vm_page_free): Rename external variable to external_laundry. + +2016-11-30 Richard Braun <[email protected]> + + VM: fix pageout on low memory + Instead of determining if memory is low, directly use the + vm_page_alloc_paused variable, which is true when memory has reached + a minimum threshold until it gets back above the high thresholds. + + This makes sure double paging is used when external pagers are unable + to allocate memory. + + * vm/vm_page.c (vm_page_seg_evict): Rename low_memory to alloc_paused. + (vm_page_evict_once): Remove low_memory and its computation. Blindly + pass the new alloc_paused argument instead. + (vm_page_evict): Pass the value of vm_page_alloc_paused to + vm_page_evict_once. + +2016-11-30 Richard Braun <[email protected]> + + VM: fix eviction logic error + * vm/vm_page.c (vm_page_evict): Test both vm_page_external_pagedout + and vm_page_laundry_count in order to determine there was "no pageout". + +2016-11-30 Richard Braun <[email protected]> + + VM: fix pageout stop condition + When checking whether to continue paging out or not, the pageout daemon + only considers the high free page threshold of a segment. But if e.g. + the default pager had to allocate reserved pages during a previous + pageout cycle, it could have exhausted a segment (this is currently + only seen with the DMA segment). In that case, the high threshold + cannot be reached because the segment has currently no pageable page. + + This change makes the pageout daemon identify this condition and + consider the segment as usable in order to make progress. The segment + will simply be ignored on the allocation path for unprivileged threads, + and if this happens with too many segments, the system will fail at + allocation time. + + * vm/vm_page.c (vm_page_seg_usable): Report usable if the segment has + no pageable page. + 2016-11-10 Brent Baccala <[email protected]> gsync: Avoid NULL pointer dereference diff --git a/configure b/configure index 31ac702..e7a4219 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for GNU Mach 1.7+git20161115. +# Generated by GNU Autoconf 2.69 for GNU Mach 1.7+git20161202. # # Report bugs to <[email protected]>. # @@ -579,8 +579,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='GNU Mach' PACKAGE_TARNAME='gnumach' -PACKAGE_VERSION='1.7+git20161115' -PACKAGE_STRING='GNU Mach 1.7+git20161115' +PACKAGE_VERSION='1.7+git20161202' +PACKAGE_STRING='GNU Mach 1.7+git20161202' PACKAGE_BUGREPORT='[email protected]' PACKAGE_URL='' @@ -1599,7 +1599,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures GNU Mach 1.7+git20161115 to adapt to many kinds of systems. +\`configure' configures GNU Mach 1.7+git20161202 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1670,7 +1670,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of GNU Mach 1.7+git20161115:";; + short | recursive ) echo "Configuration of GNU Mach 1.7+git20161202:";; esac cat <<\_ACEOF @@ -2026,7 +2026,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -GNU Mach configure 1.7+git20161115 +GNU Mach configure 1.7+git20161202 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by GNU Mach $as_me 1.7+git20161115, which was +It was created by GNU Mach $as_me 1.7+git20161202, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2984,7 +2984,7 @@ fi # Define the identity of the package. PACKAGE='gnumach' - VERSION='1.7+git20161115' + VERSION='1.7+git20161202' # Some tools Automake needs. @@ -12189,7 +12189,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by GNU Mach $as_me 1.7+git20161115, which was +This file was extended by GNU Mach $as_me 1.7+git20161202, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -12260,7 +12260,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -GNU Mach config.status 1.7+git20161115 +GNU Mach config.status 1.7+git20161202 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/doc/mach.info b/doc/mach.info index 957c2df..cf13082 100644 --- a/doc/mach.info +++ b/doc/mach.info @@ -3,7 +3,7 @@ This is mach.info, produced by makeinfo version 6.3 from mach.texi. This file documents the GNU Mach microkernel. This is edition 0.4, last updated on 16 October 2016, of 'The GNU -Mach Reference Manual', for version 1.7+git20161115. +Mach Reference Manual', for version 1.7+git20161202. Copyright (C) 2001, 2002, 2006, 2007, 2008 Free Software Foundation, Inc. diff --git a/doc/mach.info-1 b/doc/mach.info-1 index 0790f8a..126d593 100644 --- a/doc/mach.info-1 +++ b/doc/mach.info-1 @@ -3,7 +3,7 @@ This is mach.info, produced by makeinfo version 6.3 from mach.texi. This file documents the GNU Mach microkernel. This is edition 0.4, last updated on 16 October 2016, of 'The GNU -Mach Reference Manual', for version 1.7+git20161115. +Mach Reference Manual', for version 1.7+git20161202. Copyright (C) 2001, 2002, 2006, 2007, 2008 Free Software Foundation, Inc. @@ -46,7 +46,7 @@ Main Menu This file documents the GNU Mach microkernel. This is edition 0.4, last updated on 16 October 2016, of 'The GNU -Mach Reference Manual', for version 1.7+git20161115. +Mach Reference Manual', for version 1.7+git20161202. Copyright (C) 2001, 2002, 2006, 2007, 2008 Free Software Foundation, Inc. diff --git a/doc/mach.info-2 b/doc/mach.info-2 index a18e09d..6163fd8 100644 --- a/doc/mach.info-2 +++ b/doc/mach.info-2 @@ -3,7 +3,7 @@ This is mach.info, produced by makeinfo version 6.3 from mach.texi. This file documents the GNU Mach microkernel. This is edition 0.4, last updated on 16 October 2016, of 'The GNU -Mach Reference Manual', for version 1.7+git20161115. +Mach Reference Manual', for version 1.7+git20161202. Copyright (C) 2001, 2002, 2006, 2007, 2008 Free Software Foundation, Inc. diff --git a/doc/stamp-vti b/doc/stamp-vti index d99bd24..1d1d8d7 100644 --- a/doc/stamp-vti +++ b/doc/stamp-vti @@ -1,4 +1,4 @@ @set UPDATED 16 October 2016 @set UPDATED-MONTH October 2016 -@set EDITION 1.7+git20161115 -@set VERSION 1.7+git20161115 +@set EDITION 1.7+git20161202 +@set VERSION 1.7+git20161202 diff --git a/doc/version.texi b/doc/version.texi index d99bd24..1d1d8d7 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -1,4 +1,4 @@ @set UPDATED 16 October 2016 @set UPDATED-MONTH October 2016 -@set EDITION 1.7+git20161115 -@set VERSION 1.7+git20161115 +@set EDITION 1.7+git20161202 +@set VERSION 1.7+git20161202 diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c index 28ed23c..527fbfc 100644 --- a/ipc/ipc_kmsg.c +++ b/ipc/ipc_kmsg.c @@ -1391,6 +1391,8 @@ ipc_kmsg_copyin_body( if (length == 0) data = 0; else if (is_port) { + if (length > 1<<20) + printf("allocating %llu for message %u\n", length, kmsg->ikm_header.msgh_id); data = kalloc(length); if (data == 0) goto invalid_memory; diff --git a/version.m4 b/version.m4 index 80b8354..2d1efff 100644 --- a/version.m4 +++ b/version.m4 @@ -1,4 +1,4 @@ m4_define([AC_PACKAGE_NAME],[GNU Mach]) -m4_define([AC_PACKAGE_VERSION],[1.7+git20161115]) +m4_define([AC_PACKAGE_VERSION],[1.7+git20161202]) m4_define([AC_PACKAGE_BUGREPORT],[[email protected]]) m4_define([AC_PACKAGE_TARNAME],[gnumach]) diff --git a/vm/vm_map.c b/vm/vm_map.c index 003694d..604177e 100644 --- a/vm/vm_map.c +++ b/vm/vm_map.c @@ -744,7 +744,7 @@ restart: return entry; error: - printf("no more room in %p (%s)\n", map, map->name); + printf("no more room in %p (%s) for allocating %u\n", map, map->name, size); return NULL; } diff --git a/vm/vm_page.c b/vm/vm_page.c index 2a9f27b..92e36a1 100644 --- a/vm/vm_page.c +++ b/vm/vm_page.c @@ -925,12 +925,6 @@ vm_page_seg_pull_cache_page(struct vm_page_seg *seg, } static boolean_t -vm_page_seg_min_page_available(const struct vm_page_seg *seg) -{ - return (seg->nr_free_pages > seg->min_free_pages); -} - -static boolean_t vm_page_seg_page_available(const struct vm_page_seg *seg) { return (seg->nr_free_pages > seg->high_free_pages); @@ -939,6 +933,11 @@ vm_page_seg_page_available(const struct vm_page_seg *seg) static boolean_t vm_page_seg_usable(const struct vm_page_seg *seg) { + if ((seg->nr_active_pages + seg->nr_inactive_pages) == 0) { + /* Nothing to page out, assume segment is usable */ + return TRUE; + } + return (seg->nr_free_pages >= seg->high_free_pages); } @@ -1084,8 +1083,8 @@ vm_page_seg_balance(struct vm_page_seg *seg) } static boolean_t -vm_page_seg_evict(struct vm_page_seg *seg, - boolean_t external_only, boolean_t low_memory) +vm_page_seg_evict(struct vm_page_seg *seg, boolean_t external_only, + boolean_t alloc_paused) { struct vm_page *page; boolean_t reclaim, laundry; @@ -1094,6 +1093,7 @@ vm_page_seg_evict(struct vm_page_seg *seg, page = NULL; object = NULL; + laundry = FALSE; restart: vm_page_lock_queues(); @@ -1151,8 +1151,9 @@ restart: */ assert(!page->laundry); + assert(!(laundry && page->external)); - if (object->internal || !low_memory) { + if (object->internal || !alloc_paused) { laundry = FALSE; } else { laundry = page->laundry = TRUE; @@ -1873,7 +1874,7 @@ vm_page_check_usable(void) } } - vm_page_external_pagedout = -1; + vm_page_external_laundry_count = -1; vm_page_alloc_paused = FALSE; thread_wakeup(&vm_page_alloc_paused); return TRUE; @@ -1940,48 +1941,19 @@ vm_page_balance(void) } static boolean_t -vm_page_evict_once(boolean_t external_only) +vm_page_evict_once(boolean_t external_only, boolean_t alloc_paused) { - struct vm_page_seg *seg; - boolean_t low_memory, min_page_available, evicted; + boolean_t evicted; unsigned int i; /* - * XXX Page allocation currently only uses the DIRECTMAP selector, - * allowing us to know which segments to look at when determining - * whether we're very low on memory. - */ - low_memory = TRUE; - - simple_lock(&vm_page_queue_free_lock); - - for (i = 0; i < vm_page_segs_size; i++) { - if (i > VM_PAGE_SEG_DIRECTMAP) { - break; - } - - seg = vm_page_seg_get(i); - - simple_lock(&seg->lock); - min_page_available = vm_page_seg_min_page_available(seg); - simple_unlock(&seg->lock); - - if (min_page_available) { - low_memory = FALSE; - break; - } - } - - simple_unlock(&vm_page_queue_free_lock); - - /* * It's important here that pages are evicted from lower priority * segments first. */ for (i = vm_page_segs_size - 1; i < vm_page_segs_size; i--) { evicted = vm_page_seg_evict(vm_page_seg_get(i), - external_only, low_memory); + external_only, alloc_paused); if (evicted) { return TRUE; @@ -1997,14 +1969,15 @@ vm_page_evict_once(boolean_t external_only) boolean_t vm_page_evict(boolean_t *should_wait) { - boolean_t pause, evicted, external_only; + boolean_t pause, evicted, external_only, alloc_paused; unsigned int i; *should_wait = TRUE; external_only = TRUE; simple_lock(&vm_page_queue_free_lock); - vm_page_external_pagedout = 0; + vm_page_external_laundry_count = 0; + alloc_paused = vm_page_alloc_paused; simple_unlock(&vm_page_queue_free_lock); again: @@ -2018,7 +1991,7 @@ again: } for (i = 0; i < VM_PAGE_MAX_EVICTIONS; i++) { - evicted = vm_page_evict_once(external_only); + evicted = vm_page_evict_once(external_only, alloc_paused); if (!evicted) { break; @@ -2031,7 +2004,7 @@ again: * Keep in mind eviction may not cause pageouts, since non-precious * clean pages are simply released. */ - if ((vm_page_external_pagedout == 0) || (vm_page_laundry_count == 0)) { + if ((vm_page_laundry_count == 0) && (vm_page_external_laundry_count == 0)) { /* * No pageout, but some clean pages were freed. Start a complete * scan again without waiting. diff --git a/vm/vm_page.h b/vm/vm_page.h index eb684c1..2a0ad2c 100644 --- a/vm/vm_page.h +++ b/vm/vm_page.h @@ -105,6 +105,7 @@ struct vm_page { /* boolean_t */ inactive:1, /* page is in inactive list (P) */ active:1, /* page is in active list (P) */ laundry:1, /* page is being cleaned now (P)*/ + external_laundry:1, /* same as laundry for external pagers (P)*/ free:1, /* page is on free list (P) */ reference:1, /* page has been used (P) */ external:1, /* page in external object (P) */ @@ -165,7 +166,7 @@ int vm_page_wire_count; /* How many pages are wired? */ extern int vm_page_laundry_count; /* How many pages being laundered? */ extern -int vm_page_external_pagedout; /* How many external pages being paged out? */ +int vm_page_external_laundry_count; /* How many external pages being paged out? */ decl_simple_lock_data(extern,vm_page_queue_lock)/* lock on active and inactive page queues */ diff --git a/vm/vm_pageout.c b/vm/vm_pageout.c index 85db021..7dc9c12 100644 --- a/vm/vm_pageout.c +++ b/vm/vm_pageout.c @@ -46,6 +46,7 @@ #include <kern/slab.h> #include <kern/task.h> #include <kern/thread.h> +#include <kern/printf.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_object.h> @@ -53,6 +54,13 @@ #include <vm/vm_pageout.h> #include <machine/locore.h> +#define DEBUG 0 + +/* + * Maximum delay, in milliseconds, between two pageout scans. + */ +#define VM_PAGEOUT_TIMEOUT 50 + /* * Event placeholder for pageout requests, synchronized with * the free page queue lock. @@ -251,17 +259,19 @@ vm_pageout_setup( vm_page_wire(m); } else { - vm_page_activate(m); + m->external_laundry = TRUE; /* - * If vm_page_external_pagedout is negative, + * If vm_page_external_laundry_count is negative, * the pageout daemon isn't expecting to be * notified. */ - if (vm_page_external_pagedout >= 0) { - vm_page_external_pagedout++; + if (vm_page_external_laundry_count >= 0) { + vm_page_external_laundry_count++; } + + vm_page_activate(m); } vm_page_unlock_queues(); @@ -460,9 +470,19 @@ void vm_pageout(void) FALSE); } else if (should_wait) { assert_wait(&vm_pageout_continue, FALSE); - thread_set_timeout(500); + thread_set_timeout(VM_PAGEOUT_TIMEOUT); simple_unlock(&vm_page_queue_free_lock); thread_block(NULL); + +#if DEBUG + if (current_thread()->wait_result != THREAD_AWAKENED) { + printf("vm_pageout: timeout," + " vm_page_laundry_count:%d" + " vm_page_external_laundry_count:%d\n", + vm_page_laundry_count, + vm_page_external_laundry_count); + } +#endif } else { simple_unlock(&vm_page_queue_free_lock); } diff --git a/vm/vm_resident.c b/vm/vm_resident.c index e3e34dc..b5096e0 100644 --- a/vm/vm_resident.c +++ b/vm/vm_resident.c @@ -140,7 +140,7 @@ int vm_page_wire_count; * pageout daemon. */ int vm_page_laundry_count = 0; -int vm_page_external_pagedout = 0; +int vm_page_external_laundry_count = 0; /* @@ -611,6 +611,7 @@ static void vm_page_init_template(vm_page_t m) m->inactive = FALSE; m->active = FALSE; m->laundry = FALSE; + m->external_laundry = FALSE; m->free = FALSE; m->external = FALSE; @@ -811,7 +812,7 @@ phys_addr_t vm_page_grab_phys_addr(void) void vm_page_release( vm_page_t mem, boolean_t laundry, - boolean_t external) + boolean_t external_laundry) { simple_lock(&vm_page_queue_free_lock); if (mem->free) @@ -825,20 +826,20 @@ void vm_page_release( vm_pageout_resume(); } } - if (external) { + if (external_laundry) { /* - * If vm_page_external_pagedout is negative, + * If vm_page_external_laundry_count is negative, * the pageout daemon isn't expecting to be * notified. */ - if (vm_page_external_pagedout > 0) { - vm_page_external_pagedout--; - } + if (vm_page_external_laundry_count > 0) { + vm_page_external_laundry_count--; - if (vm_page_external_pagedout == 0) { - vm_pageout_resume(); + if (vm_page_external_laundry_count == 0) { + vm_pageout_resume(); + } } } @@ -977,9 +978,9 @@ void vm_page_free( vm_page_release_fictitious(mem); } else { boolean_t laundry = mem->laundry; - boolean_t external = mem->external; + boolean_t external_laundry = mem->external_laundry; vm_page_init(mem); - vm_page_release(mem, laundry, external); + vm_page_release(mem, laundry, external_laundry); } } -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hurd/gnumach.git
