El Thu, 13 May 2010 00:15:47 +0200 Sergio Lopez <s...@sinrega.org> escribió: > I need some help reviewing the patch (I consider this a preliminary > version, so there's no Changelog) and testing the stability of this > interface. Since it requires to rebuild GNU Mach, Hurd and glibc, I'll > try to publish patched packages to make easier testing it. >
You can find the patched packages here: http://blogs.nologin.es/uploads/hurd I've also applied the patches for mach-defpager, tmpfs and mutex debugging (all for the same price! ;-). Q: What should I expect after installing these packages? A:- Threads should increase at a lower rate. The new interface prevents the creation of large amounts of threads when syncing dirty memory objects. New threads are created only when Mach terminates a object which still has dirty pages (thus has not been completely synced yet), or when pageout deamon needs to urgently free some pages. If you're planning to do large builds under Hurd, you should consider applying this patch, combined with an increment of the number of cached objects in Mach, and a reduction of the filesystem synchronization interval in ext2fs. - A working (but largely untested) tmpfs. You can also find attached a newer version of the sync_request patch, with some bugs already fixed.
diff -dur a/ext2fs/pager.c b/ext2fs/pager.c --- a/ext2fs/pager.c 2010-05-21 17:21:51.000000000 +0200 +++ b/ext2fs/pager.c 2010-05-21 17:22:09.000000000 +0200 @@ -1277,8 +1277,10 @@ ports_port_ref (pager); spin_unlock (&node_to_page_lock); - if (MAY_CACHE && pager) + if (MAY_CACHE && pager) { + pager_sync(pager, 1); pager_change_attributes (pager, 0, MEMORY_OBJECT_COPY_DELAY, 0); + } if (pager) ports_port_deref (pager); } Only in b/ext2fs: pager.c.orig diff -dur a/libpager/data-return.c b/libpager/data-return.c --- a/libpager/data-return.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/data-return.c 2010-05-21 17:22:01.000000000 +0200 @@ -42,8 +42,6 @@ char *notified; error_t *pagerrs; struct lock_request *lr; - struct lock_list {struct lock_request *lr; - struct lock_list *next;} *lock_list, *ll; int wakeup; int omitdata = 0; @@ -56,11 +54,6 @@ _pager_wait_for_seqno (p, seqno); /* sanity checks -- we don't do multi-page requests yet. */ - if (control != p->memobjcntl) - { - printf ("incg data return: wrong control port\n"); - goto release_out; - } if (length % __vm_page_size) { printf ("incg data return: bad length size %zd\n", length); @@ -93,6 +86,23 @@ pm_entries = &p->pagemap[offset / __vm_page_size]; + /* Check if there's a lock request waiting for us */ + for (lr = p->lock_requests; lr; lr = lr->next) + if (!lr->write_in_progress && + (offset == lr->start && offset + length == lr->end)) { + lr->write_in_progress = TRUE; + break; + } + + if (! dirty) + { + /* Even if pages are clean, we need to wake up sync-object */ + if (lr) { + lr->write_pending = FALSE; + condition_broadcast(&p->wakeup); + } + } + if (! dirty && ! kcopy) { /* Prepare notified array. */ @@ -140,23 +150,6 @@ for (i = 0; i < npages; i++) pm_entries[i] |= PM_PAGINGOUT | PM_INIT; - /* If this write occurs while a lock is pending, record - it. We have to keep this list because a lock request - might come in while we do the I/O; in that case there - would be a new entry on p->lock_requests and we must - make sure we don't decrement it. So we have to keep - track independently of which lock requests we incremented. */ - lock_list = 0; - for (lr = p->lock_requests; lr; lr = lr->next) - if (offset < lr->end && offset + length >= lr->start) - { - ll = alloca (sizeof (struct lock_list)); - ll->lr = lr; - ll->next = lock_list; - lock_list = ll; - lr->pending_writes++; - } - /* Let someone else in. */ _pager_release_seqno (p, seqno); mutex_unlock (&p->interlock); @@ -218,11 +211,13 @@ pm_entries[i] &= ~(PM_PAGINGOUT | PM_PAGEINWAIT | PM_WRITEWAIT); } - for (ll = lock_list; ll; ll = ll->next) - if (!--ll->lr->pending_writes && !ll->lr->locks_pending) - wakeup = 1; - if (wakeup) + if (lr) { + lr->write_pending = FALSE; + wakeup = 1; + } + + if (wakeup) condition_broadcast (&p->wakeup); notify: diff -dur a/libpager/data-unlock.c b/libpager/data-unlock.c --- a/libpager/data-unlock.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/data-unlock.c 2010-05-21 17:22:01.000000000 +0200 @@ -74,13 +74,13 @@ if (!err) /* We can go ahead and release the lock. */ _pager_lock_object (p, offset, length, MEMORY_OBJECT_RETURN_NONE, 0, - VM_PROT_NONE, 0); + VM_PROT_NONE); else { /* Flush the page, and set a bit so that m_o_data_request knows to issue an error. */ - _pager_lock_object (p, offset, length, MEMORY_OBJECT_RETURN_NONE, 1, - VM_PROT_WRITE, 1); + _pager_lock_object (p, offset, length, MEMORY_OBJECT_RETURN_NONE, 0, + VM_PROT_NONE); _pager_mark_next_request_error (p, offset, length, err); } out: diff -dur a/libpager/lock-object.c b/libpager/lock-object.c --- a/libpager/lock-object.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/lock-object.c 2010-05-21 17:22:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* Synchronous wrapper for memory_object_lock_request +/* Wrapper for memory_object_lock_request Copyright (C) 1993, 1994, 1996, 1997, 2000 Free Software Foundation This program is free software; you can redistribute it and/or @@ -19,20 +19,15 @@ /* Request a lock from the kernel on pager P. Parameters OFFSET, SIZE, SHOULD_RETURN, SHOULD_FLUSH, and LOCK_VALUE are as for - memory_object_lock_request. If SYNC is set, then wait for the - operation to fully complete before returning. */ + memory_object_lock_request. */ void _pager_lock_object (struct pager *p, vm_offset_t offset, vm_size_t size, int should_return, int should_flush, - vm_prot_t lock_value, - int sync) + vm_prot_t lock_value) { - int i; - struct lock_request *lr = 0; - mutex_lock (&p->interlock); if (p->pager_state != NORMAL) { @@ -40,66 +35,8 @@ return; } - if (sync) - { - for (lr = p->lock_requests; lr; lr = lr->next) - if (lr->start == offset && lr->end == offset + size) - { - lr->locks_pending++; - lr->threads_waiting++; - break; - } - if (!lr) - { - lr = malloc (sizeof (struct lock_request)); - lr->start = offset; - lr->end = offset + size; - lr->pending_writes = 0; - lr->locks_pending = 1; - lr->threads_waiting = 1; - lr->next = p->lock_requests; - if (lr->next) - lr->next->prevp = &lr->next; - lr->prevp = &p->lock_requests; - p->lock_requests = lr; - } - } - memory_object_lock_request (p->memobjcntl, offset, size, should_return, - should_flush, lock_value, - sync ? p->port.port_right : MACH_PORT_NULL); - - if (sync) - { - while (lr->locks_pending || lr->pending_writes) - condition_wait (&p->wakeup, &p->interlock); + should_flush, lock_value, MACH_PORT_NULL); - if (! --lr->threads_waiting) - { - *lr->prevp = lr->next; - if (lr->next) - lr->next->prevp = lr->prevp; - free (lr); - } - - if (should_flush) - { - vm_offset_t pm_offs = offset / __vm_page_size; - - _pager_pagemap_resize (p, offset + size); - if (p->pagemapsize > pm_offs) - { - short *pm_entries = &p->pagemap[pm_offs]; - vm_offset_t bound = size / vm_page_size; - - if (bound > p->pagemapsize) - bound = p->pagemapsize; - - for (i = 0; i < bound; i++) - pm_entries[i] &= ~PM_INCORE; - } - } - } - mutex_unlock (&p->interlock); } diff -dur a/libpager/Makefile b/libpager/Makefile --- a/libpager/Makefile 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/Makefile 2010-05-21 17:22:01.000000000 +0200 @@ -20,12 +20,12 @@ libname = libpager SRCS = data-request.c data-return.c data-unlock.c pager-port.c \ - inhibit-term.c lock-completed.c lock-object.c mark-error.c \ + inhibit-term.c lock-object.c mark-error.c offer-page.c \ no-senders.c object-init.c object-terminate.c pagemap.c \ pager-create.c pager-flush.c pager-shutdown.c pager-sync.c \ stubs.c seqnos.c demuxer.c chg-compl.c pager-attr.c clean.c \ dropweak.c notify-stubs.c get-upi.c pager-memcpy.c pager-return.c \ - offer-page.c + sync-object.c LCLHDRS = pager.h priv.h installhdrs = pager.h diff -dur a/libpager/object-terminate.c b/libpager/object-terminate.c --- a/libpager/object-terminate.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/object-terminate.c 2010-05-21 17:22:01.000000000 +0200 @@ -23,9 +23,7 @@ in <mach/memory_object.defs>. */ kern_return_t _pager_seqnos_memory_object_terminate (mach_port_t object, - mach_port_seqno_t seqno, - mach_port_t control, - mach_port_t name) + mach_port_seqno_t seqno) { struct pager *p; @@ -36,16 +34,11 @@ mutex_lock (&p->interlock); _pager_wait_for_seqno (p, seqno); - if (control != p->memobjcntl) - { - printf ("incg terminate: wrong control port"); - goto out; - } - if (name != p->memobjname) - { - printf ("incg terminate: wrong name port"); - goto out; - } + /* Mach has already destroyed the ports, destroy our now dead names + and reflect it in P. */ + mach_port_destroy (mach_task_self (), p->memobjcntl); + mach_port_destroy (mach_task_self (), p->memobjname); + p->memobjcntl = p->memobjname = MACH_PORT_NULL; while (p->noterm) { @@ -53,12 +46,6 @@ condition_wait (&p->wakeup, &p->interlock); } - /* Destry the ports we received; mark that in P so that it doesn't bother - doing it again. */ - mach_port_destroy (mach_task_self (), control); - mach_port_destroy (mach_task_self (), name); - p->memobjcntl = p->memobjname = MACH_PORT_NULL; - _pager_free_structure (p); #ifdef KERNEL_INIT_RACE @@ -76,7 +63,6 @@ } #endif - out: _pager_release_seqno (p, seqno); mutex_unlock (&p->interlock); ports_port_deref (p); @@ -97,9 +83,11 @@ wakeup = 0; for (lr = p->lock_requests; lr; lr = lr->next) { - lr->locks_pending = 0; - if (!lr->pending_writes) + if (!lr->write_in_progress) { + lr->write_pending = FALSE; + lr->terminating = TRUE; wakeup = 1; + } } for (ar = p->attribute_requests; ar; ar = ar->next) { diff -dur a/libpager/pager-flush.c b/libpager/pager-flush.c --- a/libpager/pager-flush.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/pager-flush.c 2010-05-21 17:22:01.000000000 +0200 @@ -27,8 +27,7 @@ pager_report_extent (p->upi, &offset, &len); - _pager_lock_object (p, offset, len, MEMORY_OBJECT_RETURN_NONE, 1, - VM_PROT_NO_CHANGE, wait); + _pager_sync_object (p, offset, len, MEMORY_OBJECT_RETURN_NONE, 1); } @@ -39,7 +38,6 @@ pager_flush_some (struct pager *p, vm_address_t offset, vm_size_t size, int wait) { - _pager_lock_object (p, offset, size, MEMORY_OBJECT_RETURN_NONE, 1, - VM_PROT_NO_CHANGE, wait); + _pager_sync_object (p, offset, size, MEMORY_OBJECT_RETURN_NONE, 1); } diff -dur a/libpager/pager-return.c b/libpager/pager-return.c --- a/libpager/pager-return.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/pager-return.c 2010-05-21 17:22:01.000000000 +0200 @@ -30,15 +30,13 @@ pager_report_extent (p->upi, &offset, &len); - _pager_lock_object (p, offset, len, MEMORY_OBJECT_RETURN_ALL, 1, - VM_PROT_NO_CHANGE, wait); + _pager_sync_object (p, offset, len, MEMORY_OBJECT_RETURN_ALL, 1); } void pager_return_some (struct pager *p, vm_address_t offset, vm_size_t size, int wait) { - _pager_lock_object (p, offset, size, MEMORY_OBJECT_RETURN_ALL, 1, - VM_PROT_NO_CHANGE, wait); + _pager_sync_object (p, offset, size, MEMORY_OBJECT_RETURN_ALL, 1); } diff -dur a/libpager/pager-sync.c b/libpager/pager-sync.c --- a/libpager/pager-sync.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/pager-sync.c 2010-05-21 17:22:01.000000000 +0200 @@ -28,8 +28,7 @@ pager_report_extent (p->upi, &offset, &len); - _pager_lock_object (p, offset, len, MEMORY_OBJECT_RETURN_ALL, 0, - VM_PROT_NO_CHANGE, wait); + _pager_sync_object (p, offset, len, MEMORY_OBJECT_RETURN_DIRTY, 0); } @@ -39,7 +38,6 @@ pager_sync_some (struct pager *p, vm_address_t offset, vm_size_t size, int wait) { - _pager_lock_object (p, offset, size, MEMORY_OBJECT_RETURN_ALL, 0, - VM_PROT_NO_CHANGE, wait); + _pager_sync_object (p, offset, size, MEMORY_OBJECT_RETURN_DIRTY, 0); } diff -dur a/libpager/priv.h b/libpager/priv.h --- a/libpager/priv.h 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/priv.h 2010-05-21 17:22:01.000000000 +0200 @@ -74,9 +74,9 @@ { struct lock_request *next, **prevp; vm_address_t start, end; - int pending_writes; - int locks_pending; - int threads_waiting; + boolean_t write_pending; + boolean_t write_in_progress; + boolean_t terminating; }; struct attribute_request @@ -143,7 +143,8 @@ void _pager_mark_object_error (struct pager *, vm_address_t, vm_size_t, error_t); void _pager_lock_object (struct pager *, vm_offset_t, vm_size_t, int, int, - vm_prot_t, int); + vm_prot_t); +void _pager_sync_object (struct pager *, vm_offset_t, vm_size_t, int, int); void _pager_free_structure (struct pager *); void _pager_clean (void *arg); void _pager_real_dropweak (void *arg); diff -dur a/libpager/stubs.c b/libpager/stubs.c --- a/libpager/stubs.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/stubs.c 2010-05-21 17:22:01.000000000 +0200 @@ -66,3 +66,16 @@ return EOPNOTSUPP; } +kern_return_t +_pager_seqnos_memory_object_lock_completed (mach_port_t obj, + mach_port_seqno_t seq, + mach_port_t ctl, + vm_offset_t off, + vm_size_t len) +{ + printf ("m_o_lock_completed called\n"); + + _pager_stubs_update_seqno (obj, seq); + + return EOPNOTSUPP; +} diff -dur a/libpager/sync-object.c b/libpager/sync-object.c --- a/libpager/sync-object.c 2010-05-21 17:21:40.000000000 +0200 +++ b/libpager/sync-object.c 2010-05-21 17:22:01.000000000 +0200 @@ -0,0 +1,107 @@ +/* Sequential synchronization for pagers + Copyright (C) 2010 Free Software Foundation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "priv.h" + +/* Request synchronization from the kernel on pager P. Parameters + OFFSET, SIZE, SHOULD_RETURN, and SHOULD_FLUSH are as for + memory_object_sync_request. */ +void +_pager_sync_object (struct pager *p, + vm_offset_t offset, + vm_size_t size, + int should_return, + int should_flush) +{ + int i; + struct lock_request *lr = 0; + boolean_t dirty = FALSE; + vm_offset_t start_offset = 0; + vm_offset_t end_offset = 0; + vm_size_t flush_size = 0; + + mutex_lock (&p->interlock); + if (p->pager_state != NORMAL) + { + mutex_unlock (&p->interlock); + return; + } + + do + { + memory_object_sync_request (p->memobjcntl, offset, size, + should_return, should_flush, + &dirty, &start_offset, &end_offset); + + if (should_flush) + { + if (dirty) + flush_size = end_offset - offset; + else + flush_size = size; + + vm_offset_t pm_offs = offset / __vm_page_size; + + _pager_pagemap_resize (p, offset + flush_size); + if (p->pagemapsize > pm_offs) + { + short *pm_entries = &p->pagemap[pm_offs]; + vm_offset_t bound = flush_size / vm_page_size; + + if (bound > p->pagemapsize) + bound = p->pagemapsize; + + for (i = 0; i < bound; i++) + pm_entries[i] &= ~PM_INCORE; + } + } + + if (!dirty) + break; + + size -= (end_offset - start_offset); + offset = end_offset; + + lr = malloc (sizeof (struct lock_request)); + lr->start = start_offset; + lr->end = end_offset; + lr->write_pending = TRUE; + lr->write_in_progress = FALSE; + lr->terminating = FALSE; + lr->next = p->lock_requests; + if (lr->next) + lr->next->prevp = &lr->next; + lr->prevp = &p->lock_requests; + p->lock_requests = lr; + + while (lr->write_pending) + condition_wait(&p->wakeup, &p->interlock); + + /* If an m_o_termnated has been issued, set size to zero + to exit this loop */ + if (lr->terminating) + size = 0; + + *lr->prevp = lr->next; + if (lr->next) + lr->next->prevp = lr->prevp; + free (lr); + } + while (size != 0); + + mutex_unlock (&p->interlock); +}